[WIN32K]
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / keyboard.c
index 0620235..70e9054 100644 (file)
@@ -12,9 +12,9 @@
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 /*
  * COPYRIGHT:        See COPYING in the top level directory
@@ -28,7 +28,7 @@
 
 /* INCLUDES ******************************************************************/
 
-#include <w32k.h>
+#include <win32k.h>
 
 #define NDEBUG
 #include <debug.h>
@@ -42,7 +42,9 @@
 /* Key States */
 #define KS_DOWN_MASK     0xc0
 #define KS_DOWN_BIT      0x80
-#define KS_LOCK_BIT    0x01
+#define KS_LOCK_BIT      0x01
+/* Scan Codes */
+#define SC_KEY_UP        0x8000
 /* lParam bits */
 #define LP_EXT_BIT       (1<<24)
 /* From kbdxx.c -- Key changes with numlock */
@@ -69,15 +71,15 @@ NTSTATUS FASTCALL InitKeyboardImpl(VOID)
 static UINT DontDistinguishShifts( UINT ret )
 {
    if( ret == VK_LSHIFT || ret == VK_RSHIFT )
-      ret = VK_LSHIFT;
+      ret = VK_SHIFT;
    if( ret == VK_LCONTROL || ret == VK_RCONTROL )
-      ret = VK_LCONTROL;
+      ret = VK_CONTROL;
    if( ret == VK_LMENU || ret == VK_RMENU )
-      ret = VK_LMENU;
+      ret = VK_MENU;
    return ret;
 }
 
-static VOID STDCALL SetKeyState(DWORD key, DWORD vk, DWORD ext, BOOL down)
+static VOID APIENTRY SetKeyState(DWORD key, DWORD vk, DWORD ext, BOOL down)
 {
    ASSERT(vk <= 0xff);
 
@@ -88,12 +90,12 @@ static VOID STDCALL SetKeyState(DWORD key, DWORD vk, DWORD ext, BOOL down)
          gQueueKeyStateTable[vk] ^= KS_LOCK_BIT;
    }
 
-   if (ext && vk == VK_LSHIFT)
-      vk = VK_RSHIFT;
-   if (ext && vk == VK_LCONTROL)
-      vk = VK_RCONTROL;
-   if (ext && vk == VK_LMENU)
-      vk = VK_RMENU;
+   if (vk == VK_SHIFT)
+      vk = ext ? VK_RSHIFT : VK_LSHIFT;
+   if (vk == VK_CONTROL)
+      vk = ext ? VK_RCONTROL : VK_LCONTROL;
+   if (vk == VK_MENU)
+      vk = ext ? VK_RMENU : VK_LMENU;
 
    if (down)
       gQueueKeyStateTable[vk] |= KS_DOWN_BIT;
@@ -213,9 +215,10 @@ static DWORD ModBits( PKBDTABLES pkKT, PBYTE KeyState )
       ModBits |= GetShiftBit( pkKT, VK_MENU );
 
    /* Handle Alt+Gr */
-   if (KeysSet( pkKT, KeyState, VK_RMENU, 0 ) &
-         KS_DOWN_BIT )
-      ModBits |= GetShiftBit( pkKT, VK_CONTROL );
+   if (pkKT->fLocalFlags & 0x1) 
+      if (KeysSet( pkKT, KeyState, VK_RMENU, 0 ) &
+            KS_DOWN_BIT)
+         ModBits |= GetShiftBit( pkKT, VK_CONTROL );
 
    /* Deal with VK_CAPITAL */
    if (KeysSet( pkKT, KeyState, VK_CAPITAL, 0 ) & KS_LOCK_BIT)
@@ -294,7 +297,7 @@ static BOOL TryToTranslateChar(WORD wVirtKey,
                if( vkPtr->VirtualKey != 0xff )
                {
                   DPRINT( "Found dead key with no trailer in the table.\n" );
-                  DPRINT( "VK: %04x, ADDR: %08x\n", wVirtKey, (int)vkPtr );
+                  DPRINT( "VK: %04x, ADDR: %p\n", wVirtKey, vkPtr );
                   return FALSE;
                }
                *pwcTranslatedChar = vkPtr->wch[CapsMod];
@@ -308,7 +311,7 @@ static BOOL TryToTranslateChar(WORD wVirtKey,
 }
 
 static
-int STDCALL
+int APIENTRY
 ToUnicodeInner(UINT wVirtKey,
                UINT wScanCode,
                PBYTE lpKeyState,
@@ -361,10 +364,10 @@ DWORD FASTCALL UserGetKeyState(DWORD key)
 }
 
 
-DWORD
-STDCALL
+SHORT
+APIENTRY
 NtUserGetKeyState(
-   DWORD key)
+   INT key)
 {
    DECLARE_RETURN(DWORD);
 
@@ -396,17 +399,17 @@ DWORD FASTCALL UserGetAsyncKeyState(DWORD key)
 
 
 
-DWORD
-STDCALL
+SHORT
+APIENTRY
 NtUserGetAsyncKeyState(
-   DWORD key)
+   INT key)
 {
-   DECLARE_RETURN(DWORD);
+   DECLARE_RETURN(SHORT);
 
    DPRINT("Enter NtUserGetAsyncKeyState\n");
    UserEnterExclusive();
 
-   RETURN(UserGetAsyncKeyState(key));
+   RETURN((SHORT)UserGetAsyncKeyState(key));
 
 CLEANUP:
    DPRINT("Leave NtUserGetAsyncKeyState, ret=%i\n",_ret_);
@@ -418,8 +421,9 @@ CLEANUP:
 
 BOOL FASTCALL
 IntTranslateKbdMessage(LPMSG lpMsg,
-                       HKL dwhkl)
+                       UINT flags)
 {
+   PTHREADINFO pti;
    static INT dead_char = 0;
    LONG UState = 0;
    WCHAR wp[2] = { 0 };
@@ -428,19 +432,31 @@ IntTranslateKbdMessage(LPMSG lpMsg,
    BOOL Result = FALSE;
    DWORD ScanCode = 0;
 
-
-   keyLayout = PsGetCurrentThreadWin32Thread()->KeyboardLayout->KBTables;
+   pti = PsGetCurrentThreadWin32Thread();
+   keyLayout = pti->KeyboardLayout->KBTables;
    if( !keyLayout )
       return FALSE;
 
+   if (lpMsg->message < WM_KEYFIRST || lpMsg->message > WM_KEYLAST)
+      return FALSE;
    if (lpMsg->message != WM_KEYDOWN && lpMsg->message != WM_SYSKEYDOWN)
       return FALSE;
 
-   ScanCode = (lpMsg->lParam >> 16) & 0xff;
-
    /* All messages have to contain the cursor point. */
-   IntGetCursorLocation(PsGetCurrentThreadWin32Thread()->Desktop->WindowStation,
-                        &NewMsg.pt);
+   NewMsg.pt = gpsi->ptCursor;
+
+    switch (lpMsg->wParam)
+    {
+    case VK_PACKET:
+        NewMsg.message = (lpMsg->message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
+        NewMsg.hwnd = lpMsg->hwnd;
+        NewMsg.wParam = HIWORD(lpMsg->lParam);
+        NewMsg.lParam = LOWORD(lpMsg->lParam);
+        MsqPostMessage(pti->MessageQueue, &NewMsg, FALSE, QS_KEY);
+        return TRUE;
+    }
+
+   ScanCode = (lpMsg->lParam >> 16) & 0xff;
 
    UState = ToUnicodeInner(lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff,
                            gQueueKeyStateTable, wp, 2, 0,
@@ -476,14 +492,14 @@ IntTranslateKbdMessage(LPMSG lpMsg,
          NewMsg.wParam = dead_char;
          NewMsg.lParam = lpMsg->lParam;
          dead_char = 0;
-         MsqPostMessage(PsGetCurrentThreadWin32Thread()->MessageQueue, &NewMsg, FALSE, QS_KEY);
+         MsqPostMessage(pti->MessageQueue, &NewMsg, FALSE, QS_KEY);
       }
 
       NewMsg.hwnd = lpMsg->hwnd;
       NewMsg.wParam = wp[0];
       NewMsg.lParam = lpMsg->lParam;
       DPRINT( "CHAR='%c' %04x %08x\n", wp[0], wp[0], lpMsg->lParam );
-      MsqPostMessage(PsGetCurrentThreadWin32Thread()->MessageQueue, &NewMsg, FALSE, QS_KEY);
+      MsqPostMessage(pti->MessageQueue, &NewMsg, FALSE, QS_KEY);
       Result = TRUE;
    }
    else if (UState == -1)
@@ -494,7 +510,7 @@ IntTranslateKbdMessage(LPMSG lpMsg,
       NewMsg.wParam = wp[0];
       NewMsg.lParam = lpMsg->lParam;
       dead_char = wp[0];
-      MsqPostMessage(PsGetCurrentThreadWin32Thread()->MessageQueue, &NewMsg, FALSE, QS_KEY);
+      MsqPostMessage(pti->MessageQueue, &NewMsg, FALSE, QS_KEY);
       Result = TRUE;
    }
 
@@ -502,7 +518,7 @@ IntTranslateKbdMessage(LPMSG lpMsg,
 }
 
 DWORD
-STDCALL
+APIENTRY
 NtUserGetKeyboardState(
    LPBYTE lpKeyState)
 {
@@ -526,8 +542,8 @@ CLEANUP:
    END_CLEANUP;
 }
 
-DWORD
-STDCALL
+BOOL
+APIENTRY
 NtUserSetKeyboardState(LPBYTE lpKeyState)
 {
    BOOL Result = TRUE;
@@ -626,11 +642,11 @@ static UINT IntMapVirtualKeyEx( UINT Code, UINT Type, PKBDTABLES keyLayout )
    switch( Type )
    {
       case 0:
-         if( Code == VK_RSHIFT )
+         if( Code == VK_SHIFT )
             Code = VK_LSHIFT;
-         if( Code == VK_RMENU )
+         if( Code == VK_MENU )
             Code = VK_LMENU;
-         if( Code == VK_RCONTROL )
+         if( Code == VK_CONTROL )
             Code = VK_LCONTROL;
          ret = VkToScan( Code, FALSE, keyLayout );
          break;
@@ -661,16 +677,18 @@ static UINT IntMapVirtualKeyEx( UINT Code, UINT Type, PKBDTABLES keyLayout )
 }
 
 UINT
-STDCALL
+APIENTRY
 NtUserMapVirtualKeyEx( UINT Code, UINT Type, DWORD keyboardId, HKL dwhkl )
 {
+   PTHREADINFO pti;
    PKBDTABLES keyLayout;
    DECLARE_RETURN(UINT);
 
    DPRINT("Enter NtUserMapVirtualKeyEx\n");
    UserEnterExclusive();
 
-   keyLayout = PsGetCurrentThreadWin32Thread() ? PsGetCurrentThreadWin32Thread()->KeyboardLayout->KBTables : 0;
+   pti = PsGetCurrentThreadWin32Thread();
+   keyLayout = pti ? pti->KeyboardLayout->KBTables : 0;
 
    if( !keyLayout )
       RETURN(0);
@@ -685,7 +703,7 @@ CLEANUP:
 
 
 int
-STDCALL
+APIENTRY
 NtUserToUnicodeEx(
    UINT wVirtKey,
    UINT wScanCode,
@@ -695,14 +713,20 @@ NtUserToUnicodeEx(
    UINT wFlags,
    HKL dwhkl )
 {
+   PTHREADINFO pti;
    BYTE KeyStateBuf[0x100];
    PWCHAR OutPwszBuff = 0;
    int ret = 0;
    DECLARE_RETURN(int);
 
    DPRINT("Enter NtUserSetKeyboardState\n");
-   UserEnterShared();//faxme: this syscall doesnt seem to need any locking...
+   UserEnterShared();//fixme: this syscall doesnt seem to need any locking...
 
+   /* Key up? */
+   if (wScanCode & SC_KEY_UP)
+   {
+      RETURN(0);
+   }
 
    if( !NT_SUCCESS(MmCopyFromCaller(KeyStateBuf,
                                     lpKeyState,
@@ -711,25 +735,30 @@ NtUserToUnicodeEx(
       DPRINT1( "Couldn't copy key state from caller.\n" );
       RETURN(0);
    }
-   OutPwszBuff = ExAllocatePoolWithTag(NonPagedPool,sizeof(WCHAR) * cchBuff, TAG_STRING);
-   if( !OutPwszBuff )
+   
+   /* Virtual code is correct? */
+   if (wVirtKey < 0x100)
    {
-      DPRINT1( "ExAllocatePool(%d) failed\n", sizeof(WCHAR) * cchBuff);
-      RETURN(0);
+      OutPwszBuff = ExAllocatePoolWithTag(NonPagedPool,sizeof(WCHAR) * cchBuff, TAG_STRING);
+      if( !OutPwszBuff )
+      {
+         DPRINT1( "ExAllocatePoolWithTag(%d) failed\n", sizeof(WCHAR) * cchBuff);
+         RETURN(0);
+      }
+      RtlZeroMemory( OutPwszBuff, sizeof( WCHAR ) * cchBuff );
+
+      pti = PsGetCurrentThreadWin32Thread();
+      ret = ToUnicodeInner( wVirtKey,
+                            wScanCode,
+                            KeyStateBuf,
+                            OutPwszBuff,
+                            cchBuff,
+                            wFlags,
+                            pti ? pti->KeyboardLayout->KBTables : 0 );
+
+      MmCopyToCaller(pwszBuff,OutPwszBuff,sizeof(WCHAR)*cchBuff);
+      ExFreePoolWithTag(OutPwszBuff, TAG_STRING);
    }
-   RtlZeroMemory( OutPwszBuff, sizeof( WCHAR ) * cchBuff );
-
-   ret = ToUnicodeInner( wVirtKey,
-                         wScanCode,
-                         KeyStateBuf,
-                         OutPwszBuff,
-                         cchBuff,
-                         wFlags,
-                         PsGetCurrentThreadWin32Thread() ?
-                            PsGetCurrentThreadWin32Thread()->KeyboardLayout->KBTables : 0 );
-
-   MmCopyToCaller(pwszBuff,OutPwszBuff,sizeof(WCHAR)*cchBuff);
-   ExFreePool(OutPwszBuff);
 
    RETURN(ret);
 
@@ -747,9 +776,10 @@ static int W32kSimpleToupper( int ch )
 }
 
 DWORD
-STDCALL
+APIENTRY
 NtUserGetKeyNameText( LONG lParam, LPWSTR lpString, int nSize )
 {
+   PTHREADINFO pti;
    int i;
    DWORD ret = 0;
    UINT CareVk = 0;
@@ -763,8 +793,8 @@ NtUserGetKeyNameText( LONG lParam, LPWSTR lpString, int nSize )
    DPRINT("Enter NtUserGetKeyNameText\n");
    UserEnterShared();
 
-   keyLayout = PsGetCurrentThreadWin32Thread() ?
-      PsGetCurrentThreadWin32Thread()->KeyboardLayout->KBTables : 0;
+   pti = PsGetCurrentThreadWin32Thread();
+   keyLayout = pti ? pti->KeyboardLayout->KBTables : 0;
 
    if( !keyLayout || nSize < 1 )
       RETURN(0);
@@ -772,12 +802,22 @@ NtUserGetKeyNameText( LONG lParam, LPWSTR lpString, int nSize )
    if( lParam & (1<<25) )
    {
       CareVk = VkCode = ScanToVk( ScanCode, ExtKey, keyLayout );
-      if( VkCode == VK_LSHIFT || VkCode == VK_RSHIFT )
-         VkCode = VK_LSHIFT;
-      if( VkCode == VK_LCONTROL || VkCode == VK_RCONTROL )
-         VkCode = VK_LCONTROL;
-      if( VkCode == VK_LMENU || VkCode == VK_RMENU )
-         VkCode = VK_LMENU;
+      switch (VkCode)
+      {
+          case VK_RSHIFT:
+              ScanCode |= 0x100;
+          case VK_LSHIFT:
+             VkCode = VK_SHIFT;
+             break;
+          case VK_LCONTROL:
+          case VK_RCONTROL:
+             VkCode = VK_CONTROL;
+             break;
+          case VK_LMENU:
+          case VK_RMENU:
+             VkCode = VK_MENU;
+             break;
+      }
    }
    else
    {
@@ -984,25 +1024,34 @@ UserGetKeyboardType(
     look for wChar match.
  */
 DWORD
-STDCALL
+APIENTRY
 NtUserVkKeyScanEx(
    WCHAR wChar,
-   HKL KeyboardLayout,
-   DWORD Unknown2)
+   HKL hKeyboardLayout,
+   BOOL UsehKL ) // TRUE from KeyboardLayout, FALSE from pkbl = (THREADINFO)->KeyboardLayout
 {
-/* FIXME: currently, this routine doesnt seem to need any locking */
    PKBDTABLES KeyLayout;
    PVK_TO_WCHAR_TABLE vtwTbl;
    PVK_TO_WCHARS10 vkPtr;
    size_t size_this_entry;
    int nMod;
-   DWORD CapsMod = 0, CapsState = 0;
+   PKBL pkbl = NULL;
+   DWORD CapsMod = 0, CapsState = 0, Ret = -1;
 
-   DPRINT("NtUserVkKeyScanEx() wChar %d, KbdLayout 0x%p\n", wChar, KeyboardLayout);
+   DPRINT("NtUserVkKeyScanEx() wChar %d, KbdLayout 0x%p\n", wChar, hKeyboardLayout);
+   UserEnterShared();
 
-   if(!KeyboardLayout)
-      return -1;
-   KeyLayout = UserHklToKbl(KeyboardLayout)->KBTables;
+   if (UsehKL)
+   {
+      if ( !hKeyboardLayout || !(pkbl = UserHklToKbl(hKeyboardLayout)))
+      goto Exit;
+   }
+   else // From VkKeyScanAW it is FALSE so KeyboardLayout is white noise.
+   {
+     pkbl = ((PTHREADINFO)PsGetCurrentThreadWin32Thread())->KeyboardLayout;
+   }   
+
+   KeyLayout = pkbl->KBTables;
 
    for (nMod = 0; KeyLayout->pVkToWcharTable[nMod].nModifications; nMod++)
    {
@@ -1025,13 +1074,16 @@ NtUserVkKeyScanEx(
                CapsMod = KeyLayout->pCharModifiers->ModNumber[CapsState];
                DPRINT("nMod %d wC %04x: CapsMod %08x CapsState %08x MaxModBits %08x\n",
                       nMod, wChar, CapsMod, CapsState, KeyLayout->pCharModifiers->wMaxModBits);
-               return ((CapsMod << 8)|(vkPtr->VirtualKey & 0xff));
+               Ret = ((CapsMod << 8)|(vkPtr->VirtualKey & 0xff));
+               goto Exit;
             }
          }
          vkPtr = (PVK_TO_WCHARS10)(((BYTE *)vkPtr) + size_this_entry);
       }
    }
-   return -1;
+Exit:
+   UserLeave();
+   return Ret;
 }