📄 keyboard.c
字号:
/*
* 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 + -