Hi all, - make int09 update the BIOS data segment's keyboard status flags bytes - implement pause key handling - let int16/02 read the keyboard status flags bytes instead of calling GetAsyncKeyState() - make the keyboard state buffer used for Get*Key*() reflect VK_L/RMENU properly (WM_KEYUP only handles WM_MENU, but Get*Key*() has more detailed output !) - small fixes This patch *finally* makes Alt-x key combos work properly in IDA :-) (menu invocation and special functions) -- Andreas Mohr Stauferstr. 6, D-71272 Renningen, Germany
Determining best CVS host... Using CVSROOT :pserver:cvs@rhlx01.fht-esslingen.de:/home/wine Index: dlls/winedos/dosvm.c =================================================================== RCS file: /home/wine/wine/dlls/winedos/dosvm.c,v retrieving revision 1.20 diff -u -r1.20 dosvm.c --- dlls/winedos/dosvm.c 10 Jul 2002 23:22:29 -0000 1.20 +++ dlls/winedos/dosvm.c 4 Aug 2002 16:42:06 -0000 @@ -235,12 +235,16 @@ { INPUT_RECORD msg; DWORD res; - BYTE scan; + BYTE scan, ascii; if (ReadConsoleInputA(GetStdHandle(STD_INPUT_HANDLE),&msg,1,&res)) { switch (msg.EventType) { case KEY_EVENT: scan = msg.Event.KeyEvent.wVirtualScanCode; + ascii = msg.Event.KeyEvent.uChar.AsciiChar; + TRACE("scan %02x, ascii %02x\n", scan, ascii); + + /* set the "break" (release) flag if key released */ if (!msg.Event.KeyEvent.bKeyDown) scan |= 0x80; /* check whether extended bit is set, @@ -248,7 +252,7 @@ if (msg.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY) { DOSVM_Int09SendScan(0xE0,0); } - DOSVM_Int09SendScan(scan,msg.Event.KeyEvent.uChar.AsciiChar); + DOSVM_Int09SendScan(scan, ascii); break; case MOUSE_EVENT: DOSVM_Int33Console(&msg.Event.MouseEvent); Index: dlls/winedos/int09.c =================================================================== RCS file: /home/wine/wine/dlls/winedos/int09.c,v retrieving revision 1.4 diff -u -r1.4 int09.c --- dlls/winedos/int09.c 9 Mar 2002 23:44:32 -0000 1.4 +++ dlls/winedos/int09.c 4 Aug 2002 16:42:06 -0000 @@ -39,24 +39,158 @@ } kbdinfo; +/* + * Update the BIOS data segment's keyboard status flags (mem 0x40:0x17/0x18) + * if modifier/special keys have been pressed. + * FIXME: we merely toggle key status and don't actively set it instead, + * so we might be out of sync with the real current system status of these keys. + * Probably doesn't matter too much, though. + */ +void DOSVM_Int09UpdateKbdStatusFlags(BYTE scan, BOOL extended, BIOSDATA *data, BOOL *modifier) +{ + BYTE realscan = scan & 0x7f; /* remove 0x80 make/break flag */ + BYTE bit1 = 255, bit2 = 255; + INPUT_RECORD msg; + DWORD res; + + *modifier = TRUE; + + switch (realscan) + { + case 0x36: /* r shift */ + bit1 = 0; + break; + case 0x2a: /* l shift */ + bit1 = 1; + break; + case 0x1d: /* l/r control */ + bit1 = 2; + if (!extended) /* left control only */ + bit2 = 0; + break; + case 0x37: /* SysRq inner parts */ + /* SysRq scan code sequence: 38, e0, 37, e0, b7, b8 */ + FIXME("SysRq not handled yet.\n"); + break; + case 0x38: /* l/r menu/alt, SysRq outer parts */ + bit1 = 3; + if (!extended) /* left alt only */ + bit2 = 1; + break; + case 0x46: /* scroll lock */ + bit1 = 4; + if (!extended) /* left ctrl only */ + bit2 = 4; + break; + case 0x45: /* num lock, pause */ + if (extended) /* distinguish from non-extended Pause key */ + { /* num lock */ + bit1 = 5; + bit2 = 5; + } + else + { /* pause */ + if (!(scan & 0x80)) /* "make" code */ + bit2 = 3; + } + break; + case 0x3a: /* caps lock */ + bit1 = 6; + bit2 = 6; + break; + case 0x52: /* insert */ + bit1 = 7; + bit2 = 7; + *modifier = FALSE; /* insert is no modifier: thus pass to int16 */ + break; + } + /* now that we know which bits to set, update them */ + if (!(scan & 0x80)) /* "make" code (keypress) */ + { + if (bit2 != 255) + { + if (bit2 == 3) + { + data->KbdFlags2 |= 1 << bit2; /* set "Pause" flag */ + TRACE("PAUSE key, sleeping !\n"); + /* wait for keypress to unlock pause */ + do { + Sleep(55); + } while (!(ReadConsoleInputA(GetStdHandle(STD_INPUT_HANDLE),&msg,1,&res) && (msg.EventType == KEY_EVENT))); + data->KbdFlags2 &= ~(1 << bit2); /* release "Pause" flag */ + } + else + data->KbdFlags2 |= 1 << bit2; + } + if (bit1 != 255) + { + if (bit1 < 4) /* key "pressed" flag */ + data->KbdFlags1 |= 1 << bit1; + else /* key "active" flag */ + data->KbdFlags1 ^= 1 << bit1; + } + } + else /* "break" / release */ + { + if (bit2 != 255) + data->KbdFlags2 &= ~(1 << bit2); + if (bit1 < 4) /* is it a key "pressed" bit ? */ + data->KbdFlags1 &= ~(1 << bit1); + } + TRACE("ext. %d, bits %d/%d, KbdFlags %02x/%02x\n", extended, bit1, bit2, data->KbdFlags1, data->KbdFlags2); +} + /********************************************************************** * DOSVM_Int09Handler * * Handler for int 09h. + * See http://www.execpc.com/~geezer/osd/kbd/ for a very good description + * of keyboard mapping modes. */ void WINAPI DOSVM_Int09Handler( CONTEXT86 *context ) { + BIOSDATA *data = DOSMEM_BiosData(); BYTE ascii, scan = DOSVM_Int09ReadScan(&ascii); + BYTE realscan = scan & 0x7f; /* remove 0x80 make/break flag */ + BOOL modifier = FALSE; + static BOOL extended = FALSE; /* indicates start of extended key sequence */ BYTE ch[2]; int cnt, c2; - TRACE("scan=%02x\n",scan); - if (!(scan & 0x80)) { + TRACE("scan=%02x, ascii=%02x[%c]\n",scan, ascii, ascii ? ascii : ' '); + + if (scan == 0xe0) /* extended keycode */ + extended = TRUE; + + /* check for keys concerning keyboard status flags */ + if ((realscan == 0x52 /* insert */) + || (realscan == 0x3a /* caps lock */) + || (realscan == 0x45 /* num lock (extended) or pause/break */) + || (realscan == 0x46 /* scroll lock */) + || (realscan == 0x2a /* l shift */) + || (realscan == 0x36 /* r shift */) + || (realscan == 0x37 /* SysRq */) + || (realscan == 0x38 /* l/r menu/alt, SysRq */) + || (realscan == 0x1d /* l/r control */)) + DOSVM_Int09UpdateKbdStatusFlags(scan, extended, data, &modifier); + + if (scan != 0xe0) + extended = FALSE; /* reset extended flag now */ + + /* only interested in "make" (press) codes, not "break" (release), + * and also not in "modifier key only" (w/o ascii) notifications */ + if (!(scan & 0x80) && !(modifier && !ascii)) + { if (ascii) { /* we already have an ASCII code, no translation necessary */ - ch[0] = ascii; + if (data->KbdFlags1 & 8) /* Alt key ? */ + ch[0] = 0; /* ASCII code needs to be 0 if Alt also pressed */ + else + ch[0] = ascii; + /* FIXME: need to handle things such as Shift-F1 etc. */ cnt = 1; } else { + /* translate */ UINT vkey = MapVirtualKeyA(scan&0x7f, 1); BYTE keystate[256]; GetKeyboardState(keystate); Index: dlls/winedos/int16.c =================================================================== RCS file: /home/wine/wine/dlls/winedos/int16.c,v retrieving revision 1.4 diff -u -r1.4 int16.c --- dlls/winedos/int16.c 3 Jul 2002 01:13:34 -0000 1.4 +++ dlls/winedos/int16.c 4 Aug 2002 16:42:06 -0000 @@ -49,6 +49,8 @@ void WINAPI DOSVM_Int16Handler( CONTEXT86 *context ) { + BIOSDATA *data = NULL; + switch AH_reg(context) { case 0x00: /* Get Keystroke */ @@ -77,24 +79,11 @@ break; case 0x02: /* Get Shift Flags */ - AL_reg(context) = 0; - - if (GetAsyncKeyState(VK_RSHIFT)) - AL_reg(context) |= 0x01; - if (GetAsyncKeyState(VK_LSHIFT)) - AL_reg(context) |= 0x02; - if (GetAsyncKeyState(VK_LCONTROL) || GetAsyncKeyState(VK_RCONTROL)) - AL_reg(context) |= 0x04; - if (GetAsyncKeyState(VK_LMENU) || GetAsyncKeyState(VK_RMENU)) - AL_reg(context) |= 0x08; - if (GetAsyncKeyState(VK_SCROLL)) - AL_reg(context) |= 0x10; - if (GetAsyncKeyState(VK_NUMLOCK)) - AL_reg(context) |= 0x20; - if (GetAsyncKeyState(VK_CAPITAL)) - AL_reg(context) |= 0x40; - if (GetAsyncKeyState(VK_INSERT)) - AL_reg(context) |= 0x80; + + /* read value from BIOS data segment's keyboard status flags field */ + data = DOSMEM_BiosData(); + AL_reg(context) = data->KbdFlags1; + TRACE("Get Shift Flags: returning 0x%02x\n", AL_reg(context)); break; Index: dlls/x11drv/keyboard.c =================================================================== RCS file: /home/wine/wine/dlls/x11drv/keyboard.c,v retrieving revision 1.6 diff -u -r1.6 keyboard.c --- dlls/x11drv/keyboard.c 22 Jun 2002 01:10:37 -0000 1.6 +++ dlls/x11drv/keyboard.c 4 Aug 2002 16:42:07 -0000 @@ -923,12 +923,12 @@ TRACE_(key)("state = %X\n", event->state); - /* If XKB extensions is used, the state mask for AltGr will used the group + /* If XKB extensions is used, the state mask for AltGr will use the group index instead of the modifier mask. The group index is set in bits 13-14 of the state field in the XKeyEvent structure. So if AltGr is - pressed, look if the group index is diferent than 0. From XKB - extension documentation, the group index should for AltGr should - be 2 (event->state = 0x2000). It's probably better to not assume a + pressed, look if the group index is different than 0. From XKB + extension documentation, the group index for AltGr should be 2 + (event->state = 0x2000). It's probably better to not assume a predefined group index and find it dynamically Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */ @@ -1333,7 +1333,7 @@ keycode = TSXKeysymToKeycode(display, keysym | 0xFE00); } - TRACE("VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n", + TRACE("'%c'(%#lx, %lu): got keycode %#.2x\n", cChar,keysym,keysym,keycode); if (keycode) @@ -1370,7 +1370,7 @@ #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; } - TRACE("MapVirtualKey wCode=0x%x wMapType=%d ... \n", wCode,wMapType); + TRACE("wCode=0x%x wMapType=%d ... \n", wCode,wMapType); switch(wMapType) { case 0: { /* vkey-code to scan-code */ /* let's do vkey -> keycode -> scan */ @@ -1756,7 +1756,7 @@ } /* more areas where X returns characters but Windows does not - CTRL + number or CTRL + symbol*/ + CTRL + number or CTRL + symbol */ if (e.state & ControlMask) { if (((keysym>=33) && (keysym < 'A')) || Index: programs/wineconsole/user.c =================================================================== RCS file: /home/wine/wine/programs/wineconsole/user.c,v retrieving revision 1.15 diff -u -r1.15 user.c --- programs/wineconsole/user.c 23 Jul 2002 02:02:46 -0000 1.15 +++ programs/wineconsole/user.c 4 Aug 2002 16:42:08 -0000 @@ -876,7 +876,7 @@ } /****************************************************************** - * CUSER_GetCtrlKeyState + * WCUSER_GetCtrlKeyState * * Get the console bit mask equivalent to the VK_ status in keyState */ @@ -886,7 +886,6 @@ GetKeyboardState(keyState); if (keyState[VK_SHIFT] & 0x80) ret |= SHIFT_PRESSED; - if (keyState[VK_CONTROL] & 0x80) ret |= LEFT_CTRL_PRESSED; /* FIXME: gotta choose one */ if (keyState[VK_LCONTROL] & 0x80) ret |= LEFT_CTRL_PRESSED; if (keyState[VK_RCONTROL] & 0x80) ret |= RIGHT_CTRL_PRESSED; if (keyState[VK_LMENU] & 0x80) ret |= LEFT_ALT_PRESSED; Index: windows/message.c =================================================================== RCS file: /home/wine/wine/windows/message.c,v retrieving revision 1.136 diff -u -r1.136 message.c --- windows/message.c 1 Jul 2002 18:20:16 -0000 1.136 +++ windows/message.c 4 Aug 2002 16:42:09 -0000 @@ -131,9 +131,10 @@ /*********************************************************************** * update_queue_key_state */ -static void update_queue_key_state( UINT msg, WPARAM wp ) +static void update_queue_key_state( UINT msg, WPARAM wp, LPARAM lp ) { - BOOL down = FALSE; + BOOL down = FALSE, iskey = FALSE; + WPARAM dualkey = 0; switch (msg) { @@ -162,8 +163,25 @@ case WM_KEYUP: case WM_SYSKEYUP: wp = wp & 0xff; + iskey = TRUE; break; } + if (iskey) + { + switch(wp) + { + case VK_SHIFT: + dualkey = (HIWORD(lp) & KF_EXTENDED) ? VK_RSHIFT : VK_LSHIFT; + break; + case VK_CONTROL: + dualkey = (HIWORD(lp) & KF_EXTENDED) ? VK_RCONTROL : VK_LCONTROL; + break; + case VK_MENU: + dualkey = (HIWORD(lp) & KF_EXTENDED) ? VK_RMENU : VK_LMENU; + break; + + } + } if (down) { BYTE *p = &QueueKeyStateTable[wp]; @@ -171,6 +189,16 @@ *p |= 0x80; } else QueueKeyStateTable[wp] &= ~0x80; + if (dualkey) + { /* also update the "dual" keys properly */ + if (down) + { + BYTE *p = &QueueKeyStateTable[dualkey]; + if (!(*p & 0x80)) *p ^= 0x01; + *p |= 0x80; + } + else QueueKeyStateTable[dualkey] &= ~0x80; + } } @@ -325,7 +353,7 @@ } /* if we are going to throw away the message, update the queue state now */ - if (!msg->hwnd) update_queue_key_state( msg->message, msg->wParam ); + if (!msg->hwnd) update_queue_key_state( msg->message, msg->wParam, msg->lParam ); return (msg->hwnd != 0); } @@ -340,7 +368,7 @@ { if (remove) { - update_queue_key_state( msg->message, msg->wParam ); + update_queue_key_state( msg->message, msg->wParam, msg->lParam ); /* Handle F1 key by sending out WM_HELP message */ if ((msg->message == WM_KEYUP) && @@ -472,7 +500,7 @@ raw_message += WM_LBUTTONDOWN - WM_LBUTTONDBLCLK; } - if (remove) update_queue_key_state( raw_message, 0 ); + if (remove) update_queue_key_state( raw_message, 0, 0 ); if (HOOK_IsHooked( WH_MOUSE )) { @@ -646,7 +674,7 @@ * GetKeyboardState (USER32.@) * * An application calls the GetKeyboardState function in response to a - * keyboard-input message. This function retrieves the state of the keyboard + * keyboard input message. This function retrieves the state of the keyboard * at the time the input message was generated. (SDK 3.1 Vol 2. p 387) */ BOOL WINAPI GetKeyboardState(LPBYTE lpKeyState)