keyboard patch

Andreas Mohr andi at rhlx01.fht-esslingen.de
Sun Aug 4 11:49:24 CDT 2002


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
-------------- next part --------------
Determining best CVS host...
Using CVSROOT :pserver:cvs at 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)


More information about the wine-patches mailing list