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