- Create another branch for networking fixes
[reactos.git] / subsystems / win32 / win32k / ntuser / input.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Window classes
5 * FILE: subsys/win32k/ntuser/class.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISION HISTORY:
8 * 06-06-2001 CSH Created
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <w32k.h>
14 #include <ntddkbd.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19 extern BYTE gQueueKeyStateTable[];
20 extern NTSTATUS Win32kInitWin32Thread(PETHREAD Thread);
21
22 /* GLOBALS *******************************************************************/
23
24 PTHREADINFO ptiRawInput;
25 PKTIMER MasterTimer;
26 PATTACHINFO gpai = NULL;
27
28 static HANDLE MouseDeviceHandle;
29 static HANDLE MouseThreadHandle;
30 static CLIENT_ID MouseThreadId;
31 static HANDLE KeyboardThreadHandle;
32 static CLIENT_ID KeyboardThreadId;
33 static HANDLE KeyboardDeviceHandle;
34 static HANDLE RawInputThreadHandle;
35 static CLIENT_ID RawInputThreadId;
36 static KEVENT InputThreadsStart;
37 static BOOLEAN InputThreadsRunning = FALSE;
38 static BYTE TrackSysKey = 0; /* determine whether ALT key up will cause a WM_SYSKEYUP
39 or a WM_KEYUP message */
40
41 /* FUNCTIONS *****************************************************************/
42 DWORD IntLastInputTick(BOOL LastInputTickSetGet);
43
44 #define ClearMouseInput(mi) \
45 mi.dx = 0; \
46 mi.dy = 0; \
47 mi.mouseData = 0; \
48 mi.dwFlags = 0;
49
50 #define SendMouseEvent(mi) \
51 if(mi.dx != 0 || mi.dy != 0) \
52 mi.dwFlags |= MOUSEEVENTF_MOVE; \
53 if(mi.dwFlags) \
54 IntMouseInput(&mi); \
55 ClearMouseInput(mi);
56
57
58 DWORD IntLastInputTick(BOOL LastInputTickSetGet)
59 {
60 static DWORD LastInputTick = 0;
61 if (LastInputTickSetGet == TRUE)
62 {
63 LARGE_INTEGER TickCount;
64 KeQueryTickCount(&TickCount);
65 LastInputTick = TickCount.u.LowPart * (KeQueryTimeIncrement() / 10000);
66 }
67 return LastInputTick;
68 }
69
70 BOOL
71 APIENTRY
72 NtUserGetLastInputInfo(PLASTINPUTINFO plii)
73 {
74 BOOL ret = TRUE;
75
76 UserEnterShared();
77
78 _SEH2_TRY
79 {
80 if (ProbeForReadUint(&plii->cbSize) != sizeof(LASTINPUTINFO))
81 {
82 SetLastWin32Error(ERROR_INVALID_PARAMETER);
83 ret = FALSE;
84 _SEH2_LEAVE;
85 }
86
87 ProbeForWrite(plii, sizeof(LASTINPUTINFO), sizeof(DWORD));
88
89 plii->dwTime = IntLastInputTick(FALSE);
90 }
91 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
92 {
93 SetLastNtError(_SEH2_GetExceptionCode());
94 ret = FALSE;
95 }
96 _SEH2_END;
97
98 UserLeave();
99
100 return ret;
101 }
102
103
104 VOID FASTCALL
105 ProcessMouseInputData(PMOUSE_INPUT_DATA Data, ULONG InputCount)
106 {
107 PMOUSE_INPUT_DATA mid;
108 MOUSEINPUT mi;
109 ULONG i;
110
111 ClearMouseInput(mi);
112 mi.time = 0;
113 mi.dwExtraInfo = 0;
114 for(i = 0; i < InputCount; i++)
115 {
116 mid = (Data + i);
117 mi.dx += mid->LastX;
118 mi.dy += mid->LastY;
119
120 /* Check if the mouse move is absolute */
121 if (mid->Flags == MOUSE_MOVE_ABSOLUTE)
122 {
123 /* Set flag and convert to screen location */
124 mi.dwFlags |= MOUSEEVENTF_ABSOLUTE;
125 mi.dx = mi.dx / (65535 / (UserGetSystemMetrics(SM_CXVIRTUALSCREEN) - 1));
126 mi.dy = mi.dy / (65535 / (UserGetSystemMetrics(SM_CYVIRTUALSCREEN) - 1));
127 }
128
129 if(mid->ButtonFlags)
130 {
131 if(mid->ButtonFlags & MOUSE_LEFT_BUTTON_DOWN)
132 {
133 mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
134 SendMouseEvent(mi);
135 }
136 if(mid->ButtonFlags & MOUSE_LEFT_BUTTON_UP)
137 {
138 mi.dwFlags |= MOUSEEVENTF_LEFTUP;
139 SendMouseEvent(mi);
140 }
141 if(mid->ButtonFlags & MOUSE_MIDDLE_BUTTON_DOWN)
142 {
143 mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
144 SendMouseEvent(mi);
145 }
146 if(mid->ButtonFlags & MOUSE_MIDDLE_BUTTON_UP)
147 {
148 mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
149 SendMouseEvent(mi);
150 }
151 if(mid->ButtonFlags & MOUSE_RIGHT_BUTTON_DOWN)
152 {
153 mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
154 SendMouseEvent(mi);
155 }
156 if(mid->ButtonFlags & MOUSE_RIGHT_BUTTON_UP)
157 {
158 mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
159 SendMouseEvent(mi);
160 }
161 if(mid->ButtonFlags & MOUSE_BUTTON_4_DOWN)
162 {
163 mi.mouseData |= XBUTTON1;
164 mi.dwFlags |= MOUSEEVENTF_XDOWN;
165 SendMouseEvent(mi);
166 }
167 if(mid->ButtonFlags & MOUSE_BUTTON_4_UP)
168 {
169 mi.mouseData |= XBUTTON1;
170 mi.dwFlags |= MOUSEEVENTF_XUP;
171 SendMouseEvent(mi);
172 }
173 if(mid->ButtonFlags & MOUSE_BUTTON_5_DOWN)
174 {
175 mi.mouseData |= XBUTTON2;
176 mi.dwFlags |= MOUSEEVENTF_XDOWN;
177 SendMouseEvent(mi);
178 }
179 if(mid->ButtonFlags & MOUSE_BUTTON_5_UP)
180 {
181 mi.mouseData |= XBUTTON2;
182 mi.dwFlags |= MOUSEEVENTF_XUP;
183 SendMouseEvent(mi);
184 }
185 if(mid->ButtonFlags & MOUSE_WHEEL)
186 {
187 mi.mouseData = mid->ButtonData;
188 mi.dwFlags |= MOUSEEVENTF_WHEEL;
189 SendMouseEvent(mi);
190 }
191 }
192 }
193
194 SendMouseEvent(mi);
195 }
196
197
198
199
200 VOID APIENTRY
201 MouseThreadMain(PVOID StartContext)
202 {
203 UNICODE_STRING MouseDeviceName = RTL_CONSTANT_STRING(L"\\Device\\PointerClass0");
204 OBJECT_ATTRIBUTES MouseObjectAttributes;
205 IO_STATUS_BLOCK Iosb;
206 NTSTATUS Status;
207 MOUSE_ATTRIBUTES MouseAttr;
208
209 InitializeObjectAttributes(&MouseObjectAttributes,
210 &MouseDeviceName,
211 0,
212 NULL,
213 NULL);
214 do
215 {
216 LARGE_INTEGER DueTime;
217 KEVENT Event;
218 DueTime.QuadPart = (LONGLONG)(-10000000);
219 KeInitializeEvent(&Event, NotificationEvent, FALSE);
220 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime);
221 Status = NtOpenFile(&MouseDeviceHandle,
222 FILE_ALL_ACCESS,
223 &MouseObjectAttributes,
224 &Iosb,
225 0,
226 FILE_SYNCHRONOUS_IO_ALERT);
227 } while (!NT_SUCCESS(Status));
228
229 KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
230 LOW_REALTIME_PRIORITY + 3);
231
232 for(;;)
233 {
234 /*
235 * Wait to start input.
236 */
237 DPRINT("Mouse Input Thread Waiting for start event\n");
238 Status = KeWaitForSingleObject(&InputThreadsStart,
239 0,
240 KernelMode,
241 TRUE,
242 NULL);
243 DPRINT("Mouse Input Thread Starting...\n");
244
245 /*FIXME: Does mouse attributes need to be used for anything */
246 Status = NtDeviceIoControlFile(MouseDeviceHandle,
247 NULL,
248 NULL,
249 NULL,
250 &Iosb,
251 IOCTL_MOUSE_QUERY_ATTRIBUTES,
252 &MouseAttr, sizeof(MOUSE_ATTRIBUTES),
253 NULL, 0);
254 if(!NT_SUCCESS(Status))
255 {
256 DPRINT("Failed to get mouse attributes\n");
257 }
258
259 /*
260 * Receive and process mouse input.
261 */
262 while(InputThreadsRunning)
263 {
264 MOUSE_INPUT_DATA MouseInput;
265 Status = NtReadFile(MouseDeviceHandle,
266 NULL,
267 NULL,
268 NULL,
269 &Iosb,
270 &MouseInput,
271 sizeof(MOUSE_INPUT_DATA),
272 NULL,
273 NULL);
274 if(Status == STATUS_ALERTED && !InputThreadsRunning)
275 {
276 break;
277 }
278 if(Status == STATUS_PENDING)
279 {
280 NtWaitForSingleObject(MouseDeviceHandle, FALSE, NULL);
281 Status = Iosb.Status;
282 }
283 if(!NT_SUCCESS(Status))
284 {
285 DPRINT1("Win32K: Failed to read from mouse.\n");
286 return; //(Status);
287 }
288 DPRINT("MouseEvent\n");
289 IntLastInputTick(TRUE);
290
291 UserEnterExclusive();
292
293 ProcessMouseInputData(&MouseInput, Iosb.Information / sizeof(MOUSE_INPUT_DATA));
294
295 UserLeave();
296 }
297 DPRINT("Mouse Input Thread Stopped...\n");
298 }
299 }
300
301 /* Returns a value that indicates if the key is a modifier key, and
302 * which one.
303 */
304 static UINT APIENTRY
305 IntKeyboardGetModifiers(KEYBOARD_INPUT_DATA *InputData)
306 {
307 if (InputData->Flags & KEY_E1)
308 return 0;
309
310 if (!(InputData->Flags & KEY_E0))
311 {
312 switch (InputData->MakeCode)
313 {
314 case 0x2a: /* left shift */
315 case 0x36: /* right shift */
316 return MOD_SHIFT;
317
318 case 0x1d: /* left control */
319 return MOD_CONTROL;
320
321 case 0x38: /* left alt */
322 return MOD_ALT;
323
324 default:
325 return 0;
326 }
327 }
328 else
329 {
330 switch (InputData->MakeCode)
331 {
332 case 0x1d: /* right control */
333 return MOD_CONTROL;
334
335 case 0x38: /* right alt */
336 return MOD_ALT;
337
338 case 0x5b: /* left gui (windows) */
339 case 0x5c: /* right gui (windows) */
340 return MOD_WIN;
341
342 default:
343 return 0;
344 }
345 }
346 }
347
348 /* Asks the keyboard driver to send a small table that shows which
349 * lights should connect with which scancodes
350 */
351 static NTSTATUS APIENTRY
352 IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle,
353 PKEYBOARD_INDICATOR_TRANSLATION *IndicatorTrans)
354 {
355 NTSTATUS Status;
356 DWORD Size = 0;
357 IO_STATUS_BLOCK Block;
358 PKEYBOARD_INDICATOR_TRANSLATION Ret;
359
360 Size = sizeof(KEYBOARD_INDICATOR_TRANSLATION);
361
362 Ret = ExAllocatePoolWithTag(PagedPool,
363 Size,
364 TAG_KEYBOARD);
365
366 while (Ret)
367 {
368 Status = NtDeviceIoControlFile(KeyboardDeviceHandle,
369 NULL,
370 NULL,
371 NULL,
372 &Block,
373 IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION,
374 NULL, 0,
375 Ret, Size);
376
377 if (Status != STATUS_BUFFER_TOO_SMALL)
378 break;
379
380 ExFreePoolWithTag(Ret, TAG_KEYBOARD);
381
382 Size += sizeof(KEYBOARD_INDICATOR_TRANSLATION);
383
384 Ret = ExAllocatePoolWithTag(PagedPool,
385 Size,
386 TAG_KEYBOARD);
387 }
388
389 if (!Ret)
390 return STATUS_INSUFFICIENT_RESOURCES;
391
392 if (Status != STATUS_SUCCESS)
393 {
394 ExFreePoolWithTag(Ret, TAG_KEYBOARD);
395 return Status;
396 }
397
398 *IndicatorTrans = Ret;
399 return Status;
400 }
401
402 /* Sends the keyboard commands to turn on/off the lights.
403 */
404 static NTSTATUS APIENTRY
405 IntKeyboardUpdateLeds(HANDLE KeyboardDeviceHandle,
406 PKEYBOARD_INPUT_DATA KeyInput,
407 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans)
408 {
409 NTSTATUS Status;
410 UINT Count;
411 static KEYBOARD_INDICATOR_PARAMETERS Indicators;
412 IO_STATUS_BLOCK Block;
413
414 if (!IndicatorTrans)
415 return STATUS_NOT_SUPPORTED;
416
417 if (KeyInput->Flags & (KEY_E0 | KEY_E1 | KEY_BREAK))
418 return STATUS_SUCCESS;
419
420 for (Count = 0; Count < IndicatorTrans->NumberOfIndicatorKeys; Count++)
421 {
422 if (KeyInput->MakeCode == IndicatorTrans->IndicatorList[Count].MakeCode)
423 {
424 Indicators.LedFlags ^=
425 IndicatorTrans->IndicatorList[Count].IndicatorFlags;
426
427 /* Update the lights on the hardware */
428
429 Status = NtDeviceIoControlFile(KeyboardDeviceHandle,
430 NULL,
431 NULL,
432 NULL,
433 &Block,
434 IOCTL_KEYBOARD_SET_INDICATORS,
435 &Indicators, sizeof(Indicators),
436 NULL, 0);
437
438 return Status;
439 }
440 }
441
442 return STATUS_SUCCESS;
443 }
444
445 static VOID APIENTRY
446 IntKeyboardSendWinKeyMsg()
447 {
448 PWINDOW_OBJECT Window;
449 MSG Mesg;
450
451 if (!(Window = UserGetWindowObject(InputWindowStation->ShellWindow)))
452 {
453 DPRINT1("Couldn't find window to send Windows key message!\n");
454 return;
455 }
456
457 Mesg.hwnd = InputWindowStation->ShellWindow;
458 Mesg.message = WM_SYSCOMMAND;
459 Mesg.wParam = SC_TASKLIST;
460 Mesg.lParam = 0;
461
462 /* The QS_HOTKEY is just a guess */
463 MsqPostMessage(Window->MessageQueue, &Mesg, FALSE, QS_HOTKEY);
464 }
465
466 static VOID APIENTRY
467 co_IntKeyboardSendAltKeyMsg()
468 {
469 co_MsqPostKeyboardMessage(WM_SYSCOMMAND,SC_KEYMENU,0);
470 }
471
472 static VOID APIENTRY
473 KeyboardThreadMain(PVOID StartContext)
474 {
475 UNICODE_STRING KeyboardDeviceName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardClass0");
476 OBJECT_ATTRIBUTES KeyboardObjectAttributes;
477 IO_STATUS_BLOCK Iosb;
478 NTSTATUS Status;
479 MSG msg;
480 PUSER_MESSAGE_QUEUE FocusQueue;
481 struct _ETHREAD *FocusThread;
482
483 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans = NULL;
484 UINT ModifierState = 0;
485 USHORT LastMakeCode = 0;
486 USHORT LastFlags = 0;
487 UINT RepeatCount = 0;
488
489 InitializeObjectAttributes(&KeyboardObjectAttributes,
490 &KeyboardDeviceName,
491 0,
492 NULL,
493 NULL);
494 do
495 {
496 LARGE_INTEGER DueTime;
497 KEVENT Event;
498 DueTime.QuadPart = (LONGLONG)(-10000000);
499 KeInitializeEvent(&Event, NotificationEvent, FALSE);
500 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime);
501 Status = NtOpenFile(&KeyboardDeviceHandle,
502 FILE_ALL_ACCESS,
503 &KeyboardObjectAttributes,
504 &Iosb,
505 0,
506 FILE_SYNCHRONOUS_IO_ALERT);
507 } while (!NT_SUCCESS(Status));
508
509 /* Not sure if converting this thread to a win32 thread is such
510 a great idea. Since we're posting keyboard messages to the focus
511 window message queue, we'll be (indirectly) doing sendmessage
512 stuff from this thread (for WH_KEYBOARD_LL processing), which
513 means we need our own message queue. If keyboard messages were
514 instead queued to the system message queue, the thread removing
515 the message from the system message queue would be responsible
516 for WH_KEYBOARD_LL processing and we wouldn't need this thread
517 to be a win32 thread. */
518 Status = Win32kInitWin32Thread(PsGetCurrentThread());
519 if (!NT_SUCCESS(Status))
520 {
521 DPRINT1("Win32K: Failed making keyboard thread a win32 thread.\n");
522 return; //(Status);
523 }
524
525 KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
526 LOW_REALTIME_PRIORITY + 3);
527
528 IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle,
529 &IndicatorTrans);
530
531 for (;;)
532 {
533 /*
534 * Wait to start input.
535 */
536 DPRINT( "Keyboard Input Thread Waiting for start event\n" );
537 Status = KeWaitForSingleObject(&InputThreadsStart,
538 0,
539 KernelMode,
540 TRUE,
541 NULL);
542
543 DPRINT( "Keyboard Input Thread Starting...\n" );
544 /*
545 * Receive and process keyboard input.
546 */
547 while (InputThreadsRunning)
548 {
549 BOOLEAN NumKeys = 1;
550 BOOLEAN bLeftAlt;
551 KEYBOARD_INPUT_DATA KeyInput;
552 KEYBOARD_INPUT_DATA NextKeyInput;
553 LPARAM lParam = 0;
554 UINT fsModifiers, fsNextModifiers;
555 struct _ETHREAD *Thread;
556 HWND hWnd;
557 int id;
558
559 DPRINT("KeyInput @ %08x\n", &KeyInput);
560
561 Status = NtReadFile (KeyboardDeviceHandle,
562 NULL,
563 NULL,
564 NULL,
565 &Iosb,
566 &KeyInput,
567 sizeof(KEYBOARD_INPUT_DATA),
568 NULL,
569 NULL);
570
571 if(Status == STATUS_ALERTED && !InputThreadsRunning)
572 {
573 break;
574 }
575 if(Status == STATUS_PENDING)
576 {
577 NtWaitForSingleObject(KeyboardDeviceHandle, FALSE, NULL);
578 Status = Iosb.Status;
579 }
580 if(!NT_SUCCESS(Status))
581 {
582 DPRINT1("Win32K: Failed to read from mouse.\n");
583 return; //(Status);
584 }
585
586 DPRINT("KeyRaw: %s %04x\n",
587 (KeyInput.Flags & KEY_BREAK) ? "up" : "down",
588 KeyInput.MakeCode );
589
590 if (Status == STATUS_ALERTED && !InputThreadsRunning)
591 break;
592
593 if (!NT_SUCCESS(Status))
594 {
595 DPRINT1("Win32K: Failed to read from keyboard.\n");
596 return; //(Status);
597 }
598
599 /* Set LastInputTick */
600 IntLastInputTick(TRUE);
601
602 /* Update modifier state */
603 fsModifiers = IntKeyboardGetModifiers(&KeyInput);
604
605 if (fsModifiers)
606 {
607 if (KeyInput.Flags & KEY_BREAK)
608 {
609 ModifierState &= ~fsModifiers;
610 if(fsModifiers == MOD_ALT)
611 {
612 if(KeyInput.Flags & KEY_E0)
613 {
614 gQueueKeyStateTable[VK_RMENU] = 0;
615 }
616 else
617 {
618 gQueueKeyStateTable[VK_LMENU] = 0;
619 }
620 if (gQueueKeyStateTable[VK_RMENU] == 0 &&
621 gQueueKeyStateTable[VK_LMENU] == 0)
622 {
623 gQueueKeyStateTable[VK_MENU] = 0;
624 }
625 }
626 }
627 else
628 {
629 ModifierState |= fsModifiers;
630
631 if (ModifierState == fsModifiers &&
632 (fsModifiers == MOD_ALT || fsModifiers == MOD_WIN))
633 {
634 /* First send out special notifications
635 * (For alt, the message that turns on accelerator
636 * display, not sure what for win. Both TODO though.)
637 */
638 bLeftAlt = FALSE;
639 if(fsModifiers == MOD_ALT)
640 {
641 if(KeyInput.Flags & KEY_E0)
642 {
643 gQueueKeyStateTable[VK_RMENU] = 0x80;
644 }
645 else
646 {
647 gQueueKeyStateTable[VK_LMENU] = 0x80;
648 bLeftAlt = TRUE;
649 }
650
651 gQueueKeyStateTable[VK_MENU] = 0x80;
652 }
653
654 /* Read the next key before sending this one */
655 do
656 {
657 Status = NtReadFile (KeyboardDeviceHandle,
658 NULL,
659 NULL,
660 NULL,
661 &Iosb,
662 &NextKeyInput,
663 sizeof(KEYBOARD_INPUT_DATA),
664 NULL,
665 NULL);
666 DPRINT("KeyRaw: %s %04x\n",
667 (NextKeyInput.Flags & KEY_BREAK) ? "up":"down",
668 NextKeyInput.MakeCode );
669
670 if (Status == STATUS_ALERTED && !InputThreadsRunning)
671 goto KeyboardEscape;
672
673 }
674 while ((!(NextKeyInput.Flags & KEY_BREAK)) &&
675 NextKeyInput.MakeCode == KeyInput.MakeCode);
676 /* ^ Ignore repeats, they'll be KEY_MAKE and the same
677 * code. I'm not caring about the counting, not sure
678 * if that matters. I think not.
679 */
680
681 /* If the ModifierState is now empty again, send a
682 * special notification and eat both keypresses
683 */
684
685 fsNextModifiers = IntKeyboardGetModifiers(&NextKeyInput);
686
687 if (fsNextModifiers)
688 ModifierState ^= fsNextModifiers;
689
690 if (ModifierState == 0)
691 {
692 if (fsModifiers == MOD_WIN)
693 IntKeyboardSendWinKeyMsg();
694 else if (fsModifiers == MOD_ALT)
695 {
696 gQueueKeyStateTable[VK_MENU] = 0;
697 if(bLeftAlt)
698 {
699 gQueueKeyStateTable[VK_LMENU] = 0;
700 }
701 else
702 {
703 gQueueKeyStateTable[VK_RMENU] = 0;
704 }
705 co_IntKeyboardSendAltKeyMsg();
706 }
707 continue;
708 }
709
710 NumKeys = 2;
711 }
712 }
713 }
714
715 for (;NumKeys;memcpy(&KeyInput, &NextKeyInput, sizeof(KeyInput)),
716 NumKeys--)
717 {
718 lParam = 0;
719
720 IntKeyboardUpdateLeds(KeyboardDeviceHandle,
721 &KeyInput,
722 IndicatorTrans);
723
724 /* While we are working, we set up lParam. The format is:
725 * 0-15: The number of times this key has autorepeated
726 * 16-23: The keyboard scancode
727 * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
728 * Note that E1 is only used for PAUSE (E1-1D-45) and
729 * E0-45 happens not to be anything.
730 * 29: Alt is pressed ('Context code')
731 * 30: Previous state, if the key was down before this message
732 * This is a cheap way to ignore autorepeat keys
733 * 31: 1 if the key is being pressed
734 */
735
736 /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
737 * and it's the same key as the last one, increase the repeat
738 * count.
739 */
740
741 if (!(KeyInput.Flags & KEY_BREAK))
742 {
743 if (((KeyInput.Flags & (KEY_E0 | KEY_E1)) == LastFlags) &&
744 (KeyInput.MakeCode == LastMakeCode))
745 {
746 RepeatCount++;
747 lParam |= (1 << 30);
748 }
749 else
750 {
751 RepeatCount = 1;
752 LastFlags = KeyInput.Flags & (KEY_E0 | KEY_E1);
753 LastMakeCode = KeyInput.MakeCode;
754 }
755 }
756 else
757 {
758 LastFlags = 0;
759 LastMakeCode = 0; /* Should never match */
760 lParam |= (1 << 30) | (1 << 31);
761 }
762
763 lParam |= RepeatCount;
764
765 lParam |= (KeyInput.MakeCode & 0xff) << 16;
766
767 if (KeyInput.Flags & KEY_E0)
768 lParam |= (1 << 24);
769
770 if (ModifierState & MOD_ALT)
771 {
772 lParam |= (1 << 29);
773
774 if (!(KeyInput.Flags & KEY_BREAK))
775 msg.message = WM_SYSKEYDOWN;
776 else
777 msg.message = WM_SYSKEYUP;
778 }
779 else
780 {
781 if (!(KeyInput.Flags & KEY_BREAK))
782 msg.message = WM_KEYDOWN;
783 else
784 msg.message = WM_KEYUP;
785 }
786
787 /* Find the target thread whose locale is in effect */
788 FocusQueue = IntGetFocusMessageQueue();
789
790 /* This might cause us to lose hot keys, which are important
791 * (ctrl-alt-del secure attention sequence). Not sure if it
792 * can happen though.
793 */
794 if (!FocusQueue)
795 continue;
796
797 msg.lParam = lParam;
798 msg.hwnd = FocusQueue->FocusWindow;
799
800 FocusThread = FocusQueue->Thread;
801
802 if (!(FocusThread && FocusThread->Tcb.Win32Thread &&
803 ((PTHREADINFO)FocusThread->Tcb.Win32Thread)->KeyboardLayout))
804 continue;
805
806 /* This function uses lParam to fill wParam according to the
807 * keyboard layout in use.
808 */
809 W32kKeyProcessMessage(&msg,
810 ((PTHREADINFO)FocusThread->Tcb.Win32Thread)->KeyboardLayout->KBTables,
811 KeyInput.Flags & KEY_E0 ? 0xE0 :
812 (KeyInput.Flags & KEY_E1 ? 0xE1 : 0));
813
814 if (GetHotKey(ModifierState,
815 msg.wParam,
816 &Thread,
817 &hWnd,
818 &id))
819 {
820 if (!(KeyInput.Flags & KEY_BREAK))
821 {
822 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd, id);
823 MsqPostHotKeyMessage (Thread,
824 hWnd,
825 (WPARAM)id,
826 MAKELPARAM((WORD)ModifierState,
827 (WORD)msg.wParam));
828 }
829 continue; /* Eat key up motion too */
830 }
831
832 /*
833 * Post a keyboard message.
834 */
835 co_MsqPostKeyboardMessage(msg.message,msg.wParam,msg.lParam);
836 }
837 }
838
839 KeyboardEscape:
840 DPRINT( "KeyboardInput Thread Stopped...\n" );
841 }
842 }
843
844
845 static PVOID Objects[2];
846 /*
847 Raw Input Thread.
848 Since this relies on InputThreadsStart, just fake it.
849 */
850 static VOID APIENTRY
851 RawInputThreadMain(PVOID StartContext)
852 {
853 NTSTATUS Status;
854 LARGE_INTEGER DueTime;
855
856 DueTime.QuadPart = (LONGLONG)(-10000000);
857
858 do
859 {
860 KEVENT Event;
861 KeInitializeEvent(&Event, NotificationEvent, FALSE);
862 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime);
863 } while (!NT_SUCCESS(Status));
864
865
866 Objects[0] = &InputThreadsStart;
867
868 MasterTimer = ExAllocatePoolWithTag(NonPagedPool, sizeof(KTIMER), TAG_INPUT);
869 if (!MasterTimer)
870 {
871 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
872 return;
873 }
874 KeInitializeTimer(MasterTimer);
875 Objects[1] = MasterTimer;
876
877 // This thread requires win32k!
878 Status = Win32kInitWin32Thread(PsGetCurrentThread());
879 if (!NT_SUCCESS(Status))
880 {
881 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
882 return; //(Status);
883 }
884
885 ptiRawInput = PsGetCurrentThreadWin32Thread();
886 DPRINT("\nRaw Input Thread 0x%x \n", ptiRawInput);
887
888
889 KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
890 LOW_REALTIME_PRIORITY + 3);
891
892 UserEnterExclusive();
893 StartTheTimers();
894 UserLeave();
895
896 //
897 // ATM, we just have one job to handle, merge the other two later.
898 //
899 for(;;)
900 {
901 DPRINT( "Raw Input Thread Waiting for start event\n" );
902
903 Status = KeWaitForMultipleObjects( 2,
904 Objects,
905 WaitAll, //WaitAny,
906 WrUserRequest,
907 KernelMode,
908 TRUE,
909 NULL,
910 NULL);
911 DPRINT( "Raw Input Thread Starting...\n" );
912
913 ProcessTimers();
914 }
915 DPRINT1("Raw Input Thread Exit!\n");
916 }
917
918 NTSTATUS FASTCALL
919 InitInputImpl(VOID)
920 {
921 NTSTATUS Status;
922
923 KeInitializeEvent(&InputThreadsStart, NotificationEvent, FALSE);
924
925 /* Initialize the default keyboard layout */
926 if(!UserInitDefaultKeyboardLayout())
927 {
928 DPRINT1("Failed to initialize default keyboard layout!\n");
929 }
930
931 Status = PsCreateSystemThread(&RawInputThreadHandle,
932 THREAD_ALL_ACCESS,
933 NULL,
934 NULL,
935 &RawInputThreadId,
936 RawInputThreadMain,
937 NULL);
938 if (!NT_SUCCESS(Status))
939 {
940 DPRINT1("Win32K: Failed to create raw thread.\n");
941 }
942
943 Status = PsCreateSystemThread(&KeyboardThreadHandle,
944 THREAD_ALL_ACCESS,
945 NULL,
946 NULL,
947 &KeyboardThreadId,
948 KeyboardThreadMain,
949 NULL);
950 if (!NT_SUCCESS(Status))
951 {
952 DPRINT1("Win32K: Failed to create keyboard thread.\n");
953 }
954
955 Status = PsCreateSystemThread(&MouseThreadHandle,
956 THREAD_ALL_ACCESS,
957 NULL,
958 NULL,
959 &MouseThreadId,
960 MouseThreadMain,
961 NULL);
962 if (!NT_SUCCESS(Status))
963 {
964 DPRINT1("Win32K: Failed to create mouse thread.\n");
965 }
966
967 InputThreadsRunning = TRUE;
968 KeSetEvent(&InputThreadsStart, IO_NO_INCREMENT, FALSE);
969
970 return STATUS_SUCCESS;
971 }
972
973 NTSTATUS FASTCALL
974 CleanupInputImp(VOID)
975 {
976 return(STATUS_SUCCESS);
977 }
978
979 BOOL
980 APIENTRY
981 NtUserDragDetect(
982 HWND hWnd,
983 POINT pt) // Just like the User call.
984 {
985 UNIMPLEMENTED
986 return 0;
987 }
988
989 BOOL FASTCALL
990 IntBlockInput(PTHREADINFO W32Thread, BOOL BlockIt)
991 {
992 PTHREADINFO OldBlock;
993 ASSERT(W32Thread);
994
995 if(!W32Thread->Desktop || ((W32Thread->TIF_flags & TIF_INCLEANUP) && BlockIt))
996 {
997 /*
998 * fail blocking if exiting the thread
999 */
1000
1001 return FALSE;
1002 }
1003
1004 /*
1005 * FIXME - check access rights of the window station
1006 * e.g. services running in the service window station cannot block input
1007 */
1008 if(!ThreadHasInputAccess(W32Thread) ||
1009 !IntIsActiveDesktop(W32Thread->Desktop))
1010 {
1011 SetLastWin32Error(ERROR_ACCESS_DENIED);
1012 return FALSE;
1013 }
1014
1015 ASSERT(W32Thread->Desktop);
1016 OldBlock = W32Thread->Desktop->BlockInputThread;
1017 if(OldBlock)
1018 {
1019 if(OldBlock != W32Thread)
1020 {
1021 SetLastWin32Error(ERROR_ACCESS_DENIED);
1022 return FALSE;
1023 }
1024 W32Thread->Desktop->BlockInputThread = (BlockIt ? W32Thread : NULL);
1025 return OldBlock == NULL;
1026 }
1027
1028 W32Thread->Desktop->BlockInputThread = (BlockIt ? W32Thread : NULL);
1029 return OldBlock == NULL;
1030 }
1031
1032 BOOL
1033 APIENTRY
1034 NtUserBlockInput(
1035 BOOL BlockIt)
1036 {
1037 DECLARE_RETURN(BOOLEAN);
1038
1039 DPRINT("Enter NtUserBlockInput\n");
1040 UserEnterExclusive();
1041
1042 RETURN( IntBlockInput(PsGetCurrentThreadWin32Thread(), BlockIt));
1043
1044 CLEANUP:
1045 DPRINT("Leave NtUserBlockInput, ret=%i\n",_ret_);
1046 UserLeave();
1047 END_CLEANUP;
1048 }
1049
1050 BOOL FASTCALL
1051 IntMouseInput(MOUSEINPUT *mi)
1052 {
1053 const UINT SwapBtnMsg[2][2] =
1054 {
1055 {
1056 WM_LBUTTONDOWN, WM_RBUTTONDOWN
1057 },
1058 {WM_LBUTTONUP, WM_RBUTTONUP}
1059 };
1060 const WPARAM SwapBtn[2] =
1061 {
1062 MK_LBUTTON, MK_RBUTTON
1063 };
1064 POINT MousePos = {0}, OrgPos;
1065 PSYSTEM_CURSORINFO CurInfo;
1066 PWINSTATION_OBJECT WinSta;
1067 BOOL DoMove, SwapButtons;
1068 MSG Msg;
1069 SURFACE *psurf;
1070 SURFOBJ *pso;
1071 PDC dc;
1072 PWINDOW_OBJECT DesktopWindow;
1073
1074 #if 1
1075
1076 HDC hDC;
1077
1078 /* FIXME - get the screen dc from the window station or desktop */
1079 if(!(hDC = IntGetScreenDC()))
1080 {
1081 return FALSE;
1082 }
1083 #endif
1084
1085 ASSERT(mi);
1086 #if 0
1087
1088 WinSta = PsGetCurrentProcessWin32Process()->WindowStation;
1089 #else
1090 /* FIXME - ugly hack but as long as we're using this dumb callback from the
1091 mouse class driver, we can't access the window station from the calling
1092 process */
1093 WinSta = InputWindowStation;
1094 #endif
1095
1096 ASSERT(WinSta);
1097
1098 CurInfo = IntGetSysCursorInfo(WinSta);
1099
1100 if(!mi->time)
1101 {
1102 LARGE_INTEGER LargeTickCount;
1103 KeQueryTickCount(&LargeTickCount);
1104 mi->time = MsqCalculateMessageTime(&LargeTickCount);
1105 }
1106
1107 SwapButtons = gspv.bMouseBtnSwap;
1108 DoMove = FALSE;
1109
1110 IntGetCursorLocation(WinSta, &MousePos);
1111 OrgPos.x = MousePos.x;
1112 OrgPos.y = MousePos.y;
1113
1114 if(mi->dwFlags & MOUSEEVENTF_MOVE)
1115 {
1116 if(mi->dwFlags & MOUSEEVENTF_ABSOLUTE)
1117 {
1118 MousePos.x = mi->dx;
1119 MousePos.y = mi->dy;
1120 }
1121 else
1122 {
1123 MousePos.x += mi->dx;
1124 MousePos.y += mi->dy;
1125 }
1126
1127 DesktopWindow = IntGetWindowObject(WinSta->ActiveDesktop->DesktopWindow);
1128
1129 if (DesktopWindow)
1130 {
1131 if(MousePos.x >= DesktopWindow->Wnd->rcClient.right)
1132 MousePos.x = DesktopWindow->Wnd->rcClient.right - 1;
1133 if(MousePos.y >= DesktopWindow->Wnd->rcClient.bottom)
1134 MousePos.y = DesktopWindow->Wnd->rcClient.bottom - 1;
1135 UserDereferenceObject(DesktopWindow);
1136 }
1137
1138 if(MousePos.x < 0)
1139 MousePos.x = 0;
1140 if(MousePos.y < 0)
1141 MousePos.y = 0;
1142
1143 if(CurInfo->CursorClipInfo.IsClipped)
1144 {
1145 /* The mouse cursor needs to be clipped */
1146
1147 if(MousePos.x >= (LONG)CurInfo->CursorClipInfo.Right)
1148 MousePos.x = (LONG)CurInfo->CursorClipInfo.Right;
1149 if(MousePos.x < (LONG)CurInfo->CursorClipInfo.Left)
1150 MousePos.x = (LONG)CurInfo->CursorClipInfo.Left;
1151 if(MousePos.y >= (LONG)CurInfo->CursorClipInfo.Bottom)
1152 MousePos.y = (LONG)CurInfo->CursorClipInfo.Bottom;
1153 if(MousePos.y < (LONG)CurInfo->CursorClipInfo.Top)
1154 MousePos.y = (LONG)CurInfo->CursorClipInfo.Top;
1155 }
1156
1157 DoMove = (MousePos.x != OrgPos.x || MousePos.y != OrgPos.y);
1158 }
1159
1160 if (DoMove)
1161 {
1162 dc = DC_LockDc(hDC);
1163 if (dc)
1164 {
1165 psurf = dc->dclevel.pSurface;
1166 if (psurf)
1167 {
1168 pso = &psurf->SurfObj;
1169
1170 if (CurInfo->ShowingCursor)
1171 {
1172 IntEngMovePointer(pso, MousePos.x, MousePos.y, &(GDIDEV(pso)->Pointer.Exclude));
1173 }
1174 /* Only now, update the info in the PDEVOBJ, so EngMovePointer can
1175 * use the old values to move the pointer image */
1176 gpsi->ptCursor.x = MousePos.x;
1177 gpsi->ptCursor.y = MousePos.y;
1178 }
1179
1180 DC_UnlockDc(dc);
1181 }
1182 }
1183
1184 /*
1185 * Insert the messages into the system queue
1186 */
1187
1188 Msg.wParam = CurInfo->ButtonsDown;
1189 Msg.lParam = MAKELPARAM(MousePos.x, MousePos.y);
1190 Msg.pt = MousePos;
1191
1192 if (gQueueKeyStateTable[VK_SHIFT] & 0xc0)
1193 {
1194 Msg.wParam |= MK_SHIFT;
1195 }
1196
1197 if (gQueueKeyStateTable[VK_CONTROL] & 0xc0)
1198 {
1199 Msg.wParam |= MK_CONTROL;
1200 }
1201
1202 if(DoMove)
1203 {
1204 Msg.message = WM_MOUSEMOVE;
1205 MsqInsertSystemMessage(&Msg);
1206 }
1207
1208 Msg.message = 0;
1209 if(mi->dwFlags & MOUSEEVENTF_LEFTDOWN)
1210 {
1211 gQueueKeyStateTable[VK_LBUTTON] |= 0xc0;
1212 Msg.message = SwapBtnMsg[0][SwapButtons];
1213 CurInfo->ButtonsDown |= SwapBtn[SwapButtons];
1214 MsqInsertSystemMessage(&Msg);
1215 }
1216 else if(mi->dwFlags & MOUSEEVENTF_LEFTUP)
1217 {
1218 gQueueKeyStateTable[VK_LBUTTON] &= ~0x80;
1219 Msg.message = SwapBtnMsg[1][SwapButtons];
1220 CurInfo->ButtonsDown &= ~SwapBtn[SwapButtons];
1221 MsqInsertSystemMessage(&Msg);
1222 }
1223 if(mi->dwFlags & MOUSEEVENTF_MIDDLEDOWN)
1224 {
1225 gQueueKeyStateTable[VK_MBUTTON] |= 0xc0;
1226 Msg.message = WM_MBUTTONDOWN;
1227 CurInfo->ButtonsDown |= MK_MBUTTON;
1228 MsqInsertSystemMessage(&Msg);
1229 }
1230 else if(mi->dwFlags & MOUSEEVENTF_MIDDLEUP)
1231 {
1232 gQueueKeyStateTable[VK_MBUTTON] &= ~0x80;
1233 Msg.message = WM_MBUTTONUP;
1234 CurInfo->ButtonsDown &= ~MK_MBUTTON;
1235 MsqInsertSystemMessage(&Msg);
1236 }
1237 if(mi->dwFlags & MOUSEEVENTF_RIGHTDOWN)
1238 {
1239 gQueueKeyStateTable[VK_RBUTTON] |= 0xc0;
1240 Msg.message = SwapBtnMsg[0][!SwapButtons];
1241 CurInfo->ButtonsDown |= SwapBtn[!SwapButtons];
1242 MsqInsertSystemMessage(&Msg);
1243 }
1244 else if(mi->dwFlags & MOUSEEVENTF_RIGHTUP)
1245 {
1246 gQueueKeyStateTable[VK_RBUTTON] &= ~0x80;
1247 Msg.message = SwapBtnMsg[1][!SwapButtons];
1248 CurInfo->ButtonsDown &= ~SwapBtn[!SwapButtons];
1249 MsqInsertSystemMessage(&Msg);
1250 }
1251
1252 if((mi->dwFlags & (MOUSEEVENTF_XDOWN | MOUSEEVENTF_XUP)) &&
1253 (mi->dwFlags & MOUSEEVENTF_WHEEL))
1254 {
1255 /* fail because both types of events use the mouseData field */
1256 return FALSE;
1257 }
1258
1259 if(mi->dwFlags & MOUSEEVENTF_XDOWN)
1260 {
1261 Msg.message = WM_XBUTTONDOWN;
1262 if(mi->mouseData & XBUTTON1)
1263 {
1264 gQueueKeyStateTable[VK_XBUTTON1] |= 0xc0;
1265 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
1266 CurInfo->ButtonsDown |= XBUTTON1;
1267 MsqInsertSystemMessage(&Msg);
1268 }
1269 if(mi->mouseData & XBUTTON2)
1270 {
1271 gQueueKeyStateTable[VK_XBUTTON2] |= 0xc0;
1272 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
1273 CurInfo->ButtonsDown |= XBUTTON2;
1274 MsqInsertSystemMessage(&Msg);
1275 }
1276 }
1277 else if(mi->dwFlags & MOUSEEVENTF_XUP)
1278 {
1279 Msg.message = WM_XBUTTONUP;
1280 if(mi->mouseData & XBUTTON1)
1281 {
1282 gQueueKeyStateTable[VK_XBUTTON1] &= ~0x80;
1283 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
1284 CurInfo->ButtonsDown &= ~XBUTTON1;
1285 MsqInsertSystemMessage(&Msg);
1286 }
1287 if(mi->mouseData & XBUTTON2)
1288 {
1289 gQueueKeyStateTable[VK_XBUTTON2] &= ~0x80;
1290 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
1291 CurInfo->ButtonsDown &= ~XBUTTON2;
1292 MsqInsertSystemMessage(&Msg);
1293 }
1294 }
1295 if(mi->dwFlags & MOUSEEVENTF_WHEEL)
1296 {
1297 Msg.message = WM_MOUSEWHEEL;
1298 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, mi->mouseData);
1299 MsqInsertSystemMessage(&Msg);
1300 }
1301
1302 return TRUE;
1303 }
1304
1305 BOOL FASTCALL
1306 IntKeyboardInput(KEYBDINPUT *ki)
1307 {
1308 PUSER_MESSAGE_QUEUE FocusMessageQueue;
1309 PTHREADINFO pti;
1310 MSG Msg;
1311 LARGE_INTEGER LargeTickCount;
1312 KBDLLHOOKSTRUCT KbdHookData;
1313 WORD flags, wVkStripped, wVkL, wVkR, wVk = ki->wVk, vk_hook = ki->wVk;
1314 BOOLEAN Entered = FALSE;
1315
1316 Msg.lParam = 0;
1317
1318 // Condition may arise when calling MsqPostMessage and waiting for an event.
1319 if (!UserIsEntered())
1320 {
1321 // Fixme: Not sure ATM if this thread is locked.
1322 UserEnterExclusive();
1323 Entered = TRUE;
1324 }
1325
1326 wVk = LOBYTE(wVk);
1327 Msg.wParam = wVk;
1328 flags = LOBYTE(ki->wScan);
1329
1330 if (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) flags |= KF_EXTENDED;
1331 /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
1332
1333 /* strip left/right for menu, control, shift */
1334 switch (wVk)
1335 {
1336 case VK_MENU:
1337 case VK_LMENU:
1338 case VK_RMENU:
1339 wVk = (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) ? VK_RMENU : VK_LMENU;
1340 wVkStripped = VK_MENU;
1341 wVkL = VK_LMENU;
1342 wVkR = VK_RMENU;
1343 break;
1344 case VK_CONTROL:
1345 case VK_LCONTROL:
1346 case VK_RCONTROL:
1347 wVk = (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) ? VK_RCONTROL : VK_LCONTROL;
1348 wVkStripped = VK_CONTROL;
1349 wVkL = VK_LCONTROL;
1350 wVkR = VK_RCONTROL;
1351 break;
1352 case VK_SHIFT:
1353 case VK_LSHIFT:
1354 case VK_RSHIFT:
1355 wVk = (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) ? VK_RSHIFT : VK_LSHIFT;
1356 wVkStripped = VK_SHIFT;
1357 wVkL = VK_LSHIFT;
1358 wVkR = VK_RSHIFT;
1359 break;
1360 default:
1361 wVkStripped = wVkL = wVkR = wVk;
1362 }
1363
1364 if (ki->dwFlags & KEYEVENTF_KEYUP)
1365 {
1366 Msg.message = WM_KEYUP;
1367 if ((gQueueKeyStateTable[VK_MENU] & 0x80) &&
1368 ((wVkStripped == VK_MENU) || (wVkStripped == VK_CONTROL)
1369 || !(gQueueKeyStateTable[VK_CONTROL] & 0x80)))
1370 {
1371 if( TrackSysKey == VK_MENU || /* <ALT>-down/<ALT>-up sequence */
1372 (wVkStripped != VK_MENU)) /* <ALT>-down...<something else>-up */
1373 Msg.message = WM_SYSKEYUP;
1374 TrackSysKey = 0;
1375 }
1376 flags |= KF_REPEAT | KF_UP;
1377 }
1378 else
1379 {
1380 Msg.message = WM_KEYDOWN;
1381 if ((gQueueKeyStateTable[VK_MENU] & 0x80 || wVkStripped == VK_MENU) &&
1382 !(gQueueKeyStateTable[VK_CONTROL] & 0x80 || wVkStripped == VK_CONTROL))
1383 {
1384 Msg.message = WM_SYSKEYDOWN;
1385 TrackSysKey = wVkStripped;
1386 }
1387 if (!(ki->dwFlags & KEYEVENTF_UNICODE) && gQueueKeyStateTable[wVk] & 0x80) flags |= KF_REPEAT;
1388 }
1389
1390 if (ki->dwFlags & KEYEVENTF_UNICODE)
1391 {
1392 vk_hook = Msg.wParam = wVk = VK_PACKET;
1393 Msg.lParam = MAKELPARAM(1 /* repeat count */, ki->wScan);
1394 }
1395
1396 FocusMessageQueue = IntGetFocusMessageQueue();
1397
1398 Msg.hwnd = 0;
1399
1400 if (FocusMessageQueue && (FocusMessageQueue->FocusWindow != (HWND)0))
1401 Msg.hwnd = FocusMessageQueue->FocusWindow;
1402
1403 if (!ki->time)
1404 {
1405 KeQueryTickCount(&LargeTickCount);
1406 Msg.time = MsqCalculateMessageTime(&LargeTickCount);
1407 }
1408 else
1409 Msg.time = ki->time;
1410
1411 /* All messages have to contain the cursor point. */
1412 pti = PsGetCurrentThreadWin32Thread();
1413 IntGetCursorLocation(pti->Desktop->WindowStation,
1414 &Msg.pt);
1415
1416 DPRINT1("Kbd Hook msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1417 Msg.message, vk_hook, Msg.lParam);
1418
1419 KbdHookData.vkCode = vk_hook;
1420 KbdHookData.scanCode = ki->wScan;
1421 KbdHookData.flags = flags >> 8;
1422 KbdHookData.time = Msg.time;
1423 KbdHookData.dwExtraInfo = ki->dwExtraInfo;
1424 if (co_HOOK_CallHooks(WH_KEYBOARD_LL, HC_ACTION, Msg.message, (LPARAM) &KbdHookData))
1425 {
1426 DPRINT("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1427 Msg.message, vk_hook, Msg.lParam);
1428 if (Entered) UserLeave();
1429 return FALSE;
1430 }
1431
1432 if (!(ki->dwFlags & KEYEVENTF_UNICODE))
1433 {
1434 if (ki->dwFlags & KEYEVENTF_KEYUP)
1435 {
1436 gQueueKeyStateTable[wVk] &= ~0x80;
1437 gQueueKeyStateTable[wVkStripped] = gQueueKeyStateTable[wVkL] | gQueueKeyStateTable[wVkR];
1438 }
1439 else
1440 {
1441 if (!(gQueueKeyStateTable[wVk] & 0x80)) gQueueKeyStateTable[wVk] ^= 0x01;
1442 gQueueKeyStateTable[wVk] |= 0xc0;
1443 gQueueKeyStateTable[wVkStripped] = gQueueKeyStateTable[wVkL] | gQueueKeyStateTable[wVkR];
1444 }
1445
1446 if (gQueueKeyStateTable[VK_MENU] & 0x80) flags |= KF_ALTDOWN;
1447
1448 if (wVkStripped == VK_SHIFT) flags &= ~KF_EXTENDED;
1449
1450 Msg.lParam = MAKELPARAM(1 /* repeat count */, flags);
1451 }
1452
1453 if (FocusMessageQueue == NULL)
1454 {
1455 DPRINT("No focus message queue\n");
1456 if (Entered) UserLeave();
1457 return FALSE;
1458 }
1459
1460 if (FocusMessageQueue->FocusWindow != (HWND)0)
1461 {
1462 Msg.hwnd = FocusMessageQueue->FocusWindow;
1463 DPRINT("Msg.hwnd = %x\n", Msg.hwnd);
1464
1465 FocusMessageQueue->Desktop->DesktopInfo->LastInputWasKbd = TRUE;
1466
1467 IntGetCursorLocation(FocusMessageQueue->Desktop->WindowStation,
1468 &Msg.pt);
1469 MsqPostMessage(FocusMessageQueue, &Msg, FALSE, QS_KEY);
1470 }
1471 else
1472 {
1473 DPRINT("Invalid focus window handle\n");
1474 }
1475
1476 if (Entered) UserLeave();
1477
1478 return TRUE;
1479 }
1480
1481 BOOL FASTCALL
1482 UserAttachThreadInput( PTHREADINFO pti, PTHREADINFO ptiTo, BOOL fAttach)
1483 {
1484 PATTACHINFO pai;
1485
1486 /* Can not be the same thread.*/
1487 if (pti == ptiTo) return FALSE;
1488
1489 /* Do not attach to system threads or between different desktops. */
1490 if ( pti->TIF_flags & TIF_DONTATTACHQUEUE ||
1491 ptiTo->TIF_flags & TIF_DONTATTACHQUEUE ||
1492 pti->Desktop != ptiTo->Desktop )
1493 return FALSE;
1494
1495 /* If Attach set, allocate and link. */
1496 if ( fAttach )
1497 {
1498 pai = ExAllocatePoolWithTag(PagedPool, sizeof(ATTACHINFO), TAG_ATTACHINFO);
1499 if ( !pai ) return FALSE;
1500
1501 pai->paiNext = gpai;
1502 pai->pti1 = pti;
1503 pai->pti2 = ptiTo;
1504 gpai = pai;
1505 }
1506 else /* If clear, unlink and free it. */
1507 {
1508 PATTACHINFO paiprev = NULL;
1509
1510 if ( !gpai ) return FALSE;
1511
1512 pai = gpai;
1513
1514 /* Search list and free if found or return false. */
1515 do
1516 {
1517 if ( pai->pti2 == ptiTo && pai->pti1 == pti ) break;
1518 paiprev = pai;
1519 pai = pai->paiNext;
1520 } while (pai);
1521
1522 if ( !pai ) return FALSE;
1523
1524 if (paiprev) paiprev->paiNext = pai->paiNext;
1525
1526 ExFreePoolWithTag(pai, TAG_ATTACHINFO);
1527 }
1528
1529 return TRUE;
1530 }
1531
1532 UINT
1533 APIENTRY
1534 NtUserSendInput(
1535 UINT nInputs,
1536 LPINPUT pInput,
1537 INT cbSize)
1538 {
1539 PTHREADINFO W32Thread;
1540 UINT cnt;
1541 DECLARE_RETURN(UINT);
1542
1543 DPRINT("Enter NtUserSendInput\n");
1544 UserEnterExclusive();
1545
1546 W32Thread = PsGetCurrentThreadWin32Thread();
1547 ASSERT(W32Thread);
1548
1549 if(!W32Thread->Desktop)
1550 {
1551 RETURN( 0);
1552 }
1553
1554 if(!nInputs || !pInput || (cbSize != sizeof(INPUT)))
1555 {
1556 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1557 RETURN( 0);
1558 }
1559
1560 /*
1561 * FIXME - check access rights of the window station
1562 * e.g. services running in the service window station cannot block input
1563 */
1564 if(!ThreadHasInputAccess(W32Thread) ||
1565 !IntIsActiveDesktop(W32Thread->Desktop))
1566 {
1567 SetLastWin32Error(ERROR_ACCESS_DENIED);
1568 RETURN( 0);
1569 }
1570
1571 cnt = 0;
1572 while(nInputs--)
1573 {
1574 INPUT SafeInput;
1575 NTSTATUS Status;
1576
1577 Status = MmCopyFromCaller(&SafeInput, pInput++, sizeof(INPUT));
1578 if(!NT_SUCCESS(Status))
1579 {
1580 SetLastNtError(Status);
1581 RETURN( cnt);
1582 }
1583
1584 switch(SafeInput.type)
1585 {
1586 case INPUT_MOUSE:
1587 if(IntMouseInput(&SafeInput.mi))
1588 {
1589 cnt++;
1590 }
1591 break;
1592 case INPUT_KEYBOARD:
1593 if(IntKeyboardInput(&SafeInput.ki))
1594 {
1595 cnt++;
1596 }
1597 break;
1598 case INPUT_HARDWARE:
1599 break;
1600 #ifndef NDEBUG
1601
1602 default:
1603 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput.type);
1604 break;
1605 #endif
1606
1607 }
1608 }
1609
1610 RETURN( cnt);
1611
1612 CLEANUP:
1613 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_);
1614 UserLeave();
1615 END_CLEANUP;
1616 }
1617
1618 /* EOF */