[win32k]
[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: 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 = CurInfo->ButtonsDown;
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 MsqInsertSystemMessage(&Msg);
1138 }
1139 else if(mi->dwFlags & MOUSEEVENTF_LEFTUP)
1140 {
1141 gQueueKeyStateTable[VK_LBUTTON] &= ~0x80;
1142 Msg.message = SwapBtnMsg[1][SwapButtons];
1143 CurInfo->ButtonsDown &= ~SwapBtn[SwapButtons];
1144 MsqInsertSystemMessage(&Msg);
1145 }
1146 if(mi->dwFlags & MOUSEEVENTF_MIDDLEDOWN)
1147 {
1148 gQueueKeyStateTable[VK_MBUTTON] |= 0xc0;
1149 Msg.message = WM_MBUTTONDOWN;
1150 CurInfo->ButtonsDown |= MK_MBUTTON;
1151 MsqInsertSystemMessage(&Msg);
1152 }
1153 else if(mi->dwFlags & MOUSEEVENTF_MIDDLEUP)
1154 {
1155 gQueueKeyStateTable[VK_MBUTTON] &= ~0x80;
1156 Msg.message = WM_MBUTTONUP;
1157 CurInfo->ButtonsDown &= ~MK_MBUTTON;
1158 MsqInsertSystemMessage(&Msg);
1159 }
1160 if(mi->dwFlags & MOUSEEVENTF_RIGHTDOWN)
1161 {
1162 gQueueKeyStateTable[VK_RBUTTON] |= 0xc0;
1163 Msg.message = SwapBtnMsg[0][!SwapButtons];
1164 CurInfo->ButtonsDown |= SwapBtn[!SwapButtons];
1165 MsqInsertSystemMessage(&Msg);
1166 }
1167 else if(mi->dwFlags & MOUSEEVENTF_RIGHTUP)
1168 {
1169 gQueueKeyStateTable[VK_RBUTTON] &= ~0x80;
1170 Msg.message = SwapBtnMsg[1][!SwapButtons];
1171 CurInfo->ButtonsDown &= ~SwapBtn[!SwapButtons];
1172 MsqInsertSystemMessage(&Msg);
1173 }
1174
1175 if((mi->dwFlags & (MOUSEEVENTF_XDOWN | MOUSEEVENTF_XUP)) &&
1176 (mi->dwFlags & MOUSEEVENTF_WHEEL))
1177 {
1178 /* fail because both types of events use the mouseData field */
1179 return FALSE;
1180 }
1181
1182 if(mi->dwFlags & MOUSEEVENTF_XDOWN)
1183 {
1184 Msg.message = WM_XBUTTONDOWN;
1185 if(mi->mouseData & XBUTTON1)
1186 {
1187 gQueueKeyStateTable[VK_XBUTTON1] |= 0xc0;
1188 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
1189 CurInfo->ButtonsDown |= XBUTTON1;
1190 MsqInsertSystemMessage(&Msg);
1191 }
1192 if(mi->mouseData & XBUTTON2)
1193 {
1194 gQueueKeyStateTable[VK_XBUTTON2] |= 0xc0;
1195 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
1196 CurInfo->ButtonsDown |= XBUTTON2;
1197 MsqInsertSystemMessage(&Msg);
1198 }
1199 }
1200 else if(mi->dwFlags & MOUSEEVENTF_XUP)
1201 {
1202 Msg.message = WM_XBUTTONUP;
1203 if(mi->mouseData & XBUTTON1)
1204 {
1205 gQueueKeyStateTable[VK_XBUTTON1] &= ~0x80;
1206 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
1207 CurInfo->ButtonsDown &= ~XBUTTON1;
1208 MsqInsertSystemMessage(&Msg);
1209 }
1210 if(mi->mouseData & XBUTTON2)
1211 {
1212 gQueueKeyStateTable[VK_XBUTTON2] &= ~0x80;
1213 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
1214 CurInfo->ButtonsDown &= ~XBUTTON2;
1215 MsqInsertSystemMessage(&Msg);
1216 }
1217 }
1218 if(mi->dwFlags & MOUSEEVENTF_WHEEL)
1219 {
1220 Msg.message = WM_MOUSEWHEEL;
1221 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, mi->mouseData);
1222 MsqInsertSystemMessage(&Msg);
1223 }
1224
1225 return TRUE;
1226 }
1227
1228 BOOL FASTCALL
1229 IntKeyboardInput(KEYBDINPUT *ki)
1230 {
1231 PUSER_MESSAGE_QUEUE FocusMessageQueue;
1232 PTHREADINFO pti;
1233 MSG Msg;
1234 LARGE_INTEGER LargeTickCount;
1235 KBDLLHOOKSTRUCT KbdHookData;
1236 WORD flags, wVkStripped, wVkL, wVkR, wVk = ki->wVk, vk_hook = ki->wVk;
1237 BOOLEAN Entered = FALSE;
1238
1239 Msg.lParam = 0;
1240
1241 // Condition may arise when calling MsqPostMessage and waiting for an event.
1242 if (!UserIsEntered())
1243 {
1244 // Fixme: Not sure ATM if this thread is locked.
1245 UserEnterExclusive();
1246 Entered = TRUE;
1247 }
1248
1249 wVk = LOBYTE(wVk);
1250 Msg.wParam = wVk;
1251 flags = LOBYTE(ki->wScan);
1252
1253 if (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) flags |= KF_EXTENDED;
1254 /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
1255
1256 /* strip left/right for menu, control, shift */
1257 switch (wVk)
1258 {
1259 case VK_MENU:
1260 case VK_LMENU:
1261 case VK_RMENU:
1262 wVk = (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) ? VK_RMENU : VK_LMENU;
1263 wVkStripped = VK_MENU;
1264 wVkL = VK_LMENU;
1265 wVkR = VK_RMENU;
1266 break;
1267 case VK_CONTROL:
1268 case VK_LCONTROL:
1269 case VK_RCONTROL:
1270 wVk = (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) ? VK_RCONTROL : VK_LCONTROL;
1271 wVkStripped = VK_CONTROL;
1272 wVkL = VK_LCONTROL;
1273 wVkR = VK_RCONTROL;
1274 break;
1275 case VK_SHIFT:
1276 case VK_LSHIFT:
1277 case VK_RSHIFT:
1278 wVk = (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) ? VK_RSHIFT : VK_LSHIFT;
1279 wVkStripped = VK_SHIFT;
1280 wVkL = VK_LSHIFT;
1281 wVkR = VK_RSHIFT;
1282 break;
1283 default:
1284 wVkStripped = wVkL = wVkR = wVk;
1285 }
1286
1287 if (ki->dwFlags & KEYEVENTF_KEYUP)
1288 {
1289 Msg.message = WM_KEYUP;
1290 if ((gQueueKeyStateTable[VK_MENU] & 0x80) &&
1291 ((wVkStripped == VK_MENU) || (wVkStripped == VK_CONTROL)
1292 || !(gQueueKeyStateTable[VK_CONTROL] & 0x80)))
1293 {
1294 if( TrackSysKey == VK_MENU || /* <ALT>-down/<ALT>-up sequence */
1295 (wVkStripped != VK_MENU)) /* <ALT>-down...<something else>-up */
1296 Msg.message = WM_SYSKEYUP;
1297 TrackSysKey = 0;
1298 }
1299 flags |= KF_REPEAT | KF_UP;
1300 }
1301 else
1302 {
1303 Msg.message = WM_KEYDOWN;
1304 if ((gQueueKeyStateTable[VK_MENU] & 0x80 || wVkStripped == VK_MENU) &&
1305 !(gQueueKeyStateTable[VK_CONTROL] & 0x80 || wVkStripped == VK_CONTROL))
1306 {
1307 Msg.message = WM_SYSKEYDOWN;
1308 TrackSysKey = wVkStripped;
1309 }
1310 if (!(ki->dwFlags & KEYEVENTF_UNICODE) && gQueueKeyStateTable[wVk] & 0x80) flags |= KF_REPEAT;
1311 }
1312
1313 if (ki->dwFlags & KEYEVENTF_UNICODE)
1314 {
1315 vk_hook = Msg.wParam = wVk = VK_PACKET;
1316 Msg.lParam = MAKELPARAM(1 /* repeat count */, ki->wScan);
1317 }
1318
1319 FocusMessageQueue = IntGetFocusMessageQueue();
1320
1321 Msg.hwnd = 0;
1322
1323 if (FocusMessageQueue && (FocusMessageQueue->FocusWindow != (HWND)0))
1324 Msg.hwnd = FocusMessageQueue->FocusWindow;
1325
1326 if (!ki->time)
1327 {
1328 KeQueryTickCount(&LargeTickCount);
1329 Msg.time = MsqCalculateMessageTime(&LargeTickCount);
1330 }
1331 else
1332 Msg.time = ki->time;
1333
1334 /* All messages have to contain the cursor point. */
1335 pti = PsGetCurrentThreadWin32Thread();
1336 Msg.pt = gpsi->ptCursor;
1337
1338 DPRINT1("Kbd Hook msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1339 Msg.message, vk_hook, Msg.lParam);
1340
1341 KbdHookData.vkCode = vk_hook;
1342 KbdHookData.scanCode = ki->wScan;
1343 KbdHookData.flags = flags >> 8;
1344 KbdHookData.time = Msg.time;
1345 KbdHookData.dwExtraInfo = ki->dwExtraInfo;
1346 if (co_HOOK_CallHooks(WH_KEYBOARD_LL, HC_ACTION, Msg.message, (LPARAM) &KbdHookData))
1347 {
1348 DPRINT("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1349 Msg.message, vk_hook, Msg.lParam);
1350 if (Entered) UserLeave();
1351 return FALSE;
1352 }
1353
1354 if (!(ki->dwFlags & KEYEVENTF_UNICODE))
1355 {
1356 if (ki->dwFlags & KEYEVENTF_KEYUP)
1357 {
1358 gQueueKeyStateTable[wVk] &= ~0x80;
1359 gQueueKeyStateTable[wVkStripped] = gQueueKeyStateTable[wVkL] | gQueueKeyStateTable[wVkR];
1360 }
1361 else
1362 {
1363 if (!(gQueueKeyStateTable[wVk] & 0x80)) gQueueKeyStateTable[wVk] ^= 0x01;
1364 gQueueKeyStateTable[wVk] |= 0xc0;
1365 gQueueKeyStateTable[wVkStripped] = gQueueKeyStateTable[wVkL] | gQueueKeyStateTable[wVkR];
1366 }
1367
1368 if (gQueueKeyStateTable[VK_MENU] & 0x80) flags |= KF_ALTDOWN;
1369
1370 if (wVkStripped == VK_SHIFT) flags &= ~KF_EXTENDED;
1371
1372 Msg.lParam = MAKELPARAM(1 /* repeat count */, flags);
1373 }
1374
1375 if (FocusMessageQueue == NULL)
1376 {
1377 DPRINT("No focus message queue\n");
1378 if (Entered) UserLeave();
1379 return FALSE;
1380 }
1381
1382 if (FocusMessageQueue->FocusWindow != (HWND)0)
1383 {
1384 Msg.hwnd = FocusMessageQueue->FocusWindow;
1385 DPRINT("Msg.hwnd = %x\n", Msg.hwnd);
1386
1387 FocusMessageQueue->Desktop->pDeskInfo->LastInputWasKbd = TRUE;
1388
1389 Msg.pt = gpsi->ptCursor;
1390
1391 MsqPostMessage(FocusMessageQueue, &Msg, FALSE, QS_KEY);
1392 }
1393 else
1394 {
1395 DPRINT("Invalid focus window handle\n");
1396 }
1397
1398 if (Entered) UserLeave();
1399
1400 return TRUE;
1401 }
1402
1403 BOOL FASTCALL
1404 UserAttachThreadInput( PTHREADINFO pti, PTHREADINFO ptiTo, BOOL fAttach)
1405 {
1406 PATTACHINFO pai;
1407
1408 /* Can not be the same thread.*/
1409 if (pti == ptiTo) return FALSE;
1410
1411 /* Do not attach to system threads or between different desktops. */
1412 if ( pti->TIF_flags & TIF_DONTATTACHQUEUE ||
1413 ptiTo->TIF_flags & TIF_DONTATTACHQUEUE ||
1414 pti->rpdesk != ptiTo->rpdesk )
1415 return FALSE;
1416
1417 /* If Attach set, allocate and link. */
1418 if ( fAttach )
1419 {
1420 pai = ExAllocatePoolWithTag(PagedPool, sizeof(ATTACHINFO), TAG_ATTACHINFO);
1421 if ( !pai ) return FALSE;
1422
1423 pai->paiNext = gpai;
1424 pai->pti1 = pti;
1425 pai->pti2 = ptiTo;
1426 gpai = pai;
1427 }
1428 else /* If clear, unlink and free it. */
1429 {
1430 PATTACHINFO paiprev = NULL;
1431
1432 if ( !gpai ) return FALSE;
1433
1434 pai = gpai;
1435
1436 /* Search list and free if found or return false. */
1437 do
1438 {
1439 if ( pai->pti2 == ptiTo && pai->pti1 == pti ) break;
1440 paiprev = pai;
1441 pai = pai->paiNext;
1442 } while (pai);
1443
1444 if ( !pai ) return FALSE;
1445
1446 if (paiprev) paiprev->paiNext = pai->paiNext;
1447
1448 ExFreePoolWithTag(pai, TAG_ATTACHINFO);
1449 }
1450
1451 return TRUE;
1452 }
1453
1454 UINT
1455 APIENTRY
1456 NtUserSendInput(
1457 UINT nInputs,
1458 LPINPUT pInput,
1459 INT cbSize)
1460 {
1461 PTHREADINFO W32Thread;
1462 UINT cnt;
1463 DECLARE_RETURN(UINT);
1464
1465 DPRINT("Enter NtUserSendInput\n");
1466 UserEnterExclusive();
1467
1468 W32Thread = PsGetCurrentThreadWin32Thread();
1469 ASSERT(W32Thread);
1470
1471 if(!W32Thread->rpdesk)
1472 {
1473 RETURN( 0);
1474 }
1475
1476 if(!nInputs || !pInput || (cbSize != sizeof(INPUT)))
1477 {
1478 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1479 RETURN( 0);
1480 }
1481
1482 /*
1483 * FIXME - check access rights of the window station
1484 * e.g. services running in the service window station cannot block input
1485 */
1486 if(!ThreadHasInputAccess(W32Thread) ||
1487 !IntIsActiveDesktop(W32Thread->rpdesk))
1488 {
1489 SetLastWin32Error(ERROR_ACCESS_DENIED);
1490 RETURN( 0);
1491 }
1492
1493 cnt = 0;
1494 while(nInputs--)
1495 {
1496 INPUT SafeInput;
1497 NTSTATUS Status;
1498
1499 Status = MmCopyFromCaller(&SafeInput, pInput++, sizeof(INPUT));
1500 if(!NT_SUCCESS(Status))
1501 {
1502 SetLastNtError(Status);
1503 RETURN( cnt);
1504 }
1505
1506 switch(SafeInput.type)
1507 {
1508 case INPUT_MOUSE:
1509 if(IntMouseInput(&SafeInput.mi))
1510 {
1511 cnt++;
1512 }
1513 break;
1514 case INPUT_KEYBOARD:
1515 if(IntKeyboardInput(&SafeInput.ki))
1516 {
1517 cnt++;
1518 }
1519 break;
1520 case INPUT_HARDWARE:
1521 break;
1522 #ifndef NDEBUG
1523
1524 default:
1525 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput.type);
1526 break;
1527 #endif
1528
1529 }
1530 }
1531
1532 RETURN( cnt);
1533
1534 CLEANUP:
1535 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_);
1536 UserLeave();
1537 END_CLEANUP;
1538 }
1539
1540 /* EOF */