I am not 100% happy with the following quick-and-dirty snippet, but it seems to work well-enough for my limited goal of running Age Of Empires II in the computer-vs-computer mode. Some Windows games assume full-screen operation, and query mouse position continuously, even when Wine has no focus or when cursor is outside Wine window. When these programs are non-focused, it may be useful to report mouse as being in a constant position, especially when running in a virtual desktop window. Consider the following cases: 1. Wine has input focus and X11 cursor is within Wine 2. Wine has focus but cursor is outside Wine 3. no focus and cursor is outside Wine 4. no focus but cursor is inside Wine The following snippet handles cases 1 and 4 as before. When the pointer resides outside Wine, the environment variable WINE_FAKED_POINTER will be used to decide if a constant position will be reported: 1: Report where the mouse really is, relative to the Wine window. This is the original (and default) functionality. 2: Report mouse as being in the middle of the wine window. 3: Report mouse as being in an "initial" position. example: export WINE_FAKED_POINTER=3 wine age2_x1.exe The logic for returning the fake position report does not check for input focus. When using FocusFollowMouse or SloppyFocus this should be enough. Or maybe someone who uses click-to-focus feels an urge to continue working on this... Anyway, recommendations on cleaner ways to interact with Wine innards will be appreciated. :) --laut Code: /* This function resides in dlls/winex11.drv/mouse.c */ /******************************************************************** * GetCursorPos (X11DRV.@) */ BOOL X11DRV_GetCursorPos(LPPOINT pos) { Display *display = thread_display(); Window root, child; int rootX, rootY, winX, winY; unsigned int xstate; wine_tsx11_lock(); if ((GetTickCount() - last_time_modified > 100) && XQueryPointer( display, root_window, &root, &child, &rootX, &rootY, &winX, &winY, &xstate )) { int have_pointer = child != 0; static int fake_pointer_mode = -1; static int original_x = 0; static int original_y = 0; /* FIXME: thread-safety ? Or is wine_tsx11_lock() enough? */ if (fake_pointer_mode < 1) { char* opt = getenv("WINE_FAKED_POINTER"); fake_pointer_mode = (opt && *opt >= '1' && *opt <= '9') ? *opt - '0' : 1; /* Save initial position to be used in mode 3 */ if (have_pointer) { original_x = winX; original_y = winY; } else { original_x = (virtual_screen_rect.right - virtual_screen_rect.left) / 2; original_y = (virtual_screen_rect.bottom - virtual_screen_rect.top) / 2; } WINE_DPRINTF("%s: mode=%d, x=%d, y=%d\n", __FUNCTION__, fake_pointer_mode, original_x, original_y); } /* Pointer within Wine window: report truthfully */ if (have_pointer) { update_button_state( xstate ); winX += virtual_screen_rect.left; winY += virtual_screen_rect.top; TRACE("pointer at (%d,%d)\n", winX, winY ); cursor_pos.x = winX; cursor_pos.y = winY; } else { switch (fake_pointer_mode) { case 2: winX = (virtual_screen_rect.right - virtual_screen_rect.left) / 2; winY = (virtual_screen_rect.bottom - virtual_screen_rect.top) / 2; break; case 3: winX = original_x; winY = original_y; break; case 1: default: /* like before, report mouse in its correct position */ winX = winX; winY = winY; break; } /* For the moment, we do not update button state here. */ cursor_pos.x = winX; cursor_pos.y = winY; cursor_pos.x += virtual_screen_rect.left; cursor_pos.y += virtual_screen_rect.top; } } *pos = cursor_pos; wine_tsx11_unlock(); return TRUE; }