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