Fixing GetAsyncKeyState

Jukka Heinonen jhei at iki.fi
Wed Apr 18 03:43:38 CDT 2001


Function GetAsyncKeyState is supposed to check the
state of a single mouse button or a single key and return
the following pieces of information:

 (1) Key/button is currently pressed.
 (2) Key/button has been pressed since the last
     call to this function.

Wine currently interprets case (2) so that a call to
GetAsyncKeyState clears this status for
every mouse button and every key. I believe this to
be an incorrect interpretation and that each call to
GetAsyncKeyState should clear this status only
for the requested key. I haven't been able to 
confirm this since I don't have a Windows machine.

Anyway, Baldur's Gate (and most likely Fallouts, too) work
by calling GetAsyncKeyState for each mouse button or key
they are interested in. If you click a mouse button or a key,
case (1) above yields almost always a false result.
So, these games must trust on case (2). However, the current
Wine behaviour makes case (2) unpredictable if you poll
multiple keys. So, either Wine has wrong interpretation or
these games have serious design flaws. Either way,
changing the behaviour of GetAsyncKeyState makes practically
unplayable games just about flawless without any obvious
side effects.

Log:
GetAsyncKeyState now clears "has been pressed" information
of only the requested key instead of all keys.

Patch:
--- wine/windows/input.c     2001/01/15 20:09:11     1.45
+++ wine/windows/input.c     2001/04/18 09:13:04
@@ -601,24 +601,24 @@
      case VK_LBUTTON:
        retval = (AsyncMouseButtonsStates[0] ? 0x0001 : 0) |
                  (MouseButtonsStates[0] ? 0x8000 : 0);
+       AsyncMouseButtonsStates[0] = 0;
        break;
      case VK_MBUTTON:
        retval = (AsyncMouseButtonsStates[1] ? 0x0001 : 0) |
                  (MouseButtonsStates[1] ? 0x8000 : 0);
+       AsyncMouseButtonsStates[1] = 0;
        break;
      case VK_RBUTTON:
        retval = (AsyncMouseButtonsStates[2] ? 0x0001 : 0) |
                  (MouseButtonsStates[2] ? 0x8000 : 0);
+       AsyncMouseButtonsStates[2] = 0;
        break;
      default:
        retval = AsyncKeyStateTable[nKey] |
                ((InputKeyStateTable[nKey] & 0x80) ? 0x8000 : 0);
+       AsyncKeyStateTable[nKey] = 0;
        break;
     }
-
-    /* all states to false */
-    memset( AsyncMouseButtonsStates, 0, sizeof(AsyncMouseButtonsStates) );
-    memset( AsyncKeyStateTable, 0, sizeof(AsyncKeyStateTable) );
 
     TRACE_(key)("(%x) -> %x\n", nKey, retval);
     return retval;

-- 
Jukka Heinonen <http://www.iki.fi/jhei/>




More information about the wine-patches mailing list