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