diff --git a/dlls/winemac.drv/cocoa_event.m b/dlls/winemac.drv/cocoa_event.m index 98b44451f02..377faa825d5 100644 --- a/dlls/winemac.drv/cocoa_event.m +++ b/dlls/winemac.drv/cocoa_event.m @@ -112,8 +112,36 @@ - (void) signalEventAvailable - (void) postEventObject:(MacDrvEvent*)event { + MacDrvEvent* lastEvent; + [eventsLock lock]; - [events addObject:event]; + + if ((event->event.type == MOUSE_MOVED || + event->event.type == MOUSE_MOVED_ABSOLUTE) && + (lastEvent = [events lastObject]) && + (lastEvent->event.type == MOUSE_MOVED || + lastEvent->event.type == MOUSE_MOVED_ABSOLUTE) && + lastEvent->event.window == event->event.window) + { + if (event->event.type == MOUSE_MOVED) + { + lastEvent->event.mouse_moved.x += event->event.mouse_moved.x; + lastEvent->event.mouse_moved.y += event->event.mouse_moved.y; + } + else + { + lastEvent->event.type = MOUSE_MOVED_ABSOLUTE; + lastEvent->event.mouse_moved.x = event->event.mouse_moved.x; + lastEvent->event.mouse_moved.y = event->event.mouse_moved.y; + } + + lastEvent->event.mouse_moved.time_ms = event->event.mouse_moved.time_ms; + + macdrv_cleanup_event(&event->event); + } + else + [events addObject:event]; + [eventsLock unlock]; [self signalEventAvailable]; diff --git a/dlls/winemac.drv/cocoa_window.h b/dlls/winemac.drv/cocoa_window.h index a4e4db3c17a..76390bc85ec 100644 --- a/dlls/winemac.drv/cocoa_window.h +++ b/dlls/winemac.drv/cocoa_window.h @@ -48,6 +48,9 @@ @interface WineWindow : NSPanel NSUInteger lastModifierFlags; + BOOL forceNextMouseMoveAbsolute; + double mouseMoveDeltaX, mouseMoveDeltaY; + BOOL causing_becomeKeyWindow; BOOL ignore_windowMiniaturize; BOOL ignore_windowDeminiaturize; diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m index 4d69674773c..c7739a40eee 100644 --- a/dlls/winemac.drv/cocoa_window.m +++ b/dlls/winemac.drv/cocoa_window.m @@ -234,6 +234,7 @@ + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)w { WineWindow* window; WineContentView* contentView; + NSTrackingArea* trackingArea; [self flipRect:&window_frame]; @@ -244,6 +245,7 @@ + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)w if (!window) return nil; window->normalStyleMask = [window styleMask]; + window->forceNextMouseMoveAbsolute = TRUE; /* Standardize windows to eliminate differences between titled and borderless windows and between NSWindow and NSPanel. */ @@ -263,6 +265,17 @@ + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)w return nil; [contentView setAutoresizesSubviews:NO]; + trackingArea = [[[NSTrackingArea alloc] initWithRect:[contentView bounds] + options:(NSTrackingMouseEnteredAndExited | + NSTrackingMouseMoved | + NSTrackingActiveAlways | + NSTrackingInVisibleRect) + owner:window + userInfo:nil] autorelease]; + if (!trackingArea) + return nil; + [contentView addTrackingArea:trackingArea]; + [window setContentView:contentView]; return window; @@ -387,6 +400,7 @@ - (void) doOrderOut { self.latentParentWindow = [self parentWindow]; [latentParentWindow removeChildWindow:self]; + forceNextMouseMoveAbsolute = TRUE; [self orderOut:nil]; [NSApp removeWindowsItem:self]; } @@ -581,6 +595,48 @@ - (void) postKeyEvent:(NSEvent *)theEvent event:theEvent]; } + - (void) postMouseMovedEvent:(NSEvent *)theEvent + { + macdrv_event event; + + if (forceNextMouseMoveAbsolute) + { + CGPoint point = CGEventGetLocation([theEvent CGEvent]); + + event.type = MOUSE_MOVED_ABSOLUTE; + event.mouse_moved.x = point.x; + event.mouse_moved.y = point.y; + + mouseMoveDeltaX = 0; + mouseMoveDeltaY = 0; + + forceNextMouseMoveAbsolute = FALSE; + } + else + { + /* Add event delta to accumulated delta error */ + /* deltaY is already flipped */ + mouseMoveDeltaX += [theEvent deltaX]; + mouseMoveDeltaY += [theEvent deltaY]; + + event.type = MOUSE_MOVED; + event.mouse_moved.x = mouseMoveDeltaX; + event.mouse_moved.y = mouseMoveDeltaY; + + /* Keep the remainder after integer truncation. */ + mouseMoveDeltaX -= event.mouse_moved.x; + mouseMoveDeltaY -= event.mouse_moved.y; + } + + if (event.type == MOUSE_MOVED_ABSOLUTE || event.mouse_moved.x || event.mouse_moved.y) + { + event.window = (macdrv_window)[self retain]; + event.mouse_moved.time_ms = [NSApp ticksForEventTime:[theEvent timestamp]]; + + [queue postEvent:&event]; + } + } + /* * ---------- NSWindow method overrides ---------- @@ -709,6 +765,14 @@ - (void) flagsChanged:(NSEvent *)theEvent } } + - (void) mouseEntered:(NSEvent *)theEvent { forceNextMouseMoveAbsolute = TRUE; } + - (void) mouseExited:(NSEvent *)theEvent { forceNextMouseMoveAbsolute = TRUE; } + + - (void) mouseMoved:(NSEvent *)theEvent { [self postMouseMovedEvent:theEvent]; } + - (void) mouseDragged:(NSEvent *)theEvent { [self postMouseMovedEvent:theEvent]; } + - (void) rightMouseDragged:(NSEvent *)theEvent { [self postMouseMovedEvent:theEvent]; } + - (void) otherMouseDragged:(NSEvent *)theEvent { [self postMouseMovedEvent:theEvent]; } + /* * ---------- NSWindowDelegate methods ---------- diff --git a/dlls/winemac.drv/event.c b/dlls/winemac.drv/event.c index 5d8d260b791..1f90c0491a4 100644 --- a/dlls/winemac.drv/event.c +++ b/dlls/winemac.drv/event.c @@ -37,6 +37,8 @@ static const char *dbgstr_event(int type) "KEY_RELEASE", "KEYBOARD_CHANGED", "MOUSE_BUTTON", + "MOUSE_MOVED", + "MOUSE_MOVED_ABSOLUTE", "WINDOW_CLOSE_REQUESTED", "WINDOW_DID_MINIMIZE", "WINDOW_DID_UNMINIMIZE", @@ -69,6 +71,12 @@ static macdrv_event_mask get_event_mask(DWORD mask) if (mask & QS_MOUSEBUTTON) event_mask |= event_mask_for_type(MOUSE_BUTTON); + if (mask & QS_MOUSEMOVE) + { + event_mask |= event_mask_for_type(MOUSE_MOVED); + event_mask |= event_mask_for_type(MOUSE_MOVED_ABSOLUTE); + } + if (mask & QS_POSTMESSAGE) { event_mask |= event_mask_for_type(APP_DEACTIVATED); @@ -114,6 +122,10 @@ void macdrv_handle_event(macdrv_event *event) case MOUSE_BUTTON: macdrv_mouse_button(hwnd, event); break; + case MOUSE_MOVED: + case MOUSE_MOVED_ABSOLUTE: + macdrv_mouse_moved(hwnd, event); + break; case WINDOW_CLOSE_REQUESTED: macdrv_window_close_requested(hwnd); break; diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index e24d8ab57af..5cfcb8b1fe0 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -135,6 +135,7 @@ static inline RECT rect_from_cgrect(CGRect cgrect) extern void macdrv_window_did_unminimize(HWND hwnd) DECLSPEC_HIDDEN; extern void macdrv_mouse_button(HWND hwnd, const macdrv_event *event) DECLSPEC_HIDDEN; +extern void macdrv_mouse_moved(HWND hwnd, const macdrv_event *event) DECLSPEC_HIDDEN; extern void macdrv_compute_keyboard_layout(struct macdrv_thread_data *thread_data) DECLSPEC_HIDDEN; extern void macdrv_keyboard_changed(const macdrv_event *event) DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index 242a78e10eb..388ffb734f2 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -130,6 +130,8 @@ KEY_RELEASE, KEYBOARD_CHANGED, MOUSE_BUTTON, + MOUSE_MOVED, + MOUSE_MOVED_ABSOLUTE, WINDOW_CLOSE_REQUESTED, WINDOW_DID_MINIMIZE, WINDOW_DID_UNMINIMIZE, @@ -162,6 +164,11 @@ int y; unsigned long time_ms; } mouse_button; + struct { + int x; + int y; + unsigned long time_ms; + } mouse_moved; struct { CGRect frame; } window_frame_changed; diff --git a/dlls/winemac.drv/mouse.c b/dlls/winemac.drv/mouse.c index 31d3db00e3c..4742e376bac 100644 --- a/dlls/winemac.drv/mouse.c +++ b/dlls/winemac.drv/mouse.c @@ -120,3 +120,25 @@ void macdrv_mouse_button(HWND hwnd, const macdrv_event *event) event->mouse_button.x, event->mouse_button.y, data, event->mouse_button.time_ms); } + + +/*********************************************************************** + * macdrv_mouse_moved + * + * Handler for MOUSE_MOVED and MOUSE_MOVED_ABSOLUTE events. + */ +void macdrv_mouse_moved(HWND hwnd, const macdrv_event *event) +{ + UINT flags = MOUSEEVENTF_MOVE; + + TRACE("win %p/%p %s (%d,%d) time %lu (%lu ticks ago)\n", hwnd, event->window, + (event->type == MOUSE_MOVED) ? "relative" : "absolute", + event->mouse_moved.x, event->mouse_moved.y, + event->mouse_moved.time_ms, (GetTickCount() - event->mouse_moved.time_ms)); + + if (event->type == MOUSE_MOVED_ABSOLUTE) + flags |= MOUSEEVENTF_ABSOLUTE; + + send_mouse_input(hwnd, flags, event->mouse_moved.x, event->mouse_moved.y, + 0, event->mouse_moved.time_ms); +}