forked from Kron4ek/Wine-Builds
-
Notifications
You must be signed in to change notification settings - Fork 16
/
inputbridgefix.patch
114 lines (106 loc) · 4.92 KB
/
inputbridgefix.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c
index 053c0e2ff47..97bec34b0ea 100644
--- a/dlls/winex11.drv/event.c
+++ b/dlls/winex11.drv/event.c
@@ -775,6 +775,8 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev )
if (is_virtual_desktop() && hwnd == NtUserGetDesktopWindow()) retry_grab_clipping_window();
if (hwnd == NtUserGetDesktopWindow()) return FALSE;
+ x11drv_thread_data()->keymapnotify_hwnd = hwnd;
+
/* when keyboard grab is released, re-apply the cursor clipping rect */
was_grabbed = keyboard_grabbed;
keyboard_grabbed = event->mode == NotifyGrab || event->mode == NotifyWhileGrabbed;
diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c
index b240b228ff0..5c7f6c37276 100644
--- a/dlls/winex11.drv/keyboard.c
+++ b/dlls/winex11.drv/keyboard.c
@@ -1192,11 +1192,19 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
int i, j;
BYTE keystate[256];
WORD vkey;
+ DWORD flags;
+ KeyCode keycode;
+ HWND keymapnotify_hwnd;
BOOL changed = FALSE;
struct {
WORD vkey;
+ WORD scan;
WORD pressed;
} keys[256];
+ struct x11drv_thread_data *thread_data = x11drv_thread_data();
+
+ keymapnotify_hwnd = thread_data->keymapnotify_hwnd;
+ thread_data->keymapnotify_hwnd = NULL;
if (!get_async_key_state( keystate )) return FALSE;
@@ -1211,11 +1219,17 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
{
for (j = 0; j < 8; j++)
{
- vkey = keyc2vkey[(i * 8) + j];
+ keycode = (i * 8) + j;
+ vkey = keyc2vkey[keycode];
/* If multiple keys map to the same vkey, we want to report it as
* pressed iff any of them are pressed. */
- if (!keys[vkey & 0xff].vkey) keys[vkey & 0xff].vkey = vkey;
+ if (!keys[vkey & 0xff].vkey)
+ {
+ keys[vkey & 0xff].vkey = vkey;
+ keys[vkey & 0xff].scan = keyc2scan[keycode] & 0xff;
+ }
+
if (event->xkeymap.key_vector[i] & (1<<j)) keys[vkey & 0xff].pressed = TRUE;
}
}
@@ -1227,6 +1241,31 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
TRACE( "Adjusting state for vkey %#.2x. State before %#.2x\n",
keys[vkey].vkey, keystate[vkey]);
+ /* This KeymapNotify follows a FocusIn(mode=NotifyUngrab) event,
+ * which is caused by a keyboard grab being released.
+ * See XGrabKeyboard().
+ *
+ * We might have missed some key press/release events while the
+ * keyboard was grabbed, but keyboard grab doesn't generate focus
+ * lost / focus gained events on the Windows side, so the affected
+ * program is not aware that it needs to resync the keyboard state.
+ *
+ * This, for example, may cause Alt being stuck after using Alt+Tab.
+ *
+ * To work around that problem we sync any possible key releases.
+ *
+ * Syncing key presses is not feasible as window managers differ in
+ * event sequences, e.g. KDE performs two keyboard grabs for
+ * Alt+Tab, which would sync the Tab press.
+ */
+ if (keymapnotify_hwnd && !keys[vkey].pressed)
+ {
+ TRACE( "Sending KEYUP for a modifier %#.2x\n", vkey);
+ flags = KEYEVENTF_KEYUP;
+ if (keys[vkey].vkey & 0x1000) flags |= KEYEVENTF_EXTENDEDKEY;
+ X11DRV_send_keyboard_input( keymapnotify_hwnd, vkey, keys[vkey].scan, flags, NtGetTickCount() );
+ }
+
update_key_state( keystate, vkey, keys[vkey].pressed );
changed = TRUE;
}
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
index 3ddcf609549..612fff9995c 100644
--- a/dlls/winex11.drv/mouse.c
+++ b/dlls/winex11.drv/mouse.c
@@ -1611,6 +1611,8 @@ BOOL X11DRV_EnterNotify( HWND hwnd, XEvent *xev )
TRACE( "hwnd %p/%lx pos %d,%d detail %d\n", hwnd, event->window, event->x, event->y, event->detail );
+ x11drv_thread_data()->keymapnotify_hwnd = hwnd;
+
if (hwnd == x11drv_thread_data()->grab_hwnd) return FALSE;
/* simulate a mouse motion event */
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index e80cb6682bf..2c15a95dfab 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -382,6 +382,7 @@ struct x11drv_thread_data
XEvent *current_event; /* event currently being processed */
HWND grab_hwnd; /* window that currently grabs the mouse */
HWND last_focus; /* last window that had focus */
+ HWND keymapnotify_hwnd; /* window that should receive modifier release events */
XIM xim; /* input method */
HWND last_xic_hwnd; /* last xic window */
XFontSet font_set; /* international text drawing font set */