Sync with trunk head (part 1 of 2)
[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;
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
883 MasterTimer = ExAllocatePoolWithTag(NonPagedPool, sizeof(KTIMER), TAG_INPUT);
884 if (!MasterTimer)
885 {
886 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
887 return;
888 }
889 KeInitializeTimer(MasterTimer);
890 Objects[1] = MasterTimer;
891
892 // This thread requires win32k!
893 Status = Win32kInitWin32Thread(PsGetCurrentThread());
894 if (!NT_SUCCESS(Status))
895 {
896 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
897 return; //(Status);
898 }
899
900 ptiRawInput = PsGetCurrentThreadWin32Thread();
901 DPRINT("\nRaw Input Thread 0x%x \n", ptiRawInput);
902
903
904 KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
905 LOW_REALTIME_PRIORITY + 3);
906
907 UserEnterExclusive();
908 StartTheTimers();
909 UserLeave();
910
911 //
912 // ATM, we just have one job to handle, merge the other two later.
913 //
914 for(;;)
915 {
916 DPRINT( "Raw Input Thread Waiting for start event\n" );
917
918 Status = KeWaitForMultipleObjects( 2,
919 Objects,
920 WaitAll, //WaitAny,
921 WrUserRequest,
922 KernelMode,
923 TRUE,
924 NULL,
925 NULL);
926 DPRINT( "Raw Input Thread Starting...\n" );
927
928 ProcessTimers();
929 }
930 DPRINT1("Raw Input Thread Exit!\n");
931 }
932
933 NTSTATUS FASTCALL
934 InitInputImpl(VOID)
935 {
936 NTSTATUS Status;
937
938 KeInitializeEvent(&InputThreadsStart, NotificationEvent, FALSE);
939
940 /* Initialize the default keyboard layout */
941 if(!UserInitDefaultKeyboardLayout())
942 {
943 DPRINT1("Failed to initialize default keyboard layout!\n");
944 }
945
946 Status = PsCreateSystemThread(&RawInputThreadHandle,
947 THREAD_ALL_ACCESS,
948 NULL,
949 NULL,
950 &RawInputThreadId,
951 RawInputThreadMain,
952 NULL);
953 if (!NT_SUCCESS(Status))
954 {
955 DPRINT1("Win32K: Failed to create raw thread.\n");
956 }
957
958 Status = PsCreateSystemThread(&KeyboardThreadHandle,
959 THREAD_ALL_ACCESS,
960 NULL,
961 NULL,
962 &KeyboardThreadId,
963 KeyboardThreadMain,
964 NULL);
965 if (!NT_SUCCESS(Status))
966 {
967 DPRINT1("Win32K: Failed to create keyboard thread.\n");
968 }
969
970 Status = PsCreateSystemThread(&MouseThreadHandle,
971 THREAD_ALL_ACCESS,
972 NULL,
973 NULL,
974 &MouseThreadId,
975 MouseThreadMain,
976 NULL);
977 if (!NT_SUCCESS(Status))
978 {
979 DPRINT1("Win32K: Failed to create mouse thread.\n");
980 }
981
982 InputThreadsRunning = TRUE;
983 KeSetEvent(&InputThreadsStart, IO_NO_INCREMENT, FALSE);
984
985 return STATUS_SUCCESS;
986 }
987
988 NTSTATUS FASTCALL
989 CleanupInputImp(VOID)
990 {
991 return(STATUS_SUCCESS);
992 }
993
994 BOOL
995 APIENTRY
996 NtUserDragDetect(
997 HWND hWnd,
998 POINT pt) // Just like the User call.
999 {
1000 UNIMPLEMENTED
1001 return 0;
1002 }
1003
1004 BOOL FASTCALL
1005 IntBlockInput(PTHREADINFO W32Thread, BOOL BlockIt)
1006 {
1007 PTHREADINFO OldBlock;
1008 ASSERT(W32Thread);
1009
1010 if(!W32Thread->rpdesk || ((W32Thread->TIF_flags & TIF_INCLEANUP) && BlockIt))
1011 {
1012 /*
1013 * fail blocking if exiting the thread
1014 */
1015
1016 return FALSE;
1017 }
1018
1019 /*
1020 * FIXME - check access rights of the window station
1021 * e.g. services running in the service window station cannot block input
1022 */
1023 if(!ThreadHasInputAccess(W32Thread) ||
1024 !IntIsActiveDesktop(W32Thread->rpdesk))
1025 {
1026 SetLastWin32Error(ERROR_ACCESS_DENIED);
1027 return FALSE;
1028 }
1029
1030 ASSERT(W32Thread->rpdesk);
1031 OldBlock = W32Thread->rpdesk->BlockInputThread;
1032 if(OldBlock)
1033 {
1034 if(OldBlock != W32Thread)
1035 {
1036 SetLastWin32Error(ERROR_ACCESS_DENIED);
1037 return FALSE;
1038 }
1039 W32Thread->rpdesk->BlockInputThread = (BlockIt ? W32Thread : NULL);
1040 return OldBlock == NULL;
1041 }
1042
1043 W32Thread->rpdesk->BlockInputThread = (BlockIt ? W32Thread : NULL);
1044 return OldBlock == NULL;
1045 }
1046
1047 BOOL
1048 APIENTRY
1049 NtUserBlockInput(
1050 BOOL BlockIt)
1051 {
1052 DECLARE_RETURN(BOOLEAN);
1053
1054 DPRINT("Enter NtUserBlockInput\n");
1055 UserEnterExclusive();
1056
1057 RETURN( IntBlockInput(PsGetCurrentThreadWin32Thread(), BlockIt));
1058
1059 CLEANUP:
1060 DPRINT("Leave NtUserBlockInput, ret=%i\n",_ret_);
1061 UserLeave();
1062 END_CLEANUP;
1063 }
1064
1065 BOOL FASTCALL
1066 IntMouseInput(MOUSEINPUT *mi)
1067 {
1068 const UINT SwapBtnMsg[2][2] =
1069 {
1070 {WM_LBUTTONDOWN, WM_RBUTTONDOWN},
1071 {WM_LBUTTONUP, WM_RBUTTONUP}
1072 };
1073 const WPARAM SwapBtn[2] =
1074 {
1075 MK_LBUTTON, MK_RBUTTON
1076 };
1077 POINT MousePos;
1078 PSYSTEM_CURSORINFO CurInfo;
1079 BOOL SwapButtons;
1080 MSG Msg;
1081
1082 ASSERT(mi);
1083
1084 CurInfo = IntGetSysCursorInfo();
1085
1086 if(!mi->time)
1087 {
1088 LARGE_INTEGER LargeTickCount;
1089 KeQueryTickCount(&LargeTickCount);
1090 mi->time = MsqCalculateMessageTime(&LargeTickCount);
1091 }
1092
1093 SwapButtons = gspv.bMouseBtnSwap;
1094
1095 MousePos = gpsi->ptCursor;
1096
1097 if(mi->dwFlags & MOUSEEVENTF_MOVE)
1098 {
1099 if(mi->dwFlags & MOUSEEVENTF_ABSOLUTE)
1100 {
1101 MousePos.x = mi->dx * UserGetSystemMetrics(SM_CXVIRTUALSCREEN) >> 16;
1102 MousePos.y = mi->dy * UserGetSystemMetrics(SM_CYVIRTUALSCREEN) >> 16;
1103 }
1104 else
1105 {
1106 MousePos.x += mi->dx;
1107 MousePos.y += mi->dy;
1108 }
1109 }
1110
1111 /*
1112 * Insert the messages into the system queue
1113 */
1114 Msg.wParam = 0;
1115 Msg.lParam = MAKELPARAM(MousePos.x, MousePos.y);
1116 Msg.pt = MousePos;
1117
1118 if (gQueueKeyStateTable[VK_SHIFT] & 0xc0)
1119 {
1120 Msg.wParam |= MK_SHIFT;
1121 }
1122
1123 if (gQueueKeyStateTable[VK_CONTROL] & 0xc0)
1124 {
1125 Msg.wParam |= MK_CONTROL;
1126 }
1127
1128 if(mi->dwFlags & MOUSEEVENTF_MOVE)
1129 {
1130 UserSetCursorPos(MousePos.x, MousePos.y);
1131 }
1132 if(mi->dwFlags & MOUSEEVENTF_LEFTDOWN)
1133 {
1134 gQueueKeyStateTable[VK_LBUTTON] |= 0xc0;
1135 Msg.message = SwapBtnMsg[0][SwapButtons];
1136 CurInfo->ButtonsDown |= SwapBtn[SwapButtons];
1137 Msg.wParam |= CurInfo->ButtonsDown;
1138 MsqInsertSystemMessage(&Msg);
1139 }
1140 else if(mi->dwFlags & MOUSEEVENTF_LEFTUP)
1141 {
1142 gQueueKeyStateTable[VK_LBUTTON] &= ~0x80;
1143 Msg.message = SwapBtnMsg[1][SwapButtons];
1144 CurInfo->ButtonsDown &= ~SwapBtn[SwapButtons];
1145 Msg.wParam |= CurInfo->ButtonsDown;
1146 MsqInsertSystemMessage(&Msg);
1147 }
1148 if(mi->dwFlags & MOUSEEVENTF_MIDDLEDOWN)
1149 {
1150 gQueueKeyStateTable[VK_MBUTTON] |= 0xc0;
1151 Msg.message = WM_MBUTTONDOWN;
1152 CurInfo->ButtonsDown |= MK_MBUTTON;
1153 Msg.wParam |= CurInfo->ButtonsDown;
1154 MsqInsertSystemMessage(&Msg);
1155 }
1156 else if(mi->dwFlags & MOUSEEVENTF_MIDDLEUP)
1157 {
1158 gQueueKeyStateTable[VK_MBUTTON] &= ~0x80;
1159 Msg.message = WM_MBUTTONUP;
1160 CurInfo->ButtonsDown &= ~MK_MBUTTON;
1161 Msg.wParam |= CurInfo->ButtonsDown;
1162 MsqInsertSystemMessage(&Msg);
1163 }
1164 if(mi->dwFlags & MOUSEEVENTF_RIGHTDOWN)
1165 {
1166 gQueueKeyStateTable[VK_RBUTTON] |= 0xc0;
1167 Msg.message = SwapBtnMsg[0][!SwapButtons];
1168 CurInfo->ButtonsDown |= SwapBtn[!SwapButtons];
1169 Msg.wParam |= CurInfo->ButtonsDown;
1170 MsqInsertSystemMessage(&Msg);
1171 }
1172 else if(mi->dwFlags & MOUSEEVENTF_RIGHTUP)
1173 {
1174 gQueueKeyStateTable[VK_RBUTTON] &= ~0x80;
1175 Msg.message = SwapBtnMsg[1][!SwapButtons];
1176 CurInfo->ButtonsDown &= ~SwapBtn[!SwapButtons];
1177 Msg.wParam |= CurInfo->ButtonsDown;
1178 MsqInsertSystemMessage(&Msg);
1179 }
1180
1181 if((mi->dwFlags & (MOUSEEVENTF_XDOWN | MOUSEEVENTF_XUP)) &&
1182 (mi->dwFlags & MOUSEEVENTF_WHEEL))
1183 {
1184 /* fail because both types of events use the mouseData field */
1185 return FALSE;
1186 }
1187
1188 if(mi->dwFlags & MOUSEEVENTF_XDOWN)
1189 {
1190 Msg.message = WM_XBUTTONDOWN;
1191 if(mi->mouseData & XBUTTON1)
1192 {
1193 gQueueKeyStateTable[VK_XBUTTON1] |= 0xc0;
1194 CurInfo->ButtonsDown |= MK_XBUTTON1;
1195 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
1196 MsqInsertSystemMessage(&Msg);
1197 }
1198 if(mi->mouseData & XBUTTON2)
1199 {
1200 gQueueKeyStateTable[VK_XBUTTON2] |= 0xc0;
1201 CurInfo->ButtonsDown |= MK_XBUTTON2;
1202 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
1203 MsqInsertSystemMessage(&Msg);
1204 }
1205 }
1206 else if(mi->dwFlags & MOUSEEVENTF_XUP)
1207 {
1208 Msg.message = WM_XBUTTONUP;
1209 if(mi->mouseData & XBUTTON1)
1210 {
1211 gQueueKeyStateTable[VK_XBUTTON1] &= ~0x80;
1212 CurInfo->ButtonsDown &= ~MK_XBUTTON1;
1213 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
1214 MsqInsertSystemMessage(&Msg);
1215 }
1216 if(mi->mouseData & XBUTTON2)
1217 {
1218 gQueueKeyStateTable[VK_XBUTTON2] &= ~0x80;
1219 CurInfo->ButtonsDown &= ~MK_XBUTTON2;
1220 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
1221 MsqInsertSystemMessage(&Msg);
1222 }
1223 }
1224 if(mi->dwFlags & MOUSEEVENTF_WHEEL)
1225 {
1226 Msg.message = WM_MOUSEWHEEL;
1227 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, mi->mouseData);
1228 MsqInsertSystemMessage(&Msg);
1229 }
1230
1231 return TRUE;
1232 }
1233
1234 BOOL FASTCALL
1235 IntKeyboardInput(KEYBDINPUT *ki)
1236 {
1237 PUSER_MESSAGE_QUEUE FocusMessageQueue;
1238 PTHREADINFO pti;
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 pti = PsGetCurrentThreadWin32Thread();
1342 Msg.pt = gpsi->ptCursor;
1343
1344 DPRINT1("Kbd Hook msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1345 Msg.message, vk_hook, Msg.lParam);
1346
1347 KbdHookData.vkCode = vk_hook;
1348 KbdHookData.scanCode = ki->wScan;
1349 KbdHookData.flags = flags >> 8;
1350 KbdHookData.time = Msg.time;
1351 KbdHookData.dwExtraInfo = ki->dwExtraInfo;
1352 if (co_HOOK_CallHooks(WH_KEYBOARD_LL, HC_ACTION, Msg.message, (LPARAM) &KbdHookData))
1353 {
1354 DPRINT("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1355 Msg.message, vk_hook, Msg.lParam);
1356 if (Entered) UserLeave();
1357 return FALSE;
1358 }
1359
1360 if (!(ki->dwFlags & KEYEVENTF_UNICODE))
1361 {
1362 if (ki->dwFlags & KEYEVENTF_KEYUP)
1363 {
1364 gQueueKeyStateTable[wVk] &= ~0x80;
1365 gQueueKeyStateTable[wVkStripped] = gQueueKeyStateTable[wVkL] | gQueueKeyStateTable[wVkR];
1366 }
1367 else
1368 {
1369 if (!(gQueueKeyStateTable[wVk] & 0x80)) gQueueKeyStateTable[wVk] ^= 0x01;
1370 gQueueKeyStateTable[wVk] |= 0xc0;
1371 gQueueKeyStateTable[wVkStripped] = gQueueKeyStateTable[wVkL] | gQueueKeyStateTable[wVkR];
1372 }
1373
1374 if (gQueueKeyStateTable[VK_MENU] & 0x80) flags |= KF_ALTDOWN;
1375
1376 if (wVkStripped == VK_SHIFT) flags &= ~KF_EXTENDED;
1377
1378 Msg.lParam = MAKELPARAM(1 /* repeat count */, flags);
1379 }
1380
1381 if (FocusMessageQueue == NULL)
1382 {
1383 DPRINT("No focus message queue\n");
1384 if (Entered) UserLeave();
1385 return FALSE;
1386 }
1387
1388 if (FocusMessageQueue->FocusWindow != (HWND)0)
1389 {
1390 Msg.hwnd = FocusMessageQueue->FocusWindow;
1391 DPRINT("Msg.hwnd = %x\n", Msg.hwnd);
1392
1393 FocusMessageQueue->Desktop->pDeskInfo->LastInputWasKbd = TRUE;
1394
1395 Msg.pt = gpsi->ptCursor;
1396
1397 MsqPostMessage(FocusMessageQueue, &Msg, FALSE, QS_KEY);
1398 }
1399 else
1400 {
1401 DPRINT("Invalid focus window handle\n");
1402 }
1403
1404 if (Entered) UserLeave();
1405
1406 return TRUE;
1407 }
1408
1409 BOOL FASTCALL
1410 UserAttachThreadInput( PTHREADINFO pti, PTHREADINFO ptiTo, BOOL fAttach)
1411 {
1412 PATTACHINFO pai;
1413
1414 /* Can not be the same thread.*/
1415 if (pti == ptiTo) return FALSE;
1416
1417 /* Do not attach to system threads or between different desktops. */
1418 if ( pti->TIF_flags & TIF_DONTATTACHQUEUE ||
1419 ptiTo->TIF_flags & TIF_DONTATTACHQUEUE ||
1420 pti->rpdesk != ptiTo->rpdesk )
1421 return FALSE;
1422
1423 /* If Attach set, allocate and link. */
1424 if ( fAttach )
1425 {
1426 pai = ExAllocatePoolWithTag(PagedPool, sizeof(ATTACHINFO), TAG_ATTACHINFO);
1427 if ( !pai ) return FALSE;
1428
1429 pai->paiNext = gpai;
1430 pai->pti1 = pti;
1431 pai->pti2 = ptiTo;
1432 gpai = pai;
1433 }
1434 else /* If clear, unlink and free it. */
1435 {
1436 PATTACHINFO paiprev = NULL;
1437
1438 if ( !gpai ) return FALSE;
1439
1440 pai = gpai;
1441
1442 /* Search list and free if found or return false. */
1443 do
1444 {
1445 if ( pai->pti2 == ptiTo && pai->pti1 == pti ) break;
1446 paiprev = pai;
1447 pai = pai->paiNext;
1448 } while (pai);
1449
1450 if ( !pai ) return FALSE;
1451
1452 if (paiprev) paiprev->paiNext = pai->paiNext;
1453
1454 ExFreePoolWithTag(pai, TAG_ATTACHINFO);
1455 }
1456
1457 return TRUE;
1458 }
1459
1460 UINT
1461 APIENTRY
1462 NtUserSendInput(
1463 UINT nInputs,
1464 LPINPUT pInput,
1465 INT cbSize)
1466 {
1467 PTHREADINFO W32Thread;
1468 UINT cnt;
1469 DECLARE_RETURN(UINT);
1470
1471 DPRINT("Enter NtUserSendInput\n");
1472 UserEnterExclusive();
1473
1474 W32Thread = PsGetCurrentThreadWin32Thread();
1475 ASSERT(W32Thread);
1476
1477 if(!W32Thread->rpdesk)
1478 {
1479 RETURN( 0);
1480 }
1481
1482 if(!nInputs || !pInput || (cbSize != sizeof(INPUT)))
1483 {
1484 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1485 RETURN( 0);
1486 }
1487
1488 /*
1489 * FIXME - check access rights of the window station
1490 * e.g. services running in the service window station cannot block input
1491 */
1492 if(!ThreadHasInputAccess(W32Thread) ||
1493 !IntIsActiveDesktop(W32Thread->rpdesk))
1494 {
1495 SetLastWin32Error(ERROR_ACCESS_DENIED);
1496 RETURN( 0);
1497 }
1498
1499 cnt = 0;
1500 while(nInputs--)
1501 {
1502 INPUT SafeInput;
1503 NTSTATUS Status;
1504
1505 Status = MmCopyFromCaller(&SafeInput, pInput++, sizeof(INPUT));
1506 if(!NT_SUCCESS(Status))
1507 {
1508 SetLastNtError(Status);
1509 RETURN( cnt);
1510 }
1511
1512 switch(SafeInput.type)
1513 {
1514 case INPUT_MOUSE:
1515 if(IntMouseInput(&SafeInput.mi))
1516 {
1517 cnt++;
1518 }
1519 break;
1520 case INPUT_KEYBOARD:
1521 if(IntKeyboardInput(&SafeInput.ki))
1522 {
1523 cnt++;
1524 }
1525 break;
1526 case INPUT_HARDWARE:
1527 break;
1528 #ifndef NDEBUG
1529
1530 default:
1531 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput.type);
1532 break;
1533 #endif
1534
1535 }
1536 }
1537
1538 RETURN( cnt);
1539
1540 CLEANUP:
1541 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_);
1542 UserLeave();
1543 END_CLEANUP;
1544 }
1545
1546 /* EOF */