keyboard patch (take 2)

Andreas Mohr andi at rhlx01.fht-esslingen.de
Sun Oct 27 12:20:08 CST 2002


Hi all,

resending this patch as it hasn't been applied before.
I just hope it won't break the current interrupt reorganisation ;-)

- 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/DOS :-)
(menu invocation and special functions)

-- 
Andreas Mohr                        Stauferstr. 6, D-71272 Renningen, Germany
-------------- next part --------------
Determining best CVS host...
Using CVSROOT :pserver:cvs at cvs.winehq.com:/home/wine
Index: dlls/winedos/dosvm.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/dosvm.c,v
retrieving revision 1.26
diff -u -r1.26 dosvm.c
--- dlls/winedos/dosvm.c	23 Oct 2002 22:24:10 -0000	1.26
+++ dlls/winedos/dosvm.c	27 Oct 2002 17:16:00 -0000
@@ -240,12 +240,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,
@@ -253,7 +257,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	27 Oct 2002 17:16:01 -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 = BIOS_DATA;
   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.7
diff -u -r1.7 int16.c
--- dlls/winedos/int16.c	31 Aug 2002 18:47:00 -0000	1.7
+++ dlls/winedos/int16.c	27 Oct 2002 17:16:01 -0000
@@ -51,7 +51,9 @@
 
 void WINAPI DOSVM_Int16Handler( CONTEXT86 *context )
 {
-    BYTE ascii, scan;
+   BIOSDATA *data = NULL;
+   BYTE ascii, scan;
+
    switch AH_reg(context) {
 
    case 0x00: /* Get Keystroke */
@@ -84,24 +86,11 @@
       break;
 
    case 0x02: /* Get Shift Flags */
-      SET_AL( context, 0 );
 
-      if (GetAsyncKeyState(VK_RSHIFT))
-          context->Eax |= 0x01;
-      if (GetAsyncKeyState(VK_LSHIFT))
-          context->Eax |= 0x02;
-      if (GetAsyncKeyState(VK_LCONTROL) || GetAsyncKeyState(VK_RCONTROL))
-          context->Eax |= 0x04;
-      if (GetAsyncKeyState(VK_LMENU) || GetAsyncKeyState(VK_RMENU))
-          context->Eax |= 0x08;
-      if (GetAsyncKeyState(VK_SCROLL))
-          context->Eax |= 0x10;
-      if (GetAsyncKeyState(VK_NUMLOCK))
-          context->Eax |= 0x20;
-      if (GetAsyncKeyState(VK_CAPITAL))
-          context->Eax |= 0x40;
-      if (GetAsyncKeyState(VK_INSERT))
-          context->Eax |= 0x80;
+      /* read value from BIOS data segment's keyboard status flags field */
+      data = BIOS_DATA;
+      SET_AL( context, data->KbdFlags1 );
+
       TRACE("Get Shift Flags: returning 0x%02x\n", AL_reg(context));
       break;
 
Index: programs/wineconsole/user.c
===================================================================
RCS file: /home/wine/wine/programs/wineconsole/user.c,v
retrieving revision 1.16
diff -u -r1.16 user.c
--- programs/wineconsole/user.c	4 Sep 2002 18:41:52 -0000	1.16
+++ programs/wineconsole/user.c	27 Oct 2002 17:16:02 -0000
@@ -874,7 +874,7 @@
 }
 
 /******************************************************************
- *		CUSER_GetCtrlKeyState
+ *		WCUSER_GetCtrlKeyState
  *
  * Get the console bit mask equivalent to the VK_ status in keyState
  */
@@ -884,7 +884,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.145
diff -u -r1.145 message.c
--- windows/message.c	17 Oct 2002 18:26:53 -0000	1.145
+++ windows/message.c	27 Oct 2002 17:16:04 -0000
@@ -134,9 +134,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)
     {
@@ -165,8 +166,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];
@@ -174,6 +192,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;
+    }
 }
 
 
@@ -328,7 +356,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);
 }
@@ -343,7 +371,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) &&
@@ -483,7 +511,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 ))
     {
@@ -662,7 +690,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