input.c
字号:
struct _ETHREAD *FocusThread;
extern NTSTATUS Win32kInitWin32Thread(PETHREAD Thread);
PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans = NULL;
UINT ModifierState = 0;
USHORT LastMakeCode = 0;
USHORT LastFlags = 0;
UINT RepeatCount = 0;
InitializeObjectAttributes(&KeyboardObjectAttributes,
&KeyboardDeviceName,
0,
NULL,
NULL);
do
{
LARGE_INTEGER DueTime;
KEVENT Event;
DueTime.QuadPart = (LONGLONG)(-10000000);
KeInitializeEvent(&Event, NotificationEvent, FALSE);
Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime);
Status = NtOpenFile(&KeyboardDeviceHandle,
FILE_ALL_ACCESS,
&KeyboardObjectAttributes,
&Iosb,
0,
FILE_SYNCHRONOUS_IO_ALERT);
} while (!NT_SUCCESS(Status));
/* Not sure if converting this thread to a win32 thread is such
a great idea. Since we're posting keyboard messages to the focus
window message queue, we'll be (indirectly) doing sendmessage
stuff from this thread (for WH_KEYBOARD_LL processing), which
means we need our own message queue. If keyboard messages were
instead queued to the system message queue, the thread removing
the message from the system message queue would be responsible
for WH_KEYBOARD_LL processing and we wouldn't need this thread
to be a win32 thread. */
Status = Win32kInitWin32Thread(PsGetCurrentThread());
if (!NT_SUCCESS(Status))
{
DPRINT1("Win32K: Failed making keyboard thread a win32 thread.\n");
return; //(Status);
}
KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
LOW_REALTIME_PRIORITY + 3);
IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle,
&IndicatorTrans);
for (;;)
{
/*
* Wait to start input.
*/
DPRINT( "Keyboard Input Thread Waiting for start event\n" );
Status = KeWaitForSingleObject(&InputThreadsStart,
0,
KernelMode,
TRUE,
NULL);
DPRINT( "Keyboard Input Thread Starting...\n" );
/*
* Receive and process keyboard input.
*/
while (InputThreadsRunning)
{
BOOLEAN NumKeys = 1;
KEYBOARD_INPUT_DATA KeyInput;
KEYBOARD_INPUT_DATA NextKeyInput;
LPARAM lParam = 0;
UINT fsModifiers, fsNextModifiers;
struct _ETHREAD *Thread;
HWND hWnd;
int id;
DPRINT("KeyInput @ %08x\n", &KeyInput);
Status = NtReadFile (KeyboardDeviceHandle,
NULL,
NULL,
NULL,
&Iosb,
&KeyInput,
sizeof(KEYBOARD_INPUT_DATA),
NULL,
NULL);
if(Status == STATUS_ALERTED && !InputThreadsRunning)
{
break;
}
if(Status == STATUS_PENDING)
{
NtWaitForSingleObject(KeyboardDeviceHandle, FALSE, NULL);
Status = Iosb.Status;
}
if(!NT_SUCCESS(Status))
{
DPRINT1("Win32K: Failed to read from mouse.\n");
return; //(Status);
}
DPRINT("KeyRaw: %s %04x\n",
(KeyInput.Flags & KEY_BREAK) ? "up" : "down",
KeyInput.MakeCode );
if (Status == STATUS_ALERTED && !InputThreadsRunning)
break;
if (!NT_SUCCESS(Status))
{
DPRINT1("Win32K: Failed to read from keyboard.\n");
return; //(Status);
}
/* Update modifier state */
fsModifiers = IntKeyboardGetModifiers(&KeyInput);
if (fsModifiers)
{
if (KeyInput.Flags & KEY_BREAK)
{
ModifierState &= ~fsModifiers;
}
else
{
ModifierState |= fsModifiers;
if (ModifierState == fsModifiers &&
(fsModifiers == MOD_ALT || fsModifiers == MOD_WIN))
{
/* First send out special notifications
* (For alt, the message that turns on accelerator
* display, not sure what for win. Both TODO though.)
*/
/* Read the next key before sending this one */
do
{
Status = NtReadFile (KeyboardDeviceHandle,
NULL,
NULL,
NULL,
&Iosb,
&NextKeyInput,
sizeof(KEYBOARD_INPUT_DATA),
NULL,
NULL);
DPRINT("KeyRaw: %s %04x\n",
(NextKeyInput.Flags & KEY_BREAK) ? "up":"down",
NextKeyInput.MakeCode );
if (Status == STATUS_ALERTED && !InputThreadsRunning)
goto KeyboardEscape;
}
while ((!(NextKeyInput.Flags & KEY_BREAK)) &&
NextKeyInput.MakeCode == KeyInput.MakeCode);
/* ^ Ignore repeats, they'll be KEY_MAKE and the same
* code. I'm not caring about the counting, not sure
* if that matters. I think not.
*/
/* If the ModifierState is now empty again, send a
* special notification and eat both keypresses
*/
fsNextModifiers = IntKeyboardGetModifiers(&NextKeyInput);
if (fsNextModifiers)
ModifierState ^= fsNextModifiers;
if (ModifierState == 0)
{
if (fsModifiers == MOD_WIN)
IntKeyboardSendWinKeyMsg();
else if (fsModifiers == MOD_ALT)
co_IntKeyboardSendAltKeyMsg();
continue;
}
NumKeys = 2;
}
}
}
for (;NumKeys;memcpy(&KeyInput, &NextKeyInput, sizeof(KeyInput)),
NumKeys--)
{
lParam = 0;
IntKeyboardUpdateLeds(KeyboardDeviceHandle,
&KeyInput,
IndicatorTrans);
/* While we are working, we set up lParam. The format is:
* 0-15: The number of times this key has autorepeated
* 16-23: The keyboard scancode
* 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
* Note that E1 is only used for PAUSE (E1-1D-45) and
* E0-45 happens not to be anything.
* 29: Alt is pressed ('Context code')
* 30: Previous state, if the key was down before this message
* This is a cheap way to ignore autorepeat keys
* 31: 1 if the key is being pressed
*/
/* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
* and it's the same key as the last one, increase the repeat
* count.
*/
if (!(KeyInput.Flags & KEY_BREAK))
{
if (((KeyInput.Flags & (KEY_E0 | KEY_E1)) == LastFlags) &&
(KeyInput.MakeCode == LastMakeCode))
{
RepeatCount++;
lParam |= (1 << 30);
}
else
{
RepeatCount = 0;
LastFlags = KeyInput.Flags & (KEY_E0 | KEY_E1);
LastMakeCode = KeyInput.MakeCode;
}
}
else
{
LastFlags = 0;
LastMakeCode = 0; /* Should never match */
lParam |= (1 << 30) | (1 << 31);
}
lParam |= RepeatCount;
lParam |= (KeyInput.MakeCode & 0xff) << 16;
if (KeyInput.Flags & KEY_E0)
lParam |= (1 << 24);
if (ModifierState & MOD_ALT)
{
lParam |= (1 << 29);
if (!(KeyInput.Flags & KEY_BREAK))
msg.message = WM_SYSKEYDOWN;
else
msg.message = WM_SYSKEYUP;
}
else
{
if (!(KeyInput.Flags & KEY_BREAK))
msg.message = WM_KEYDOWN;
else
msg.message = WM_KEYUP;
}
/* Find the target thread whose locale is in effect */
if (!IntGetScreenDC())
FocusQueue = W32kGetPrimitiveMessageQueue();
else
FocusQueue = IntGetFocusMessageQueue();
/* This might cause us to lose hot keys, which are important
* (ctrl-alt-del secure attention sequence). Not sure if it
* can happen though.
*/
if (!FocusQueue)
continue;
msg.lParam = lParam;
msg.hwnd = FocusQueue->FocusWindow;
FocusThread = FocusQueue->Thread;
if (!(FocusThread && FocusThread->Tcb.Win32Thread &&
((PW32THREAD)FocusThread->Tcb.Win32Thread)->KeyboardLayout))
continue;
/* This function uses lParam to fill wParam according to the
* keyboard layout in use.
*/
W32kKeyProcessMessage(&msg,
((PW32THREAD)FocusThread->Tcb.Win32Thread)->KeyboardLayout,
KeyInput.Flags & KEY_E0 ? 0xE0 :
(KeyInput.Flags & KEY_E1 ? 0xE1 : 0));
if (GetHotKey(ModifierState,
msg.wParam,
&Thread,
&hWnd,
&id))
{
if (!(KeyInput.Flags & KEY_BREAK))
{
DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd, id);
MsqPostHotKeyMessage (Thread,
hWnd,
(WPARAM)id,
MAKELPARAM((WORD)ModifierState,
(WORD)msg.wParam));
}
continue; /* Eat key up motion too */
}
/*
* Post a keyboard message.
*/
co_MsqPostKeyboardMessage(msg.message,msg.wParam,msg.lParam);
}
}
KeyboardEscape:
DPRINT( "KeyboardInput Thread Stopped...\n" );
}
}
NTSTATUS FASTCALL
UserAcquireOrReleaseInputOwnership(BOOLEAN Release)
{
if (Release && InputThreadsRunning && !pmPrimitiveMessageQueue)
{
DPRINT( "Releasing input: PM = %08x\n", pmPrimitiveMessageQueue );
KeClearEvent(&InputThreadsStart);
InputThreadsRunning = FALSE;
NtAlertThread(KeyboardThreadHandle);
NtAlertThread(MouseThreadHandle);
}
else if (!Release && !InputThreadsRunning)
{
InputThreadsRunning = TRUE;
KeSetEvent(&InputThreadsStart, IO_NO_INCREMENT, FALSE);
}
return(STATUS_SUCCESS);
}
NTSTATUS STDCALL
NtUserAcquireOrReleaseInputOwnership(BOOLEAN Release)
{
DECLARE_RETURN(NTSTATUS);
DPRINT("Enter NtUserAcquireOrReleaseInputOwnership\n");
UserEnterExclusive();
RETURN(UserAcquireOrReleaseInputOwnership(Release));
CLEANUP:
DPRINT("Leave NtUserAcquireOrReleaseInputOwnership, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
NTSTATUS FASTCALL
InitInputImpl(VOID)
{
NTSTATUS Status;
KeInitializeEvent(&InputThreadsStart, NotificationEvent, FALSE);
Status = PsCreateSystemThread(&KeyboardThreadHandle,
THREAD_ALL_ACCESS,
NULL,
NULL,
&KeyboardThreadId,
KeyboardThreadMain,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Win32K: Failed to create keyboard thread.\n");
}
/* Initialize the default keyboard layout */
(VOID)W32kGetDefaultKeyLayout();
Status = PsCreateSystemThread(&MouseThreadHandle,
THREAD_ALL_ACCESS,
NULL,
NULL,
&MouseThreadId,
MouseThreadMain,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Win32K: Failed to create mouse thread.\n");
}
return STATUS_SUCCESS;
}
NTSTATUS FASTCALL
CleanupInputImp(VOID)
{
return(STATUS_SUCCESS);
}
BOOL
STDCALL
NtUserDragDetect(
HWND hWnd,
LONG x,
LONG y)
{
UNIMPLEMENTED
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -