winex11: Fetch the key state from the server when adjusting state on KeymapNotify and key events.

This commit is contained in:
Alexandre Julliard 2011-03-02 12:24:25 +01:00
parent 0f18d2bb09
commit 731f5b0b7b
1 changed files with 62 additions and 53 deletions

View File

@ -1270,28 +1270,21 @@ void X11DRV_send_keyboard_input( HWND hwnd, WORD wVk, WORD wScan, DWORD event_fl
/***********************************************************************
* KEYBOARD_UpdateOneState
*
* Updates internal state for <vkey>, depending on key <state> under X
*
* get_async_key_state
*/
static inline void KEYBOARD_UpdateOneState ( HWND hwnd, WORD vkey, WORD scan, int state, DWORD time )
static BOOL get_async_key_state( BYTE state[256] )
{
/* Do something if internal table state != X state for keycode */
if (((key_state_table[vkey & 0xff] & 0x80)!=0) != state)
BOOL ret;
SERVER_START_REQ( get_key_state )
{
DWORD flags = vkey & 0x100 ? KEYEVENTF_EXTENDEDKEY : 0;
if (!state) flags |= KEYEVENTF_KEYUP;
TRACE("Adjusting state for vkey %#.2x. State before %#.2x\n",
vkey, key_state_table[vkey & 0xff]);
/* Fake key being pressed inside wine */
X11DRV_send_keyboard_input( hwnd, vkey & 0xff, scan & 0xff, flags, time, 0, 0 );
TRACE("State after %#.2x\n", key_state_table[vkey & 0xff]);
req->tid = 0;
req->key = -1;
wine_server_set_reply( req, state, 256 );
ret = !wine_server_call( req );
}
SERVER_END_REQ;
return ret;
}
/***********************************************************************
@ -1307,6 +1300,9 @@ void X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
{
int i, j;
DWORD time = GetCurrentTime();
BYTE keystate[256];
if (!get_async_key_state( keystate )) return;
/* the minimum keycode is always greater or equal to 8, so we can
* skip the first 8 values, hence start at 1
@ -1316,8 +1312,6 @@ void X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
for (j = 0; j < 8; j++)
{
WORD vkey = keyc2vkey[(i * 8) + j];
WORD scan = keyc2scan[(i * 8) + j];
int state = (event->xkeymap.key_vector[i] & (1<<j)) != 0;
switch(vkey & 0xff)
{
@ -1327,21 +1321,62 @@ void X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
case VK_RCONTROL:
case VK_LSHIFT:
case VK_RSHIFT:
KEYBOARD_UpdateOneState( hwnd, vkey, scan, state, time );
if (!(keystate[vkey & 0xff] & 0x80) != !(event->xkeymap.key_vector[i] & (1<<j)))
{
WORD scan = keyc2scan[(i * 8) + j];
DWORD flags = vkey & 0x100 ? KEYEVENTF_EXTENDEDKEY : 0;
if (!(event->xkeymap.key_vector[i] & (1<<j))) flags |= KEYEVENTF_KEYUP;
TRACE( "Adjusting state for vkey %#.2x. State before %#.2x\n",
vkey, keystate[vkey & 0xff]);
/* Fake key being pressed inside wine */
X11DRV_send_keyboard_input( hwnd, vkey & 0xff, scan & 0xff, flags, time, 0, 0 );
}
break;
}
}
}
}
static void update_lock_state(HWND hwnd, BYTE vkey, WORD scan, DWORD time)
static void update_lock_state( HWND hwnd, WORD vkey, UINT state, DWORD time )
{
DWORD flags = vkey == VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0;
BYTE keystate[256];
if (key_state_table[vkey] & 0x80) flags ^= KEYEVENTF_KEYUP;
/* Note: X sets the below states on key down and clears them on key up.
Windows triggers them on key down. */
X11DRV_send_keyboard_input( hwnd, vkey, scan, flags, time, 0, 0 );
X11DRV_send_keyboard_input( hwnd, vkey, scan, flags ^ KEYEVENTF_KEYUP, time, 0, 0 );
if (!get_async_key_state( keystate )) return;
/* Adjust the CAPSLOCK state if it has been changed outside wine */
if (!(keystate[VK_CAPITAL] & 0x01) != !(state & LockMask) && vkey != VK_CAPITAL)
{
DWORD flags = 0;
if (keystate[VK_CAPITAL] & 0x80) flags ^= KEYEVENTF_KEYUP;
TRACE("Adjusting CapsLock state (%#.2x)\n", keystate[VK_CAPITAL]);
X11DRV_send_keyboard_input( hwnd, VK_CAPITAL, 0x3a, flags, time, 0, 0 );
X11DRV_send_keyboard_input( hwnd, VK_CAPITAL, 0x3a, flags ^ KEYEVENTF_KEYUP, time, 0, 0 );
}
/* Adjust the NUMLOCK state if it has been changed outside wine */
if (!(keystate[VK_NUMLOCK] & 0x01) != !(state & NumLockMask) && (vkey & 0xff) != VK_NUMLOCK)
{
DWORD flags = KEYEVENTF_EXTENDEDKEY;
if (keystate[VK_NUMLOCK] & 0x80) flags ^= KEYEVENTF_KEYUP;
TRACE("Adjusting NumLock state (%#.2x)\n", keystate[VK_NUMLOCK]);
X11DRV_send_keyboard_input( hwnd, VK_NUMLOCK, 0x45, flags, time, 0, 0 );
X11DRV_send_keyboard_input( hwnd, VK_NUMLOCK, 0x45, flags ^ KEYEVENTF_KEYUP, time, 0, 0 );
}
/* Adjust the SCROLLLOCK state if it has been changed outside wine */
if (!(keystate[VK_SCROLL] & 0x01) != !(state & ScrollLockMask) && vkey != VK_SCROLL)
{
DWORD flags = 0;
if (keystate[VK_SCROLL] & 0x80) flags ^= KEYEVENTF_KEYUP;
TRACE("Adjusting ScrLock state (%#.2x)\n", keystate[VK_SCROLL]);
X11DRV_send_keyboard_input( hwnd, VK_SCROLL, 0x46, flags, time, 0, 0 );
X11DRV_send_keyboard_input( hwnd, VK_SCROLL, 0x46, flags ^ KEYEVENTF_KEYUP, time, 0, 0 );
}
}
/***********************************************************************
@ -1441,33 +1476,7 @@ void X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
/* Note: X sets the below states on key down and clears them on key up.
Windows triggers them on key down. */
/* Adjust the CAPSLOCK state if it has been changed outside wine */
if (!(key_state_table[VK_CAPITAL] & 0x01) != !(event->state & LockMask) &&
vkey != VK_CAPITAL)
{
TRACE("Adjusting CapsLock state (%#.2x)\n", key_state_table[VK_CAPITAL]);
update_lock_state( hwnd, VK_CAPITAL, 0x3A, event_time );
}
/* Adjust the NUMLOCK state if it has been changed outside wine */
if (!(key_state_table[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask) &&
(vkey & 0xff) != VK_NUMLOCK)
{
TRACE("Adjusting NumLock state (%#.2x)\n", key_state_table[VK_NUMLOCK]);
update_lock_state( hwnd, VK_NUMLOCK, 0x45, event_time );
}
/* Adjust the SCROLLLOCK state if it has been changed outside wine */
if (!(key_state_table[VK_SCROLL] & 0x01) != !(event->state & ScrollLockMask) &&
vkey != VK_SCROLL)
{
TRACE("Adjusting ScrLock state (%#.2x)\n", key_state_table[VK_SCROLL]);
update_lock_state( hwnd, VK_SCROLL, 0x46, event_time );
}
update_lock_state( hwnd, vkey, event->state, event_time );
bScan = keyc2scan[event->keycode] & 0xFF;
TRACE_(key)("bScan = 0x%02x.\n", bScan);