04fc11531be137c8e127f1fcbeaf0ac0e6f48786
[reactos.git] / reactos / 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 if (fsModifiers == MOD_WIN)
712 IntKeyboardSendWinKeyMsg();
713 else if (fsModifiers == MOD_ALT)
714 {
715 gQueueKeyStateTable[VK_MENU] = 0;
716 if(bLeftAlt)
717 {
718 gQueueKeyStateTable[VK_LMENU] = 0;
719 }
720 else
721 {
722 gQueueKeyStateTable[VK_RMENU] = 0;
723 }
724 co_IntKeyboardSendAltKeyMsg();
725 }
726 continue;
727 }
728
729 NumKeys = 2;
730 }
731 }
732 }
733
734 for (;NumKeys;memcpy(&KeyInput, &NextKeyInput, sizeof(KeyInput)),
735 NumKeys--)
736 {
737 PKBL keyboardLayout = NULL;
738 lParam = 0;
739
740 IntKeyboardUpdateLeds(KeyboardDeviceHandle,
741 &KeyInput,
742 IndicatorTrans);
743
744 /* While we are working, we set up lParam. The format is:
745 * 0-15: The number of times this key has autorepeated
746 * 16-23: The keyboard scancode
747 * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
748 * Note that E1 is only used for PAUSE (E1-1D-45) and
749 * E0-45 happens not to be anything.
750 * 29: Alt is pressed ('Context code')
751 * 30: Previous state, if the key was down before this message
752 * This is a cheap way to ignore autorepeat keys
753 * 31: 1 if the key is being pressed
754 */
755
756 /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
757 * and it's the same key as the last one, increase the repeat
758 * count.
759 */
760
761 if (!(KeyInput.Flags & KEY_BREAK))
762 {
763 if (((KeyInput.Flags & (KEY_E0 | KEY_E1)) == LastFlags) &&
764 (KeyInput.MakeCode == LastMakeCode))
765 {
766 RepeatCount++;
767 lParam |= (1 << 30);
768 }
769 else
770 {
771 RepeatCount = 1;
772 LastFlags = KeyInput.Flags & (KEY_E0 | KEY_E1);
773 LastMakeCode = KeyInput.MakeCode;
774 }
775 }
776 else
777 {
778 LastFlags = 0;
779 LastMakeCode = 0; /* Should never match */
780 lParam |= (1 << 30) | (1 << 31);
781 }
782
783 lParam |= RepeatCount;
784
785 lParam |= (KeyInput.MakeCode & 0xff) << 16;
786
787 if (KeyInput.Flags & KEY_E0)
788 lParam |= (1 << 24);
789
790 if (ModifierState & MOD_ALT)
791 {
792 lParam |= (1 << 29);
793
794 if (!(KeyInput.Flags & KEY_BREAK))
795 msg.message = WM_SYSKEYDOWN;
796 else
797 msg.message = WM_SYSKEYUP;
798 }
799 else
800 {
801 if (!(KeyInput.Flags & KEY_BREAK))
802 msg.message = WM_KEYDOWN;
803 else
804 msg.message = WM_KEYUP;
805 }
806
807 /* Find the target thread whose locale is in effect */
808 FocusQueue = IntGetFocusMessageQueue();
809
810 if (FocusQueue)
811 {
812 msg.hwnd = FocusQueue->FocusWindow;
813
814 FocusThread = FocusQueue->Thread;
815 if (FocusThread && FocusThread->Tcb.Win32Thread)
816 {
817 keyboardLayout = ((PTHREADINFO)FocusThread->Tcb.Win32Thread)->KeyboardLayout;
818 }
819 }
820 if (!keyboardLayout)
821 {
822 keyboardLayout = W32kGetDefaultKeyLayout();
823 }
824
825 msg.lParam = lParam;
826
827 /* This function uses lParam to fill wParam according to the
828 * keyboard layout in use.
829 */
830 W32kKeyProcessMessage(&msg,
831 keyboardLayout->KBTables,
832 KeyInput.Flags & KEY_E0 ? 0xE0 :
833 (KeyInput.Flags & KEY_E1 ? 0xE1 : 0));
834
835 if (GetHotKey(ModifierState,
836 msg.wParam,
837 &Thread,
838 &hWnd,
839 &id))
840 {
841 if (!(KeyInput.Flags & KEY_BREAK))
842 {
843 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd, id);
844 MsqPostHotKeyMessage (Thread,
845 hWnd,
846 (WPARAM)id,
847 MAKELPARAM((WORD)ModifierState,
848 (WORD)msg.wParam));
849 }
850 continue; /* Eat key up motion too */
851 }
852
853 if (!FocusQueue)
854 {
855 /* There is no focused window to receive a keyboard message */
856 continue;
857 }
858 /*
859 * Post a keyboard message.
860 */
861 co_MsqPostKeyboardMessage(msg.message,msg.wParam,msg.lParam);
862 }
863 }
864
865 KeyboardEscape:
866 DPRINT( "KeyboardInput Thread Stopped...\n" );
867 }
868 }
869
870
871 static PVOID Objects[2];
872 /*
873 Raw Input Thread.
874 Since this relies on InputThreadsStart, just fake it.
875 */
876 static VOID APIENTRY
877 RawInputThreadMain(PVOID StartContext)
878 {
879 NTSTATUS Status;
880 LARGE_INTEGER DueTime;
881
882 DueTime.QuadPart = (LONGLONG)(-10000000);
883
884 do
885 {
886 KEVENT Event;
887 KeInitializeEvent(&Event, NotificationEvent, FALSE);
888 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime);
889 } while (!NT_SUCCESS(Status));
890
891
892 Objects[0] = &InputThreadsStart;
893 Objects[1] = MasterTimer;
894
895 // This thread requires win32k!
896 Status = Win32kInitWin32Thread(PsGetCurrentThread());
897 if (!NT_SUCCESS(Status))
898 {
899 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
900 return; //(Status);
901 }
902
903 ptiRawInput = PsGetCurrentThreadWin32Thread();
904 ptiRawInput->TIF_flags |= TIF_SYSTEMTHREAD;
905 DPRINT("Raw Input Thread 0x%x \n", ptiRawInput);
906
907 KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
908 LOW_REALTIME_PRIORITY + 3);
909
910 UserEnterExclusive();
911 StartTheTimers();
912 UserLeave();
913
914 //
915 // ATM, we just have one job to handle, merge the other two later.
916 //
917 for(;;)
918 {
919 DPRINT( "Raw Input Thread Waiting for start event\n" );
920
921 Status = KeWaitForMultipleObjects( 2,
922 Objects,
923 WaitAll, //WaitAny,
924 WrUserRequest,
925 KernelMode,
926 TRUE,
927 NULL,
928 NULL);
929 DPRINT( "Raw Input Thread Starting...\n" );
930
931 ProcessTimers();
932 }
933 DPRINT1("Raw Input Thread Exit!\n");
934 }
935
936 INIT_FUNCTION
937 NTSTATUS
938 NTAPI
939 InitInputImpl(VOID)
940 {
941 NTSTATUS Status;
942
943 KeInitializeEvent(&InputThreadsStart, NotificationEvent, FALSE);
944
945 MasterTimer = ExAllocatePoolWithTag(NonPagedPool, sizeof(KTIMER), USERTAG_SYSTEM);
946 if (!MasterTimer)
947 {
948 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
949 ASSERT(FALSE);
950 return STATUS_UNSUCCESSFUL;
951 }
952 KeInitializeTimer(MasterTimer);
953
954 /* Initialize the default keyboard layout */
955 if(!UserInitDefaultKeyboardLayout())
956 {
957 DPRINT1("Failed to initialize default keyboard layout!\n");
958 }
959
960 Status = PsCreateSystemThread(&RawInputThreadHandle,
961 THREAD_ALL_ACCESS,
962 NULL,
963 NULL,
964 &RawInputThreadId,
965 RawInputThreadMain,
966 NULL);
967 if (!NT_SUCCESS(Status))
968 {
969 DPRINT1("Win32K: Failed to create raw thread.\n");
970 }
971
972 Status = PsCreateSystemThread(&KeyboardThreadHandle,
973 THREAD_ALL_ACCESS,
974 NULL,
975 NULL,
976 &KeyboardThreadId,
977 KeyboardThreadMain,
978 NULL);
979 if (!NT_SUCCESS(Status))
980 {
981 DPRINT1("Win32K: Failed to create keyboard thread.\n");
982 }
983
984 Status = PsCreateSystemThread(&MouseThreadHandle,
985 THREAD_ALL_ACCESS,
986 NULL,
987 NULL,
988 &MouseThreadId,
989 MouseThreadMain,
990 NULL);
991 if (!NT_SUCCESS(Status))
992 {
993 DPRINT1("Win32K: Failed to create mouse thread.\n");
994 }
995
996 InputThreadsRunning = TRUE;
997 KeSetEvent(&InputThreadsStart, IO_NO_INCREMENT, FALSE);
998
999 return STATUS_SUCCESS;
1000 }
1001
1002 NTSTATUS FASTCALL
1003 CleanupInputImp(VOID)
1004 {
1005 return(STATUS_SUCCESS);
1006 }
1007
1008 BOOL FASTCALL
1009 IntBlockInput(PTHREADINFO W32Thread, BOOL BlockIt)
1010 {
1011 PTHREADINFO OldBlock;
1012 ASSERT(W32Thread);
1013
1014 if(!W32Thread->rpdesk || ((W32Thread->TIF_flags & TIF_INCLEANUP) && BlockIt))
1015 {
1016 /*
1017 * fail blocking if exiting the thread
1018 */
1019
1020 return FALSE;
1021 }
1022
1023 /*
1024 * FIXME - check access rights of the window station
1025 * e.g. services running in the service window station cannot block input
1026 */
1027 if(!ThreadHasInputAccess(W32Thread) ||
1028 !IntIsActiveDesktop(W32Thread->rpdesk))
1029 {
1030 EngSetLastError(ERROR_ACCESS_DENIED);
1031 return FALSE;
1032 }
1033
1034 ASSERT(W32Thread->rpdesk);
1035 OldBlock = W32Thread->rpdesk->BlockInputThread;
1036 if(OldBlock)
1037 {
1038 if(OldBlock != W32Thread)
1039 {
1040 EngSetLastError(ERROR_ACCESS_DENIED);
1041 return FALSE;
1042 }
1043 W32Thread->rpdesk->BlockInputThread = (BlockIt ? W32Thread : NULL);
1044 return OldBlock == NULL;
1045 }
1046
1047 W32Thread->rpdesk->BlockInputThread = (BlockIt ? W32Thread : NULL);
1048 return OldBlock == NULL;
1049 }
1050
1051 BOOL
1052 APIENTRY
1053 NtUserBlockInput(
1054 BOOL BlockIt)
1055 {
1056 DECLARE_RETURN(BOOLEAN);
1057
1058 DPRINT("Enter NtUserBlockInput\n");
1059 UserEnterExclusive();
1060
1061 RETURN( IntBlockInput(PsGetCurrentThreadWin32Thread(), BlockIt));
1062
1063 CLEANUP:
1064 DPRINT("Leave NtUserBlockInput, ret=%i\n",_ret_);
1065 UserLeave();
1066 END_CLEANUP;
1067 }
1068
1069 BOOL FASTCALL
1070 IntMouseInput(MOUSEINPUT *mi)
1071 {
1072 const UINT SwapBtnMsg[2][2] =
1073 {
1074 {WM_LBUTTONDOWN, WM_RBUTTONDOWN},
1075 {WM_LBUTTONUP, WM_RBUTTONUP}
1076 };
1077 const WPARAM SwapBtn[2] =
1078 {
1079 MK_LBUTTON, MK_RBUTTON
1080 };
1081 POINT MousePos;
1082 PSYSTEM_CURSORINFO CurInfo;
1083 BOOL SwapButtons;
1084 MSG Msg;
1085
1086 ASSERT(mi);
1087
1088 CurInfo = IntGetSysCursorInfo();
1089
1090 if(!mi->time)
1091 {
1092 LARGE_INTEGER LargeTickCount;
1093 KeQueryTickCount(&LargeTickCount);
1094 mi->time = MsqCalculateMessageTime(&LargeTickCount);
1095 }
1096
1097 SwapButtons = gspv.bMouseBtnSwap;
1098
1099 MousePos = gpsi->ptCursor;
1100
1101 if(mi->dwFlags & MOUSEEVENTF_MOVE)
1102 {
1103 if(mi->dwFlags & MOUSEEVENTF_ABSOLUTE)
1104 {
1105 MousePos.x = mi->dx * UserGetSystemMetrics(SM_CXVIRTUALSCREEN) >> 16;
1106 MousePos.y = mi->dy * UserGetSystemMetrics(SM_CYVIRTUALSCREEN) >> 16;
1107 }
1108 else
1109 {
1110 MousePos.x += mi->dx;
1111 MousePos.y += mi->dy;
1112 }
1113 }
1114
1115 /*
1116 * Insert the messages into the system queue
1117 */
1118 Msg.wParam = 0;
1119 Msg.lParam = MAKELPARAM(MousePos.x, MousePos.y);
1120 Msg.pt = MousePos;
1121
1122 if (gQueueKeyStateTable[VK_SHIFT] & 0xc0)
1123 {
1124 Msg.wParam |= MK_SHIFT;
1125 }
1126
1127 if (gQueueKeyStateTable[VK_CONTROL] & 0xc0)
1128 {
1129 Msg.wParam |= MK_CONTROL;
1130 }
1131
1132 if(mi->dwFlags & MOUSEEVENTF_MOVE)
1133 {
1134 UserSetCursorPos(MousePos.x, MousePos.y, TRUE);
1135 }
1136 if(mi->dwFlags & MOUSEEVENTF_LEFTDOWN)
1137 {
1138 gQueueKeyStateTable[VK_LBUTTON] |= 0xc0;
1139 Msg.message = SwapBtnMsg[0][SwapButtons];
1140 CurInfo->ButtonsDown |= SwapBtn[SwapButtons];
1141 Msg.wParam |= CurInfo->ButtonsDown;
1142 co_MsqInsertMouseMessage(&Msg);
1143 }
1144 else if(mi->dwFlags & MOUSEEVENTF_LEFTUP)
1145 {
1146 gQueueKeyStateTable[VK_LBUTTON] &= ~0x80;
1147 Msg.message = SwapBtnMsg[1][SwapButtons];
1148 CurInfo->ButtonsDown &= ~SwapBtn[SwapButtons];
1149 Msg.wParam |= CurInfo->ButtonsDown;
1150 co_MsqInsertMouseMessage(&Msg);
1151 }
1152 if(mi->dwFlags & MOUSEEVENTF_MIDDLEDOWN)
1153 {
1154 gQueueKeyStateTable[VK_MBUTTON] |= 0xc0;
1155 Msg.message = WM_MBUTTONDOWN;
1156 CurInfo->ButtonsDown |= MK_MBUTTON;
1157 Msg.wParam |= CurInfo->ButtonsDown;
1158 co_MsqInsertMouseMessage(&Msg);
1159 }
1160 else if(mi->dwFlags & MOUSEEVENTF_MIDDLEUP)
1161 {
1162 gQueueKeyStateTable[VK_MBUTTON] &= ~0x80;
1163 Msg.message = WM_MBUTTONUP;
1164 CurInfo->ButtonsDown &= ~MK_MBUTTON;
1165 Msg.wParam |= CurInfo->ButtonsDown;
1166 co_MsqInsertMouseMessage(&Msg);
1167 }
1168 if(mi->dwFlags & MOUSEEVENTF_RIGHTDOWN)
1169 {
1170 gQueueKeyStateTable[VK_RBUTTON] |= 0xc0;
1171 Msg.message = SwapBtnMsg[0][!SwapButtons];
1172 CurInfo->ButtonsDown |= SwapBtn[!SwapButtons];
1173 Msg.wParam |= CurInfo->ButtonsDown;
1174 co_MsqInsertMouseMessage(&Msg);
1175 }
1176 else if(mi->dwFlags & MOUSEEVENTF_RIGHTUP)
1177 {
1178 gQueueKeyStateTable[VK_RBUTTON] &= ~0x80;
1179 Msg.message = SwapBtnMsg[1][!SwapButtons];
1180 CurInfo->ButtonsDown &= ~SwapBtn[!SwapButtons];
1181 Msg.wParam |= CurInfo->ButtonsDown;
1182 co_MsqInsertMouseMessage(&Msg);
1183 }
1184
1185 if((mi->dwFlags & (MOUSEEVENTF_XDOWN | MOUSEEVENTF_XUP)) &&
1186 (mi->dwFlags & MOUSEEVENTF_WHEEL))
1187 {
1188 /* fail because both types of events use the mouseData field */
1189 return FALSE;
1190 }
1191
1192 if(mi->dwFlags & MOUSEEVENTF_XDOWN)
1193 {
1194 Msg.message = WM_XBUTTONDOWN;
1195 if(mi->mouseData & XBUTTON1)
1196 {
1197 gQueueKeyStateTable[VK_XBUTTON1] |= 0xc0;
1198 CurInfo->ButtonsDown |= MK_XBUTTON1;
1199 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
1200 co_MsqInsertMouseMessage(&Msg);
1201 }
1202 if(mi->mouseData & XBUTTON2)
1203 {
1204 gQueueKeyStateTable[VK_XBUTTON2] |= 0xc0;
1205 CurInfo->ButtonsDown |= MK_XBUTTON2;
1206 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
1207 co_MsqInsertMouseMessage(&Msg);
1208 }
1209 }
1210 else if(mi->dwFlags & MOUSEEVENTF_XUP)
1211 {
1212 Msg.message = WM_XBUTTONUP;
1213 if(mi->mouseData & XBUTTON1)
1214 {
1215 gQueueKeyStateTable[VK_XBUTTON1] &= ~0x80;
1216 CurInfo->ButtonsDown &= ~MK_XBUTTON1;
1217 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
1218 co_MsqInsertMouseMessage(&Msg);
1219 }
1220 if(mi->mouseData & XBUTTON2)
1221 {
1222 gQueueKeyStateTable[VK_XBUTTON2] &= ~0x80;
1223 CurInfo->ButtonsDown &= ~MK_XBUTTON2;
1224 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
1225 co_MsqInsertMouseMessage(&Msg);
1226 }
1227 }
1228 if(mi->dwFlags & MOUSEEVENTF_WHEEL)
1229 {
1230 Msg.message = WM_MOUSEWHEEL;
1231 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, mi->mouseData);
1232 co_MsqInsertMouseMessage(&Msg);
1233 }
1234
1235 return TRUE;
1236 }
1237
1238 BOOL FASTCALL
1239 IntKeyboardInput(KEYBDINPUT *ki)
1240 {
1241 PUSER_MESSAGE_QUEUE FocusMessageQueue;
1242 MSG Msg;
1243 LARGE_INTEGER LargeTickCount;
1244 KBDLLHOOKSTRUCT KbdHookData;
1245 WORD flags, wVkStripped, wVkL, wVkR, wVk = ki->wVk, vk_hook = ki->wVk;
1246 BOOLEAN Entered = FALSE;
1247
1248 Msg.lParam = 0;
1249
1250 // Condition may arise when calling MsqPostMessage and waiting for an event.
1251 if (!UserIsEntered())
1252 {
1253 // Fixme: Not sure ATM if this thread is locked.
1254 UserEnterExclusive();
1255 Entered = TRUE;
1256 }
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 if (Entered) UserLeave();
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 if (Entered) UserLeave();
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 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), USERTAG_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, USERTAG_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 EngSetLastError(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 EngSetLastError(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 */