Sync with trunk (r48008)
[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 PWINDOW_OBJECT 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->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 PTHREADINFO pti;
1240 MSG Msg;
1241 LARGE_INTEGER LargeTickCount;
1242 KBDLLHOOKSTRUCT KbdHookData;
1243 WORD flags, wVkStripped, wVkL, wVkR, wVk = ki->wVk, vk_hook = ki->wVk;
1244 BOOLEAN Entered = FALSE;
1245
1246 Msg.lParam = 0;
1247
1248 // Condition may arise when calling MsqPostMessage and waiting for an event.
1249 if (!UserIsEntered())
1250 {
1251 // Fixme: Not sure ATM if this thread is locked.
1252 UserEnterExclusive();
1253 Entered = TRUE;
1254 }
1255
1256 wVk = LOBYTE(wVk);
1257 Msg.wParam = wVk;
1258 flags = LOBYTE(ki->wScan);
1259
1260 if (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) flags |= KF_EXTENDED;
1261 /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
1262
1263 /* strip left/right for menu, control, shift */
1264 switch (wVk)
1265 {
1266 case VK_MENU:
1267 case VK_LMENU:
1268 case VK_RMENU:
1269 wVk = (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) ? VK_RMENU : VK_LMENU;
1270 wVkStripped = VK_MENU;
1271 wVkL = VK_LMENU;
1272 wVkR = VK_RMENU;
1273 break;
1274 case VK_CONTROL:
1275 case VK_LCONTROL:
1276 case VK_RCONTROL:
1277 wVk = (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) ? VK_RCONTROL : VK_LCONTROL;
1278 wVkStripped = VK_CONTROL;
1279 wVkL = VK_LCONTROL;
1280 wVkR = VK_RCONTROL;
1281 break;
1282 case VK_SHIFT:
1283 case VK_LSHIFT:
1284 case VK_RSHIFT:
1285 wVk = (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) ? VK_RSHIFT : VK_LSHIFT;
1286 wVkStripped = VK_SHIFT;
1287 wVkL = VK_LSHIFT;
1288 wVkR = VK_RSHIFT;
1289 break;
1290 default:
1291 wVkStripped = wVkL = wVkR = wVk;
1292 }
1293
1294 if (ki->dwFlags & KEYEVENTF_KEYUP)
1295 {
1296 Msg.message = WM_KEYUP;
1297 if ((gQueueKeyStateTable[VK_MENU] & 0x80) &&
1298 ((wVkStripped == VK_MENU) || (wVkStripped == VK_CONTROL)
1299 || !(gQueueKeyStateTable[VK_CONTROL] & 0x80)))
1300 {
1301 if( TrackSysKey == VK_MENU || /* <ALT>-down/<ALT>-up sequence */
1302 (wVkStripped != VK_MENU)) /* <ALT>-down...<something else>-up */
1303 Msg.message = WM_SYSKEYUP;
1304 TrackSysKey = 0;
1305 }
1306 flags |= KF_REPEAT | KF_UP;
1307 }
1308 else
1309 {
1310 Msg.message = WM_KEYDOWN;
1311 if ((gQueueKeyStateTable[VK_MENU] & 0x80 || wVkStripped == VK_MENU) &&
1312 !(gQueueKeyStateTable[VK_CONTROL] & 0x80 || wVkStripped == VK_CONTROL))
1313 {
1314 Msg.message = WM_SYSKEYDOWN;
1315 TrackSysKey = wVkStripped;
1316 }
1317 if (!(ki->dwFlags & KEYEVENTF_UNICODE) && gQueueKeyStateTable[wVk] & 0x80) flags |= KF_REPEAT;
1318 }
1319
1320 if (ki->dwFlags & KEYEVENTF_UNICODE)
1321 {
1322 vk_hook = Msg.wParam = wVk = VK_PACKET;
1323 Msg.lParam = MAKELPARAM(1 /* repeat count */, ki->wScan);
1324 }
1325
1326 FocusMessageQueue = IntGetFocusMessageQueue();
1327
1328 Msg.hwnd = 0;
1329
1330 if (FocusMessageQueue && (FocusMessageQueue->FocusWindow != (HWND)0))
1331 Msg.hwnd = FocusMessageQueue->FocusWindow;
1332
1333 if (!ki->time)
1334 {
1335 KeQueryTickCount(&LargeTickCount);
1336 Msg.time = MsqCalculateMessageTime(&LargeTickCount);
1337 }
1338 else
1339 Msg.time = ki->time;
1340
1341 /* All messages have to contain the cursor point. */
1342 pti = PsGetCurrentThreadWin32Thread();
1343 Msg.pt = gpsi->ptCursor;
1344
1345 KbdHookData.vkCode = vk_hook;
1346 KbdHookData.scanCode = ki->wScan;
1347 KbdHookData.flags = flags >> 8;
1348 KbdHookData.time = Msg.time;
1349 KbdHookData.dwExtraInfo = ki->dwExtraInfo;
1350 if (co_HOOK_CallHooks(WH_KEYBOARD_LL, HC_ACTION, Msg.message, (LPARAM) &KbdHookData))
1351 {
1352 DPRINT("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1353 Msg.message, vk_hook, Msg.lParam);
1354 if (Entered) UserLeave();
1355 return FALSE;
1356 }
1357
1358 if (!(ki->dwFlags & KEYEVENTF_UNICODE))
1359 {
1360 if (ki->dwFlags & KEYEVENTF_KEYUP)
1361 {
1362 gQueueKeyStateTable[wVk] &= ~0x80;
1363 gQueueKeyStateTable[wVkStripped] = gQueueKeyStateTable[wVkL] | gQueueKeyStateTable[wVkR];
1364 }
1365 else
1366 {
1367 if (!(gQueueKeyStateTable[wVk] & 0x80)) gQueueKeyStateTable[wVk] ^= 0x01;
1368 gQueueKeyStateTable[wVk] |= 0xc0;
1369 gQueueKeyStateTable[wVkStripped] = gQueueKeyStateTable[wVkL] | gQueueKeyStateTable[wVkR];
1370 }
1371
1372 if (gQueueKeyStateTable[VK_MENU] & 0x80) flags |= KF_ALTDOWN;
1373
1374 if (wVkStripped == VK_SHIFT) flags &= ~KF_EXTENDED;
1375
1376 Msg.lParam = MAKELPARAM(1 /* repeat count */, flags);
1377 }
1378
1379 if (FocusMessageQueue == NULL)
1380 {
1381 DPRINT("No focus message queue\n");
1382 if (Entered) UserLeave();
1383 return FALSE;
1384 }
1385
1386 if (FocusMessageQueue->FocusWindow != (HWND)0)
1387 {
1388 Msg.hwnd = FocusMessageQueue->FocusWindow;
1389 DPRINT("Msg.hwnd = %x\n", Msg.hwnd);
1390
1391 FocusMessageQueue->Desktop->pDeskInfo->LastInputWasKbd = TRUE;
1392
1393 Msg.pt = gpsi->ptCursor;
1394
1395 MsqPostMessage(FocusMessageQueue, &Msg, FALSE, QS_KEY);
1396 }
1397 else
1398 {
1399 DPRINT("Invalid focus window handle\n");
1400 }
1401
1402 if (Entered) UserLeave();
1403
1404 return TRUE;
1405 }
1406
1407 BOOL FASTCALL
1408 UserAttachThreadInput( PTHREADINFO pti, PTHREADINFO ptiTo, BOOL fAttach)
1409 {
1410 PATTACHINFO pai;
1411
1412 /* Can not be the same thread.*/
1413 if (pti == ptiTo) return FALSE;
1414
1415 /* Do not attach to system threads or between different desktops. */
1416 if ( pti->TIF_flags & TIF_DONTATTACHQUEUE ||
1417 ptiTo->TIF_flags & TIF_DONTATTACHQUEUE ||
1418 pti->rpdesk != ptiTo->rpdesk )
1419 return FALSE;
1420
1421 /* If Attach set, allocate and link. */
1422 if ( fAttach )
1423 {
1424 pai = ExAllocatePoolWithTag(PagedPool, sizeof(ATTACHINFO), TAG_ATTACHINFO);
1425 if ( !pai ) return FALSE;
1426
1427 pai->paiNext = gpai;
1428 pai->pti1 = pti;
1429 pai->pti2 = ptiTo;
1430 gpai = pai;
1431 }
1432 else /* If clear, unlink and free it. */
1433 {
1434 PATTACHINFO paiprev = NULL;
1435
1436 if ( !gpai ) return FALSE;
1437
1438 pai = gpai;
1439
1440 /* Search list and free if found or return false. */
1441 do
1442 {
1443 if ( pai->pti2 == ptiTo && pai->pti1 == pti ) break;
1444 paiprev = pai;
1445 pai = pai->paiNext;
1446 } while (pai);
1447
1448 if ( !pai ) return FALSE;
1449
1450 if (paiprev) paiprev->paiNext = pai->paiNext;
1451
1452 ExFreePoolWithTag(pai, TAG_ATTACHINFO);
1453 }
1454
1455 return TRUE;
1456 }
1457
1458 UINT
1459 APIENTRY
1460 NtUserSendInput(
1461 UINT nInputs,
1462 LPINPUT pInput,
1463 INT cbSize)
1464 {
1465 PTHREADINFO W32Thread;
1466 UINT cnt;
1467 DECLARE_RETURN(UINT);
1468
1469 DPRINT("Enter NtUserSendInput\n");
1470 UserEnterExclusive();
1471
1472 W32Thread = PsGetCurrentThreadWin32Thread();
1473 ASSERT(W32Thread);
1474
1475 if(!W32Thread->rpdesk)
1476 {
1477 RETURN( 0);
1478 }
1479
1480 if(!nInputs || !pInput || (cbSize != sizeof(INPUT)))
1481 {
1482 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1483 RETURN( 0);
1484 }
1485
1486 /*
1487 * FIXME - check access rights of the window station
1488 * e.g. services running in the service window station cannot block input
1489 */
1490 if(!ThreadHasInputAccess(W32Thread) ||
1491 !IntIsActiveDesktop(W32Thread->rpdesk))
1492 {
1493 SetLastWin32Error(ERROR_ACCESS_DENIED);
1494 RETURN( 0);
1495 }
1496
1497 cnt = 0;
1498 while(nInputs--)
1499 {
1500 INPUT SafeInput;
1501 NTSTATUS Status;
1502
1503 Status = MmCopyFromCaller(&SafeInput, pInput++, sizeof(INPUT));
1504 if(!NT_SUCCESS(Status))
1505 {
1506 SetLastNtError(Status);
1507 RETURN( cnt);
1508 }
1509
1510 switch(SafeInput.type)
1511 {
1512 case INPUT_MOUSE:
1513 if(IntMouseInput(&SafeInput.mi))
1514 {
1515 cnt++;
1516 }
1517 break;
1518 case INPUT_KEYBOARD:
1519 if(IntKeyboardInput(&SafeInput.ki))
1520 {
1521 cnt++;
1522 }
1523 break;
1524 case INPUT_HARDWARE:
1525 break;
1526 #ifndef NDEBUG
1527
1528 default:
1529 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput.type);
1530 break;
1531 #endif
1532
1533 }
1534 }
1535
1536 RETURN( cnt);
1537
1538 CLEANUP:
1539 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_);
1540 UserLeave();
1541 END_CLEANUP;
1542 }
1543
1544 /* EOF */