update for HEAD-2003091401
[reactos.git] / subsys / win32k / ntuser / keyboard.c
index b060ea2..0cbdd17 100644 (file)
@@ -1,9 +1,27 @@
+/*
+ *  ReactOS W32 Subsystem
+ *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  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.
+ */
 /* $Id$
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
  * PURPOSE:          Messages
- * FILE:             subsys/win32k/ntuser/message.c
+ * FILE:             subsys/win32k/ntuser/keyboard.c
  * PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
  * REVISION HISTORY:
  *       06-06-2001  CSH  Created
@@ -13,6 +31,8 @@
 
 #include <ddk/ntddk.h>
 #include <win32k/win32k.h>
+#include <internal/safe.h>
+#include <internal/kbd.h>
 #include <include/guicheck.h>
 #include <include/msgqueue.h>
 #include <include/window.h>
 #define NDEBUG
 #include <debug.h>
 
-/* FUNCTIONS *****************************************************************/
-
+DWORD ModBits = 0;
 BYTE QueueKeyStateTable[256];
+static PVOID pkKeyboardLayout = 0;
+
+/* arty -- These should be phased out for the general kbdxx.dll tables */
 
 struct accent_char
 {
@@ -145,40 +167,231 @@ static const struct accent_char accent_chars[] =
 /*  {'.', 'I', '\335'},  {'.', 'i', '\375'}, */        /* dot above */
 };
 
+/* FUNCTIONS *****************************************************************/
+
+/*** Statics used by TranslateMessage ***/
+
+static VOID STDCALL SetKeyState(DWORD key, BOOL down) {
+  if( key >= 'a' && key <= 'z' ) key += 'A' - 'a';
+  QueueKeyStateTable[key] = down;
+}
+
+static BOOL SetModKey( PKBDTABLES pkKT, WORD wVK, BOOL down ) {
+  int i;
+  
+  for( i = 0; pkKT->pCharModifiers->pVkToBit[i].Vk; i++ ) {
+    DbgPrint( "vk[%d] = { %04x, %x }\n", i, 
+       pkKT->pCharModifiers->pVkToBit[i].Vk,
+       pkKT->pCharModifiers->pVkToBit[i].ModBits );
+    if( pkKT->pCharModifiers->pVkToBit[i].Vk == wVK ) {
+      if( down ) ModBits |= pkKT->pCharModifiers->pVkToBit[i].ModBits;
+      else ModBits &= ~pkKT->pCharModifiers->pVkToBit[i].ModBits;
+      DbgPrint( "ModBits: %x\n", ModBits );
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+static BOOL TryToTranslateChar( WORD wVirtKey,
+                               PVK_TO_WCHAR_TABLE vtwTbl, 
+                               DWORD ModBits,
+                               PBOOL pbDead,
+                               PBOOL pbLigature,
+                               PWCHAR pwcTranslatedChar ) {
+  int i,j;
+  size_t size_this_entry = vtwTbl->cbSize;
+  int nStates = vtwTbl->nModifications;
+  PVK_TO_WCHARS10 vkPtr;
+
+  for( i = 0;; i++ ) {
+    vkPtr = (PVK_TO_WCHARS10)
+      (((BYTE *)vtwTbl->pVkToWchars) + i * size_this_entry);
+
+    if( !vkPtr->VirtualKey ) return FALSE;
+    if( wVirtKey == vkPtr->VirtualKey ) {
+      for( j = 0; j < nStates; j++ ) {
+       if( j == (int) ModBits ) { /* OK, we found a wchar with the correct
+                               shift state and vk */
+         *pbDead = vkPtr->wch[j] == WCH_DEAD;
+         *pbLigature = vkPtr->wch[j] == WCH_LGTR;
+         *pwcTranslatedChar = vkPtr->wch[j];
+         if( *pbDead ) {
+           i++;
+           vkPtr = (PVK_TO_WCHARS10)
+             (((BYTE *)vtwTbl->pVkToWchars) + i * size_this_entry);
+           if( vkPtr->VirtualKey != 0xff ) {
+             DPRINT( "Found dead key with no trailer in the table.\n" );
+             DPRINT( "VK: %04x, ADDR: %08x\n", wVirtKey, (int)vkPtr );
+             return FALSE;
+           }
+           *pwcTranslatedChar = vkPtr->wch[j];
+         }
+         return TRUE;
+       }
+      }
+    }
+  }
+}
+
+static
 int STDCALL
-ToUnicode(UINT wVirtKey,
-         UINT wScanCode,
-         PBYTE lpKeyState,
-         LPWSTR pwszBuff,
-         int cchBuff,
-         UINT wFlags)
+ToUnicodeInner(UINT wVirtKey,
+              UINT wScanCode,
+              PBYTE lpKeyState,
+              LPWSTR pwszBuff,
+              int cchBuff,
+              UINT wFlags,
+              DWORD ModBits,
+              PKBDTABLES pkKT)
 {
+  int i;
+
+  DbgPrint("wVirtKey=%08x, wScanCode=%08x, lpKeyState=[], "
+          "pwszBuff=%S, cchBuff=%d, wFlags=%x\n",
+          wVirtKey, wScanCode, /* lpKeyState, */ pwszBuff,
+          cchBuff, wFlags );
+
+  for( i = 0; pkKT->pVkToWcharTable[i].nModifications; i++ ) {
+    WCHAR wcTranslatedChar;
+    BOOL bDead;
+    BOOL bLigature;
+
+    if( TryToTranslateChar( wVirtKey,
+                           &pkKT->pVkToWcharTable[i], 
+                           ModBits,
+                           &bDead,
+                           &bLigature,
+                           &wcTranslatedChar ) ) {
+      if( bLigature ) {
+       DPRINT("Not handling ligature (yet)\n" );
+       return 0;
+      }
+
+      if( cchBuff > 0 ) pwszBuff[0] = wcTranslatedChar;
+
+      if( bDead ) return -1;
+      else return 1;
+    }
+  }
+
+  return 0;
+}
+
+DWORD
+STDCALL
+NtUserGetKeyState(
+  DWORD key)
+{
+  DWORD ret;
+
+    if (key >= 'a' && key <= 'z') key += 'A' - 'a';
+    ret = ((DWORD)(QueueKeyStateTable[key] & 0x80) << 8 ) |
+              (QueueKeyStateTable[key] & 0x80) |
+              (QueueKeyStateTable[key] & 0x01);
+    return ret;
+}
+
+int STDCALL ToUnicode( UINT wVirtKey,
+                      UINT wScanCode,
+                      PBYTE lpKeyState,
+                      LPWSTR pwszBuff,
+                      int cchBuff,
+                      UINT wFlags ) {
+  return ToUnicodeInner( wVirtKey,
+                        wScanCode,
+                        QueueKeyStateTable,
+                        pwszBuff,
+                        cchBuff,
+                        wFlags,
+                        ModBits,
+                        pkKeyboardLayout );
+}
+
+typedef PVOID (*KbdLayerDescriptor)(VOID);
+NTSTATUS STDCALL LdrGetProcedureAddress(PVOID module,
+                                       PANSI_STRING import_name,
+                                       DWORD flags,
+                                       PVOID *func_addr);
+
+void InitKbdLayout( PVOID *pkKeyboardLayout ) {
+  HMODULE kbModule = 0;
+  ANSI_STRING kbdProcedureName;
+  //NTSTATUS Status;
+
+  KbdLayerDescriptor layerDescGetFn;
+
+  kbModule = EngLoadImage(L"\\SystemRoot\\system32\\kbdus.dll");
+
+  if( !kbModule ) {
+    DbgPrint( "Foo: No kbdus.dll\n" );
+    return;
+  }
+
+  RtlInitAnsiString( &kbdProcedureName, "KbdLayerDescriptor" );
+  LdrGetProcedureAddress((PVOID)kbModule,
+                        &kbdProcedureName,
+                        0,
+                        (PVOID*)&layerDescGetFn);
+  if( layerDescGetFn ) {
+    *pkKeyboardLayout = layerDescGetFn();
+  }
 }
 
 BOOL STDCALL
 NtUserTranslateMessage(LPMSG lpMsg,
-                      DWORD Unknown1)
+                      DWORD Unknown1) /* Used to pass the kbd layout */
 {
-  LONG UState;
-  WCHAR wp[2];
-  MSG NewMsg;
-  static INT dead_char;
+  static INT dead_char = 0;
+  LONG UState = 0;
+  WCHAR wp[2] = { 0 };
+  MSG NewMsg = { 0 };
   PUSER_MESSAGE UMsg;
 
+  /* FIXME: Should pass current keyboard layout for this thread. */
+  /* At the moment, the keyboard layout is global. */
+  /* Also, we're fixed at kbdus.dll ... */
+  if( !pkKeyboardLayout ) InitKbdLayout( &pkKeyboardLayout );
+  if( !pkKeyboardLayout ) {
+    DbgPrint( "Not Translating due to empty layout.\n" );
+    return FALSE;
+  }
+
   if (lpMsg->message != WM_KEYDOWN && lpMsg->message != WM_SYSKEYDOWN)
     {
+      if (lpMsg->message == WM_KEYUP) {
+       DbgPrint( "About to SetKeyState( %04x, FALSE );\n", lpMsg->wParam );
+       SetKeyState( lpMsg->wParam, FALSE ); /* Release key */
+        DbgPrint( "About to SetModKey();\n" );
+       SetModKey( pkKeyboardLayout, lpMsg->wParam, FALSE );
+       /* Release Mod if any */
+       DbgPrint( "Done with keys.\n" );
+      }
       return(FALSE);
     }
 
-  /* FIXME: Should pass current keyboard layout for this thread. */
-  UState = ToUnicode(lpMsg->wParam, HIWORD(lpMsg->lParam),
-                    QueueKeyStateTable, wp, 2, 0);
+  DbgPrint( "About to SetKeyState( %04x, TRUE );\n", lpMsg->wParam );
+  SetKeyState( lpMsg->wParam, TRUE ); /* Strike key */
+
+  /* Pass 1: Search for modifiers */
+  DbgPrint( "About to SetModKey();\n" );
+  if( SetModKey( pkKeyboardLayout, lpMsg->wParam, TRUE ) ) return TRUE;
+  DbgPrint( "Done with keys.\n" );
+
+  /* Pass 2: Get Unicode Character */
+  DbgPrint( "Calling ToUnicodeString()\n" );
+  UState = ToUnicodeInner(lpMsg->wParam, HIWORD(lpMsg->lParam),
+                         QueueKeyStateTable, wp, 2, 0, ModBits,
+                         pkKeyboardLayout);
+
+  DbgPrint( "UState is %d after key %04x\n", UState, wp[0] );
   if (UState == 1)
     {
       NewMsg.message = (lpMsg->message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
       if (dead_char)
         {
-         int i;
+         ULONG i;
          
          if (wp[0] == ' ') wp[0] =  dead_char;
          if (dead_char == 0xa2) dead_char = '(';
@@ -198,13 +411,14 @@ NtUserTranslateMessage(LPMSG lpMsg,
                 }
              dead_char = 0;
            }
-         NewMsg.hwnd = lpMsg->hwnd;
-         NewMsg.wParam = wp[0];
-         NewMsg.lParam = lpMsg->lParam;
-         UMsg = MsqCreateMessage(&NewMsg);
-         MsqPostMessage(PsGetWin32Thread()->MessageQueue, UMsg);
-         return(TRUE);
-       }
+        }
+      NewMsg.hwnd = lpMsg->hwnd;
+      NewMsg.wParam = wp[0];
+      NewMsg.lParam = lpMsg->lParam;
+      UMsg = MsqCreateMessage(&NewMsg);
+      DbgPrint( "CHAR='%c' %04x %08x\n", wp[0], wp[0], lpMsg->lParam );
+      MsqPostMessage(PsGetWin32Thread()->MessageQueue, UMsg);
+      return(TRUE);
     }
   else if (UState == -1)
     {
@@ -220,3 +434,36 @@ NtUserTranslateMessage(LPMSG lpMsg,
     }
   return(FALSE);
 }
+
+HWND STDCALL
+NtUserSetFocus(HWND hWnd)
+{
+  return IntSetFocusWindow(hWnd);
+}
+
+DWORD
+STDCALL
+NtUserGetKeyboardState(
+  LPBYTE lpKeyState)
+{
+  if (lpKeyState) {
+       if(!NT_SUCCESS(MmCopyToCaller(lpKeyState, QueueKeyStateTable, 256)))
+               return FALSE;
+  }
+  return TRUE;
+}
+
+DWORD
+STDCALL
+NtUserSetKeyboardState(
+  LPBYTE lpKeyState)
+{
+       if (lpKeyState) {
+               if(! NT_SUCCESS(MmCopyFromCaller(QueueKeyStateTable, lpKeyState, 256)))
+                       return FALSE;
+       }
+    return TRUE;
+}
+
+
+/* EOF */