⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 keyboard.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 *  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.
 */
/*
 * COPYRIGHT:        See COPYING in the top level directory
 * PROJECT:          ReactOS kernel
 * PURPOSE:          Messages
 * FILE:             subsys/win32k/ntuser/keyboard.c
 * PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
 * REVISION HISTORY:
 *       06-06-2001  CSH  Created
 */

/* INCLUDES ******************************************************************/

#include <w32k.h>

#define NDEBUG
#include <debug.h>


/* Lock modifiers */
#define CAPITAL_BIT   0x80000000
#define NUMLOCK_BIT   0x40000000
#define MOD_BITS_MASK 0x3fffffff
#define MOD_KCTRL     0x02
/* Key States */
#define KS_DOWN_MASK     0xc0
#define KS_DOWN_BIT      0x80
#define KS_LOCK_BIT    0x01
/* lParam bits */
#define LP_EXT_BIT       (1<<24)
/* From kbdxx.c -- Key changes with numlock */
#define KNUMP         0x400


BYTE gQueueKeyStateTable[256];



/* FUNCTIONS *****************************************************************/

/* Initialization -- Right now, just zero the key state and init the lock */
NTSTATUS FASTCALL InitKeyboardImpl(VOID)
{
   RtlZeroMemory(&gQueueKeyStateTable,0x100);
   return STATUS_SUCCESS;
}

/*** Statics used by TranslateMessage ***/

/*** Shift state code was out of hand, sorry. --- arty */

static UINT DontDistinguishShifts( UINT ret )
{
   if( ret == VK_LSHIFT || ret == VK_RSHIFT )
      ret = VK_LSHIFT;
   if( ret == VK_LCONTROL || ret == VK_RCONTROL )
      ret = VK_LCONTROL;
   if( ret == VK_LMENU || ret == VK_RMENU )
      ret = VK_LMENU;
   return ret;
}

static VOID STDCALL SetKeyState(DWORD key, DWORD vk, DWORD ext, BOOL down)
{
   ASSERT(vk <= 0xff);

   /* Special handling for toggles like numpad and caps lock */
   if (vk == VK_CAPITAL || vk == VK_NUMLOCK)
   {
      if (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 (down)
      gQueueKeyStateTable[vk] |= KS_DOWN_BIT;
   else
      gQueueKeyStateTable[vk] &= ~KS_DOWN_MASK;

   if (vk == VK_LSHIFT || vk == VK_RSHIFT)
   {
      if ((gQueueKeyStateTable[VK_LSHIFT] & KS_DOWN_BIT) ||
            (gQueueKeyStateTable[VK_RSHIFT] & KS_DOWN_BIT))
      {
         gQueueKeyStateTable[VK_SHIFT] |= KS_DOWN_BIT;
      }
      else
      {
         gQueueKeyStateTable[VK_SHIFT] &= ~KS_DOWN_MASK;
      }
   }

   if (vk == VK_LCONTROL || vk == VK_RCONTROL)
   {
      if ((gQueueKeyStateTable[VK_LCONTROL] & KS_DOWN_BIT) ||
            (gQueueKeyStateTable[VK_RCONTROL] & KS_DOWN_BIT))
      {
         gQueueKeyStateTable[VK_CONTROL] |= KS_DOWN_BIT;
      }
      else
      {
         gQueueKeyStateTable[VK_CONTROL] &= ~KS_DOWN_MASK;
      }
   }

   if (vk == VK_LMENU || vk == VK_RMENU)
   {
      if ((gQueueKeyStateTable[VK_LMENU] & KS_DOWN_BIT) ||
            (gQueueKeyStateTable[VK_RMENU] & KS_DOWN_BIT))
      {
         gQueueKeyStateTable[VK_MENU] |= KS_DOWN_BIT;
      }
      else
      {
         gQueueKeyStateTable[VK_MENU] &= ~KS_DOWN_MASK;
      }
   }
}

VOID DumpKeyState( PBYTE KeyState )
{
   int i;

   DbgPrint( "KeyState { " );
   for( i = 0; i < 0x100; i++ )
   {
      if( KeyState[i] )
         DbgPrint( "%02x(%02x) ", i, KeyState[i] );
   }
   DbgPrint( "};\n" );
}

static BYTE KeysSet( PKBDTABLES pkKT, PBYTE KeyState,
                     int FakeModLeft, int FakeModRight )
{
   if( !KeyState || !pkKT )
      return 0;

   /* Search special codes first */
   if( FakeModLeft && KeyState[FakeModLeft] )
      return KeyState[FakeModLeft];
   else if( FakeModRight && KeyState[FakeModRight] )
      return KeyState[FakeModRight];

   return 0;
}

/* Search the keyboard layout modifiers table for the shift bit.  I don't
 * want to count on the shift bit not moving, because it can be specified
 * in the layout */

static DWORD FASTCALL GetShiftBit( PKBDTABLES pkKT, DWORD Vk )
{
   int i;

   for( i = 0; pkKT->pCharModifiers->pVkToBit[i].Vk; i++ )
      if( pkKT->pCharModifiers->pVkToBit[i].Vk == Vk )
         return pkKT->pCharModifiers->pVkToBit[i].ModBits;

   return 0;
}

static DWORD ModBits( PKBDTABLES pkKT, PBYTE KeyState )
{
   DWORD ModBits = 0;

   if( !KeyState )
      return 0;

   /* DumpKeyState( KeyState ); */

   if (KeysSet( pkKT, KeyState, VK_LSHIFT, VK_RSHIFT ) &
         KS_DOWN_BIT)
      ModBits |= GetShiftBit( pkKT, VK_SHIFT );

   if (KeysSet( pkKT, KeyState, VK_LCONTROL, VK_RCONTROL ) &
         KS_DOWN_BIT )
      ModBits |= GetShiftBit( pkKT, VK_CONTROL );

   if (KeysSet( pkKT, KeyState, VK_LMENU, VK_RMENU ) &
         KS_DOWN_BIT )
      ModBits |= GetShiftBit( pkKT, VK_MENU );

   /* Handle Alt+Gr */
   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)
   {
      ModBits |= CAPITAL_BIT;
   }

   /* Deal with VK_NUMLOCK */
   if (KeysSet( pkKT, KeyState, VK_NUMLOCK, 0 ) & KS_LOCK_BIT)
   {
      ModBits |= NUMLOCK_BIT;
   }

   DPRINT( "Current Mod Bits: %x\n", ModBits );

   return ModBits;
}

static BOOL TryToTranslateChar(WORD wVirtKey,
                               DWORD ModBits,
                               PBOOL pbDead,
                               PBOOL pbLigature,
                               PWCHAR pwcTranslatedChar,
                               PKBDTABLES keyLayout )
{
   PVK_TO_WCHAR_TABLE vtwTbl;
   PVK_TO_WCHARS10 vkPtr;
   size_t size_this_entry;
   int nMod;
   DWORD CapsMod = 0, CapsState = 0;

   CapsState = ModBits & ~MOD_BITS_MASK;
   ModBits = ModBits & MOD_BITS_MASK;

   DPRINT ( "TryToTranslate: %04x %x\n", wVirtKey, ModBits );

   if (ModBits > keyLayout->pCharModifiers->wMaxModBits)
   {
      return FALSE;
   }

   for (nMod = 0; keyLayout->pVkToWcharTable[nMod].nModifications; nMod++)
   {
      vtwTbl = &keyLayout->pVkToWcharTable[nMod];
      size_this_entry = vtwTbl->cbSize;
      vkPtr = (PVK_TO_WCHARS10)((BYTE *)vtwTbl->pVkToWchars);
      while(vkPtr->VirtualKey)
      {
         if( wVirtKey == (vkPtr->VirtualKey & 0xff) )
         {
            CapsMod = keyLayout->pCharModifiers->ModNumber
                      [ModBits ^
                       ((CapsState & CAPITAL_BIT) ? vkPtr->Attributes : 0)];

            if( CapsMod >= keyLayout->pVkToWcharTable[nMod].nModifications )
            {
               return FALSE;
            }

            if( vkPtr->wch[CapsMod] == WCH_NONE )
            {
               return FALSE;
            }

            *pbDead = vkPtr->wch[CapsMod] == WCH_DEAD;
            *pbLigature = vkPtr->wch[CapsMod] == WCH_LGTR;
            *pwcTranslatedChar = vkPtr->wch[CapsMod];

            DPRINT("%d %04x: CapsMod %08x CapsState %08x Char %04x\n",
                   nMod, wVirtKey,
                   CapsMod, CapsState, *pwcTranslatedChar);

            if( *pbDead )
            {
               vkPtr = (PVK_TO_WCHARS10)(((BYTE *)vkPtr) + 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[CapsMod];
            }
            return TRUE;
         }
         vkPtr = (PVK_TO_WCHARS10)(((BYTE *)vkPtr) + size_this_entry);
      }
   }
   return FALSE;
}

static
int STDCALL
ToUnicodeInner(UINT wVirtKey,
               UINT wScanCode,
               PBYTE lpKeyState,
               LPWSTR pwszBuff,
               int cchBuff,
               UINT wFlags,
               PKBDTABLES pkKT)
{
   WCHAR wcTranslatedChar;
   BOOL bDead;
   BOOL bLigature;

   if( !pkKT )
      return 0;

   if( TryToTranslateChar( wVirtKey,
                           ModBits( pkKT, lpKeyState ),
                           &bDead,
                           &bLigature,
                           &wcTranslatedChar,
                           pkKT ) )
   {
      if( bLigature )
      {
         DPRINT("Not handling ligature (yet)\n" );
         return 0;
      }

      if( cchBuff > 0 )
         pwszBuff[0] = wcTranslatedChar;

      return bDead ? -1 : 1;
   }

   return 0;
}


DWORD FASTCALL UserGetKeyState(DWORD key)
{
   DWORD ret = 0;

   if( key < 0x100 )
   {
      ret = ((DWORD)(gQueueKeyStateTable[key] & KS_DOWN_BIT) << 8 ) |
            (gQueueKeyStateTable[key] & KS_LOCK_BIT);
   }

   return ret;
}


DWORD
STDCALL
NtUserGetKeyState(
   DWORD key)
{
   DECLARE_RETURN(DWORD);

   DPRINT("Enter NtUserGetKeyState\n");
   UserEnterExclusive();

   RETURN(UserGetKeyState(key));

CLEANUP:
   DPRINT("Leave NtUserGetKeyState, ret=%i\n",_ret_);
   UserLeave();
   END_CLEANUP;
}



DWORD FASTCALL UserGetAsyncKeyState(DWORD key)
{
   DWORD ret = 0;

   if( key < 0x100 )
   {
      ret = ((DWORD)(gQueueKeyStateTable[key] & KS_DOWN_BIT) << 8 ) |
            (gQueueKeyStateTable[key] & KS_LOCK_BIT);
   }

   return ret;
}



DWORD
STDCALL
NtUserGetAsyncKeyState(
   DWORD key)
{
   DECLARE_RETURN(DWORD);

   DPRINT("Enter NtUserGetAsyncKeyState\n");
   UserEnterExclusive();

   RETURN(UserGetAsyncKeyState(key));

CLEANUP:
   DPRINT("Leave NtUserGetAsyncKeyState, ret=%i\n",_ret_);
   UserLeave();
   END_CLEANUP;
}



int STDCALL ToUnicodeEx( UINT wVirtKey,
                         UINT wScanCode,
                         PBYTE lpKeyState,
                         LPWSTR pwszBuff,
                         int cchBuff,
                         UINT wFlags,
                         HKL dwhkl )
{
   int ToUnicodeResult = 0;

   if (0 == (lpKeyState[wVirtKey] & KS_DOWN_BIT))
   {
      ToUnicodeResult = 0;
   }
   else
   {
      ToUnicodeResult = ToUnicodeInner( wVirtKey,
                                        wScanCode,
                                        lpKeyState,
                                        pwszBuff,
                                        cchBuff,
                                        wFlags,
                                        PsGetCurrentThreadWin32Thread() ?
                                        PsGetCurrentThreadWin32Thread()->KeyboardLayout->KBTables : 0 );
   }

   return ToUnicodeResult;
}

int STDCALL ToUnicode( UINT wVirtKey,
                       UINT wScanCode,
                       PBYTE lpKeyState,
                       LPWSTR pwszBuff,
                       int cchBuff,
                       UINT wFlags )
{
   return ToUnicodeEx( wVirtKey,
                       wScanCode,
                       gQueueKeyStateTable,
                       pwszBuff,
                       cchBuff,
                       wFlags,
                       0 );
}


BOOL FASTCALL
IntTranslateKbdMessage(LPMSG lpMsg,
                       HKL dwhkl)
{
   static INT dead_char = 0;
   LONG UState = 0;
   WCHAR wp[2] = { 0 };
   MSG NewMsg = { 0 };
   PKBDTABLES keyLayout;
   BOOL Result = FALSE;
   DWORD ScanCode = 0;


   keyLayout = PsGetCurrentThreadWin32Thread()->KeyboardLayout->KBTables;
   if( !keyLayout )
      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);

   UState = ToUnicodeInner(lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff,
                           gQueueKeyStateTable, wp, 2, 0,
                           keyLayout );

   if (UState == 1)
   {
      NewMsg.message = (lpMsg->message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
      if (dead_char)
      {
         ULONG i;
         WCHAR first, second;
         DPRINT("PREVIOUS DEAD CHAR: %c\n", dead_char);

         for( i = 0; keyLayout->pDeadKey[i].dwBoth; i++ )
         {
            first = keyLayout->pDeadKey[i].dwBoth >> 16;
            second = keyLayout->pDeadKey[i].dwBoth;
            if (first == dead_char && second == wp[0])
            {
               wp[0] = keyLayout->pDeadKey[i].wchComposed;
               dead_char = 0;
               break;
            }
         }

         DPRINT("FINAL CHAR: %c\n", wp[0]);
      }

      if (dead_char)
      {
         NewMsg.hwnd = lpMsg->hwnd;
         NewMsg.wParam = dead_char;
         NewMsg.lParam = lpMsg->lParam;
         dead_char = 0;
         MsqPostMessage(PsGetCurrentThreadWin32Thread()->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);
      Result = TRUE;
   }
   else if (UState == -1)
   {
      NewMsg.message =
         (lpMsg->message == WM_KEYDOWN) ? WM_DEADCHAR : WM_SYSDEADCHAR;
      NewMsg.hwnd = lpMsg->hwnd;
      NewMsg.wParam = wp[0];
      NewMsg.lParam = lpMsg->lParam;
      dead_char = wp[0];
      MsqPostMessage(PsGetCurrentThreadWin32Thread()->MessageQueue, &NewMsg, FALSE, QS_KEY);
      Result = TRUE;
   }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -