[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 <w32k.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 and convert to screen location */
124 mi.dwFlags |= MOUSEEVENTF_ABSOLUTE;
125 mi.dx = mi.dx / (65535 / (UserGetSystemMetrics(SM_CXVIRTUALSCREEN) - 1));
126 mi.dy = mi.dy / (65535 / (UserGetSystemMetrics(SM_CYVIRTUALSCREEN) - 1));
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 InitializeObjectAttributes(&MouseObjectAttributes,
210 &MouseDeviceName,
211 0,
212 NULL,
213 NULL);
214 do
215 {
216 LARGE_INTEGER DueTime;
217 KEVENT Event;
218 DueTime.QuadPart = (LONGLONG)(-10000000);
219 KeInitializeEvent(&Event, NotificationEvent, FALSE);
220 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime);
221 Status = NtOpenFile(&MouseDeviceHandle,
222 FILE_ALL_ACCESS,
223 &MouseObjectAttributes,
224 &Iosb,
225 0,
226 FILE_SYNCHRONOUS_IO_ALERT);
227 } while (!NT_SUCCESS(Status));
228
229 KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
230 LOW_REALTIME_PRIORITY + 3);
231
232 for(;;)
233 {
234 /*
235 * Wait to start input.
236 */
237 DPRINT("Mouse Input Thread Waiting for start event\n");
238 Status = KeWaitForSingleObject(&InputThreadsStart,
239 0,
240 KernelMode,
241 TRUE,
242 NULL);
243 DPRINT("Mouse Input Thread Starting...\n");
244
245 /*FIXME: Does mouse attributes need to be used for anything */
246 Status = NtDeviceIoControlFile(MouseDeviceHandle,
247 NULL,
248 NULL,
249 NULL,
250 &Iosb,
251 IOCTL_MOUSE_QUERY_ATTRIBUTES,
252 &MouseAttr, sizeof(MOUSE_ATTRIBUTES),
253 NULL, 0);
254 if(!NT_SUCCESS(Status))
255 {
256 DPRINT("Failed to get mouse attributes\n");
257 }
258
259 /*
260 * Receive and process mouse input.
261 */
262 while(InputThreadsRunning)
263 {
264 MOUSE_INPUT_DATA MouseInput;
265 Status = NtReadFile(MouseDeviceHandle,
266 NULL,
267 NULL,
268 NULL,
269 &Iosb,
270 &MouseInput,
271 sizeof(MOUSE_INPUT_DATA),
272 NULL,
273 NULL);
274 if(Status == STATUS_ALERTED && !InputThreadsRunning)
275 {
276 break;
277 }
278 if(Status == STATUS_PENDING)
279 {
280 NtWaitForSingleObject(MouseDeviceHandle, FALSE, NULL);
281 Status = Iosb.Status;
282 }
283 if(!NT_SUCCESS(Status))
284 {
285 DPRINT1("Win32K: Failed to read from mouse.\n");
286 return; //(Status);
287 }
288 DPRINT("MouseEvent\n");
289 IntLastInputTick(TRUE);
290
291 UserEnterExclusive();
292
293 ProcessMouseInputData(&MouseInput, Iosb.Information / sizeof(MOUSE_INPUT_DATA));
294
295 UserLeave();
296 }
297 DPRINT("Mouse Input Thread Stopped...\n");
298 }
299 }
300
301 /* Returns a value that indicates if the key is a modifier key, and
302 * which one.
303 */
304 static UINT APIENTRY
305 IntKeyboardGetModifiers(KEYBOARD_INPUT_DATA *InputData)
306 {
307 if (InputData->Flags & KEY_E1)
308 return 0;
309
310 if (!(InputData->Flags & KEY_E0))
311 {
312 switch (InputData->MakeCode)
313 {
314 case 0x2a: /* left shift */
315 case 0x36: /* right shift */
316 return MOD_SHIFT;
317
318 case 0x1d: /* left control */
319 return MOD_CONTROL;
320
321 case 0x38: /* left alt */
322 return MOD_ALT;
323
324 default:
325 return 0;
326 }
327 }
328 else
329 {
330 switch (InputData->MakeCode)
331 {
332 case 0x1d: /* right control */
333 return MOD_CONTROL;
334
335 case 0x38: /* right alt */
336 return MOD_ALT;
337
338 case 0x5b: /* left gui (windows) */
339 case 0x5c: /* right gui (windows) */
340 return MOD_WIN;
341
342 default:
343 return 0;
344 }
345 }
346 }
347
348 /* Asks the keyboard driver to send a small table that shows which
349 * lights should connect with which scancodes
350 */
351 static NTSTATUS APIENTRY
352 IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle,
353 PKEYBOARD_INDICATOR_TRANSLATION *IndicatorTrans)
354 {
355 NTSTATUS Status;
356 DWORD Size = 0;
357 IO_STATUS_BLOCK Block;
358 PKEYBOARD_INDICATOR_TRANSLATION Ret;
359
360 Size = sizeof(KEYBOARD_INDICATOR_TRANSLATION);
361
362 Ret = ExAllocatePoolWithTag(PagedPool,
363 Size,
364 TAG_KEYBOARD);
365
366 while (Ret)
367 {
368 Status = NtDeviceIoControlFile(KeyboardDeviceHandle,
369 NULL,
370 NULL,
371 NULL,
372 &Block,
373 IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION,
374 NULL, 0,
375 Ret, Size);
376
377 if (Status != STATUS_BUFFER_TOO_SMALL)
378 break;
379
380 ExFreePoolWithTag(Ret, TAG_KEYBOARD);
381
382 Size += sizeof(KEYBOARD_INDICATOR_TRANSLATION);
383
384 Ret = ExAllocatePoolWithTag(PagedPool,
385 Size,
386 TAG_KEYBOARD);
387 }
388
389 if (!Ret)
390 return STATUS_INSUFFICIENT_RESOURCES;
391
392 if (Status != STATUS_SUCCESS)
393 {
394 ExFreePoolWithTag(Ret, TAG_KEYBOARD);
395 return Status;
396 }
397
398 *IndicatorTrans = Ret;
399 return Status;
400 }
401
402 /* Sends the keyboard commands to turn on/off the lights.
403 */
404 static NTSTATUS APIENTRY
405 IntKeyboardUpdateLeds(HANDLE KeyboardDeviceHandle,
406 PKEYBOARD_INPUT_DATA KeyInput,
407 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans)
408 {
409 NTSTATUS Status;
410 UINT Count;
411 static KEYBOARD_INDICATOR_PARAMETERS Indicators;
412 IO_STATUS_BLOCK Block;
413
414 if (!IndicatorTrans)
415 return STATUS_NOT_SUPPORTED;
416
417 if (KeyInput->Flags & (KEY_E0 | KEY_E1 | KEY_BREAK))
418 return STATUS_SUCCESS;
419
420 for (Count = 0; Count < IndicatorTrans->NumberOfIndicatorKeys; Count++)
421 {
422 if (KeyInput->MakeCode == IndicatorTrans->IndicatorList[Count].MakeCode)
423 {
424 Indicators.LedFlags ^=
425 IndicatorTrans->IndicatorList[Count].IndicatorFlags;
426
427 /* Update the lights on the hardware */
428
429 Status = NtDeviceIoControlFile(KeyboardDeviceHandle,
430 NULL,
431 NULL,
432 NULL,
433 &Block,
434 IOCTL_KEYBOARD_SET_INDICATORS,
435 &Indicators, sizeof(Indicators),
436 NULL, 0);
437
438 return Status;
439 }
440 }
441
442 return STATUS_SUCCESS;
443 }
444
445 static VOID APIENTRY
446 IntKeyboardSendWinKeyMsg()
447 {
448 PWINDOW_OBJECT Window;
449 MSG Mesg;
450
451 if (!(Window = UserGetWindowObject(InputWindowStation->ShellWindow)))
452 {
453 DPRINT1("Couldn't find window to send Windows key message!\n");
454 return;
455 }
456
457 Mesg.hwnd = InputWindowStation->ShellWindow;
458 Mesg.message = WM_SYSCOMMAND;
459 Mesg.wParam = SC_TASKLIST;
460 Mesg.lParam = 0;
461
462 /* The QS_HOTKEY is just a guess */
463 MsqPostMessage(Window->MessageQueue, &Mesg, FALSE, QS_HOTKEY);
464 }
465
466 static VOID APIENTRY
467 co_IntKeyboardSendAltKeyMsg()
468 {
469 co_MsqPostKeyboardMessage(WM_SYSCOMMAND,SC_KEYMENU,0);
470 }
471
472 static VOID APIENTRY
473 KeyboardThreadMain(PVOID StartContext)
474 {
475 UNICODE_STRING KeyboardDeviceName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardClass0");
476 OBJECT_ATTRIBUTES KeyboardObjectAttributes;
477 IO_STATUS_BLOCK Iosb;
478 NTSTATUS Status;
479 MSG msg;
480 PUSER_MESSAGE_QUEUE FocusQueue;
481 struct _ETHREAD *FocusThread;
482
483 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans = NULL;
484 UINT ModifierState = 0;
485 USHORT LastMakeCode = 0;
486 USHORT LastFlags = 0;
487 UINT RepeatCount = 0;
488
489 InitializeObjectAttributes(&KeyboardObjectAttributes,
490 &KeyboardDeviceName,
491 0,
492 NULL,
493 NULL);
494 do
495 {
496 LARGE_INTEGER DueTime;
497 KEVENT Event;
498 DueTime.QuadPart = (LONGLONG)(-10000000);
499 KeInitializeEvent(&Event, NotificationEvent, FALSE);
500 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime);
501 Status = NtOpenFile(&KeyboardDeviceHandle,
502 FILE_ALL_ACCESS,
503 &KeyboardObjectAttributes,
504 &Iosb,
505 0,
506 FILE_SYNCHRONOUS_IO_ALERT);
507 } while (!NT_SUCCESS(Status));
508
509 /* Not sure if converting this thread to a win32 thread is such
510 a great idea. Since we're posting keyboard messages to the focus
511 window message queue, we'll be (indirectly) doing sendmessage
512 stuff from this thread (for WH_KEYBOARD_LL processing), which
513 means we need our own message queue. If keyboard messages were
514 instead queued to the system message queue, the thread removing
515 the message from the system message queue would be responsible
516 for WH_KEYBOARD_LL processing and we wouldn't need this thread
517 to be a win32 thread. */
518 Status = Win32kInitWin32Thread(PsGetCurrentThread());
519 if (!NT_SUCCESS(Status))
520 {
521 DPRINT1("Win32K: Failed making keyboard thread a win32 thread.\n");
522 return; //(Status);
523 }
524
525 KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
526 LOW_REALTIME_PRIORITY + 3);
527
528 IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle,
529 &IndicatorTrans);
530
531 for (;;)
532 {
533 /*
534 * Wait to start input.
535 */
536 DPRINT( "Keyboard Input Thread Waiting for start event\n" );
537 Status = KeWaitForSingleObject(&InputThreadsStart,
538 0,
539 KernelMode,
540 TRUE,
541 NULL);
542
543 DPRINT( "Keyboard Input Thread Starting...\n" );
544 /*
545 * Receive and process keyboard input.
546 */
547 while (InputThreadsRunning)
548 {
549 BOOLEAN NumKeys = 1;
550 BOOLEAN bLeftAlt;
551 KEYBOARD_INPUT_DATA KeyInput;
552 KEYBOARD_INPUT_DATA NextKeyInput;
553 LPARAM lParam = 0;
554 UINT fsModifiers, fsNextModifiers;
555 struct _ETHREAD *Thread;
556 HWND hWnd;
557 int id;
558
559 DPRINT("KeyInput @ %08x\n", &KeyInput);
560
561 Status = NtReadFile (KeyboardDeviceHandle,
562 NULL,
563 NULL,
564 NULL,
565 &Iosb,
566 &KeyInput,
567 sizeof(KEYBOARD_INPUT_DATA),
568 NULL,
569 NULL);
570
571 if(Status == STATUS_ALERTED && !InputThreadsRunning)
572 {
573 break;
574 }
575 if(Status == STATUS_PENDING)
576 {
577 NtWaitForSingleObject(KeyboardDeviceHandle, FALSE, NULL);
578 Status = Iosb.Status;
579 }
580 if(!NT_SUCCESS(Status))
581 {
582 DPRINT1("Win32K: Failed to read from mouse.\n");
583 return; //(Status);
584 }
585
586 DPRINT("KeyRaw: %s %04x\n",
587 (KeyInput.Flags & KEY_BREAK) ? "up" : "down",
588 KeyInput.MakeCode );
589
590 if (Status == STATUS_ALERTED && !InputThreadsRunning)
591 break;
592
593 if (!NT_SUCCESS(Status))
594 {
595 DPRINT1("Win32K: Failed to read from keyboard.\n");
596 return; //(Status);
597 }
598
599 /* Set LastInputTick */
600 IntLastInputTick(TRUE);
601
602 /* Update modifier state */
603 fsModifiers = IntKeyboardGetModifiers(&KeyInput);
604
605 if (fsModifiers)
606 {
607 if (KeyInput.Flags & KEY_BREAK)
608 {
609 ModifierState &= ~fsModifiers;
610 if(fsModifiers == MOD_ALT)
611 {
612 if(KeyInput.Flags & KEY_E0)
613 {
614 gQueueKeyStateTable[VK_RMENU] = 0;
615 }
616 else
617 {
618 gQueueKeyStateTable[VK_LMENU] = 0;
619 }
620 if (gQueueKeyStateTable[VK_RMENU] == 0 &&
621 gQueueKeyStateTable[VK_LMENU] == 0)
622 {
623 gQueueKeyStateTable[VK_MENU] = 0;
624 }
625 }
626 }
627 else
628 {
629 ModifierState |= fsModifiers;
630
631 if (ModifierState == fsModifiers &&
632 (fsModifiers == MOD_ALT || fsModifiers == MOD_WIN))
633 {
634 /* First send out special notifications
635 * (For alt, the message that turns on accelerator
636 * display, not sure what for win. Both TODO though.)
637 */
638 bLeftAlt = FALSE;
639 if(fsModifiers == MOD_ALT)
640 {
641 if(KeyInput.Flags & KEY_E0)
642 {
643 gQueueKeyStateTable[VK_RMENU] = 0x80;
644 }
645 else
646 {
647 gQueueKeyStateTable[VK_LMENU] = 0x80;
648 bLeftAlt = TRUE;
649 }
650
651 gQueueKeyStateTable[VK_MENU] = 0x80;
652 }
653
654 /* Read the next key before sending this one */
655 do
656 {
657 Status = NtReadFile (KeyboardDeviceHandle,
658 NULL,
659 NULL,
660 NULL,
661 &Iosb,
662 &NextKeyInput,
663 sizeof(KEYBOARD_INPUT_DATA),
664 NULL,
665 NULL);
666 DPRINT("KeyRaw: %s %04x\n",
667 (NextKeyInput.Flags & KEY_BREAK) ? "up":"down",
668 NextKeyInput.MakeCode );
669
670 if (Status == STATUS_ALERTED && !InputThreadsRunning)
671 goto KeyboardEscape;
672
673 }
674 while ((!(NextKeyInput.Flags & KEY_BREAK)) &&
675 NextKeyInput.MakeCode == KeyInput.MakeCode);
676 /* ^ Ignore repeats, they'll be KEY_MAKE and the same
677 * code. I'm not caring about the counting, not sure
678 * if that matters. I think not.
679 */
680
681 /* If the ModifierState is now empty again, send a
682 * special notification and eat both keypresses
683 */
684
685 fsNextModifiers = IntKeyboardGetModifiers(&NextKeyInput);
686
687 if (fsNextModifiers)
688 ModifierState ^= fsNextModifiers;
689
690 if (ModifierState == 0)
691 {
692 if (fsModifiers == MOD_WIN)
693 IntKeyboardSendWinKeyMsg();
694 else if (fsModifiers == MOD_ALT)
695 {
696 gQueueKeyStateTable[VK_MENU] = 0;
697 if(bLeftAlt)
698 {
699 gQueueKeyStateTable[VK_LMENU] = 0;
700 }
701 else
702 {
703 gQueueKeyStateTable[VK_RMENU] = 0;
704 }
705 co_IntKeyboardSendAltKeyMsg();
706 }
707 continue;
708 }
709
710 NumKeys = 2;
711 }
712 }
713 }
714
715 for (;NumKeys;memcpy(&KeyInput, &NextKeyInput, sizeof(KeyInput)),
716 NumKeys--)
717 {
718 lParam = 0;
719
720 IntKeyboardUpdateLeds(KeyboardDeviceHandle,
721 &KeyInput,
722 IndicatorTrans);
723
724 /* While we are working, we set up lParam. The format is:
725 * 0-15: The number of times this key has autorepeated
726 * 16-23: The keyboard scancode
727 * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
728 * Note that E1 is only used for PAUSE (E1-1D-45) and
729 * E0-45 happens not to be anything.
730 * 29: Alt is pressed ('Context code')
731 * 30: Previous state, if the key was down before this message
732 * This is a cheap way to ignore autorepeat keys
733 * 31: 1 if the key is being pressed
734 */
735
736 /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
737 * and it's the same key as the last one, increase the repeat
738 * count.
739 */
740
741 if (!(KeyInput.Flags & KEY_BREAK))
742 {
743 if (((KeyInput.Flags & (KEY_E0 | KEY_E1)) == LastFlags) &&
744 (KeyInput.MakeCode == LastMakeCode))
745 {
746 RepeatCount++;
747 lParam |= (1 << 30);
748 }
749 else
750 {
751 RepeatCount = 1;
752 LastFlags = KeyInput.Flags & (KEY_E0 | KEY_E1);
753 LastMakeCode = KeyInput.MakeCode;
754 }
755 }
756 else
757 {
758 LastFlags = 0;
759 LastMakeCode = 0; /* Should never match */
760 lParam |= (1 << 30) | (1 << 31);
761 }
762
763 lParam |= RepeatCount;
764
765 lParam |= (KeyInput.MakeCode & 0xff) << 16;
766
767 if (KeyInput.Flags & KEY_E0)
768 lParam |= (1 << 24);
769
770 if (ModifierState & MOD_ALT)
771 {
772 lParam |= (1 << 29);
773
774 if (!(KeyInput.Flags & KEY_BREAK))
775 msg.message = WM_SYSKEYDOWN;
776 else
777 msg.message = WM_SYSKEYUP;
778 }
779 else
780 {
781 if (!(KeyInput.Flags & KEY_BREAK))
782 msg.message = WM_KEYDOWN;
783 else
784 msg.message = WM_KEYUP;
785 }
786
787 /* Find the target thread whose locale is in effect */
788 FocusQueue = IntGetFocusMessageQueue();
789
790 /* This might cause us to lose hot keys, which are important
791 * (ctrl-alt-del secure attention sequence). Not sure if it
792 * can happen though.
793 */
794 if (!FocusQueue)
795 continue;
796
797 msg.lParam = lParam;
798 msg.hwnd = FocusQueue->FocusWindow;
799
800 FocusThread = FocusQueue->Thread;
801
802 if (!(FocusThread && FocusThread->Tcb.Win32Thread &&
803 ((PTHREADINFO)FocusThread->Tcb.Win32Thread)->KeyboardLayout))
804 continue;
805
806 /* This function uses lParam to fill wParam according to the
807 * keyboard layout in use.
808 */
809 W32kKeyProcessMessage(&msg,
810 ((PTHREADINFO)FocusThread->Tcb.Win32Thread)->KeyboardLayout->KBTables,
811 KeyInput.Flags & KEY_E0 ? 0xE0 :
812 (KeyInput.Flags & KEY_E1 ? 0xE1 : 0));
813
814 if (GetHotKey(ModifierState,
815 msg.wParam,
816 &Thread,
817 &hWnd,
818 &id))
819 {
820 if (!(KeyInput.Flags & KEY_BREAK))
821 {
822 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd, id);
823 MsqPostHotKeyMessage (Thread,
824 hWnd,
825 (WPARAM)id,
826 MAKELPARAM((WORD)ModifierState,
827 (WORD)msg.wParam));
828 }
829 continue; /* Eat key up motion too */
830 }
831
832 /*
833 * Post a keyboard message.
834 */
835 co_MsqPostKeyboardMessage(msg.message,msg.wParam,msg.lParam);
836 }
837 }
838
839 KeyboardEscape:
840 DPRINT( "KeyboardInput Thread Stopped...\n" );
841 }
842 }
843
844
845 static PVOID Objects[2];
846 /*
847 Raw Input Thread.
848 Since this relies on InputThreadsStart, just fake it.
849 */
850 static VOID APIENTRY
851 RawInputThreadMain(PVOID StartContext)
852 {
853 NTSTATUS Status;
854 LARGE_INTEGER DueTime;
855
856 DueTime.QuadPart = (LONGLONG)(-10000000);
857
858 do
859 {
860 KEVENT Event;
861 KeInitializeEvent(&Event, NotificationEvent, FALSE);
862 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime);
863 } while (!NT_SUCCESS(Status));
864
865
866 Objects[0] = &InputThreadsStart;
867
868 MasterTimer = ExAllocatePoolWithTag(NonPagedPool, sizeof(KTIMER), TAG_INPUT);
869 if (!MasterTimer)
870 {
871 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
872 return;
873 }
874 KeInitializeTimer(MasterTimer);
875 Objects[1] = MasterTimer;
876
877 // This thread requires win32k!
878 Status = Win32kInitWin32Thread(PsGetCurrentThread());
879 if (!NT_SUCCESS(Status))
880 {
881 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
882 return; //(Status);
883 }
884
885 ptiRawInput = PsGetCurrentThreadWin32Thread();
886 DPRINT("\nRaw Input Thread 0x%x \n", ptiRawInput);
887
888
889 KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
890 LOW_REALTIME_PRIORITY + 3);
891
892 UserEnterExclusive();
893 StartTheTimers();
894 UserLeave();
895
896 //
897 // ATM, we just have one job to handle, merge the other two later.
898 //
899 for(;;)
900 {
901 DPRINT( "Raw Input Thread Waiting for start event\n" );
902
903 Status = KeWaitForMultipleObjects( 2,
904 Objects,
905 WaitAll, //WaitAny,
906 WrUserRequest,
907 KernelMode,
908 TRUE,
909 NULL,
910 NULL);
911 DPRINT( "Raw Input Thread Starting...\n" );
912
913 ProcessTimers();
914 }
915 DPRINT1("Raw Input Thread Exit!\n");
916 }
917
918 NTSTATUS FASTCALL
919 InitInputImpl(VOID)
920 {
921 NTSTATUS Status;
922
923 KeInitializeEvent(&InputThreadsStart, NotificationEvent, FALSE);
924
925 /* Initialize the default keyboard layout */
926 if(!UserInitDefaultKeyboardLayout())
927 {
928 DPRINT1("Failed to initialize default keyboard layout!\n");
929 }
930
931 Status = PsCreateSystemThread(&RawInputThreadHandle,
932 THREAD_ALL_ACCESS,
933 NULL,
934 NULL,
935 &RawInputThreadId,
936 RawInputThreadMain,
937 NULL);
938 if (!NT_SUCCESS(Status))
939 {
940 DPRINT1("Win32K: Failed to create raw thread.\n");
941 }
942
943 Status = PsCreateSystemThread(&KeyboardThreadHandle,
944 THREAD_ALL_ACCESS,
945 NULL,
946 NULL,
947 &KeyboardThreadId,
948 KeyboardThreadMain,
949 NULL);
950 if (!NT_SUCCESS(Status))
951 {
952 DPRINT1("Win32K: Failed to create keyboard thread.\n");
953 }
954
955 Status = PsCreateSystemThread(&MouseThreadHandle,
956 THREAD_ALL_ACCESS,
957 NULL,
958 NULL,
959 &MouseThreadId,
960 MouseThreadMain,
961 NULL);
962 if (!NT_SUCCESS(Status))
963 {
964 DPRINT1("Win32K: Failed to create mouse thread.\n");
965 }
966
967 InputThreadsRunning = TRUE;
968 KeSetEvent(&InputThreadsStart, IO_NO_INCREMENT, FALSE);
969
970 return STATUS_SUCCESS;
971 }
972
973 NTSTATUS FASTCALL
974 CleanupInputImp(VOID)
975 {
976 return(STATUS_SUCCESS);
977 }
978
979 BOOL
980 APIENTRY
981 NtUserDragDetect(
982 HWND hWnd,
983 POINT pt) // Just like the User call.
984 {
985 UNIMPLEMENTED
986 return 0;
987 }
988
989 BOOL FASTCALL
990 IntBlockInput(PTHREADINFO W32Thread, BOOL BlockIt)
991 {
992 PTHREADINFO OldBlock;
993 ASSERT(W32Thread);
994
995 if(!W32Thread->Desktop || ((W32Thread->TIF_flags & TIF_INCLEANUP) && BlockIt))
996 {
997 /*
998 * fail blocking if exiting the thread
999 */
1000
1001 return FALSE;
1002 }
1003
1004 /*
1005 * FIXME - check access rights of the window station
1006 * e.g. services running in the service window station cannot block input
1007 */
1008 if(!ThreadHasInputAccess(W32Thread) ||
1009 !IntIsActiveDesktop(W32Thread->Desktop))
1010 {
1011 SetLastWin32Error(ERROR_ACCESS_DENIED);
1012 return FALSE;
1013 }
1014
1015 ASSERT(W32Thread->Desktop);
1016 OldBlock = W32Thread->Desktop->BlockInputThread;
1017 if(OldBlock)
1018 {
1019 if(OldBlock != W32Thread)
1020 {
1021 SetLastWin32Error(ERROR_ACCESS_DENIED);
1022 return FALSE;
1023 }
1024 W32Thread->Desktop->BlockInputThread = (BlockIt ? W32Thread : NULL);
1025 return OldBlock == NULL;
1026 }
1027
1028 W32Thread->Desktop->BlockInputThread = (BlockIt ? W32Thread : NULL);
1029 return OldBlock == NULL;
1030 }
1031
1032 BOOL
1033 APIENTRY
1034 NtUserBlockInput(
1035 BOOL BlockIt)
1036 {
1037 DECLARE_RETURN(BOOLEAN);
1038
1039 DPRINT("Enter NtUserBlockInput\n");
1040 UserEnterExclusive();
1041
1042 RETURN( IntBlockInput(PsGetCurrentThreadWin32Thread(), BlockIt));
1043
1044 CLEANUP:
1045 DPRINT("Leave NtUserBlockInput, ret=%i\n",_ret_);
1046 UserLeave();
1047 END_CLEANUP;
1048 }
1049
1050 BOOL FASTCALL
1051 IntMouseInput(MOUSEINPUT *mi)
1052 {
1053 const UINT SwapBtnMsg[2][2] =
1054 {
1055 {
1056 WM_LBUTTONDOWN, WM_RBUTTONDOWN
1057 },
1058 {WM_LBUTTONUP, WM_RBUTTONUP}
1059 };
1060 const WPARAM SwapBtn[2] =
1061 {
1062 MK_LBUTTON, MK_RBUTTON
1063 };
1064 POINT MousePos = {0}, OrgPos;
1065 PSYSTEM_CURSORINFO CurInfo;
1066 PWINSTATION_OBJECT WinSta;
1067 BOOL DoMove, SwapButtons;
1068 MSG Msg;
1069 SURFACE *psurf;
1070 SURFOBJ *pso;
1071 PDC dc;
1072 PWINDOW_OBJECT DesktopWindow;
1073
1074 #if 1
1075
1076 HDC hDC;
1077
1078 /* FIXME - get the screen dc from the window station or desktop */
1079 if(!(hDC = IntGetScreenDC()))
1080 {
1081 return FALSE;
1082 }
1083 #endif
1084
1085 ASSERT(mi);
1086 #if 0
1087
1088 WinSta = PsGetCurrentProcessWin32Process()->WindowStation;
1089 #else
1090 /* FIXME - ugly hack but as long as we're using this dumb callback from the
1091 mouse class driver, we can't access the window station from the calling
1092 process */
1093 WinSta = InputWindowStation;
1094 #endif
1095
1096 ASSERT(WinSta);
1097
1098 CurInfo = IntGetSysCursorInfo();
1099
1100 if(!mi->time)
1101 {
1102 LARGE_INTEGER LargeTickCount;
1103 KeQueryTickCount(&LargeTickCount);
1104 mi->time = MsqCalculateMessageTime(&LargeTickCount);
1105 }
1106
1107 SwapButtons = gspv.bMouseBtnSwap;
1108 DoMove = FALSE;
1109
1110 OrgPos = MousePos = gpsi->ptCursor;
1111
1112 if(mi->dwFlags & MOUSEEVENTF_MOVE)
1113 {
1114 if(mi->dwFlags & MOUSEEVENTF_ABSOLUTE)
1115 {
1116 MousePos.x = mi->dx;
1117 MousePos.y = mi->dy;
1118 }
1119 else
1120 {
1121 MousePos.x += mi->dx;
1122 MousePos.y += mi->dy;
1123 }
1124
1125 DesktopWindow = IntGetWindowObject(WinSta->ActiveDesktop->DesktopWindow);
1126
1127 if (DesktopWindow)
1128 {
1129 if(MousePos.x >= DesktopWindow->Wnd->rcClient.right)
1130 MousePos.x = DesktopWindow->Wnd->rcClient.right - 1;
1131 if(MousePos.y >= DesktopWindow->Wnd->rcClient.bottom)
1132 MousePos.y = DesktopWindow->Wnd->rcClient.bottom - 1;
1133 UserDereferenceObject(DesktopWindow);
1134 }
1135
1136 if(MousePos.x < 0)
1137 MousePos.x = 0;
1138 if(MousePos.y < 0)
1139 MousePos.y = 0;
1140
1141 if(CurInfo->CursorClipInfo.IsClipped)
1142 {
1143 /* The mouse cursor needs to be clipped */
1144
1145 if(MousePos.x >= (LONG)CurInfo->CursorClipInfo.Right)
1146 MousePos.x = (LONG)CurInfo->CursorClipInfo.Right;
1147 if(MousePos.x < (LONG)CurInfo->CursorClipInfo.Left)
1148 MousePos.x = (LONG)CurInfo->CursorClipInfo.Left;
1149 if(MousePos.y >= (LONG)CurInfo->CursorClipInfo.Bottom)
1150 MousePos.y = (LONG)CurInfo->CursorClipInfo.Bottom;
1151 if(MousePos.y < (LONG)CurInfo->CursorClipInfo.Top)
1152 MousePos.y = (LONG)CurInfo->CursorClipInfo.Top;
1153 }
1154
1155 DoMove = (MousePos.x != OrgPos.x || MousePos.y != OrgPos.y);
1156 }
1157
1158 if (DoMove)
1159 {
1160 dc = DC_LockDc(hDC);
1161 if (dc)
1162 {
1163 psurf = dc->dclevel.pSurface;
1164 if (psurf)
1165 {
1166 pso = &psurf->SurfObj;
1167
1168 if (CurInfo->ShowingCursor)
1169 {
1170 IntEngMovePointer(pso, MousePos.x, MousePos.y, &(GDIDEV(pso)->Pointer.Exclude));
1171 }
1172 /* Only now, update the info in the PDEVOBJ, so EngMovePointer can
1173 * use the old values to move the pointer image */
1174 gpsi->ptCursor.x = MousePos.x;
1175 gpsi->ptCursor.y = MousePos.y;
1176 }
1177
1178 DC_UnlockDc(dc);
1179 }
1180 }
1181
1182 /*
1183 * Insert the messages into the system queue
1184 */
1185
1186 Msg.wParam = CurInfo->ButtonsDown;
1187 Msg.lParam = MAKELPARAM(MousePos.x, MousePos.y);
1188 Msg.pt = MousePos;
1189
1190 if (gQueueKeyStateTable[VK_SHIFT] & 0xc0)
1191 {
1192 Msg.wParam |= MK_SHIFT;
1193 }
1194
1195 if (gQueueKeyStateTable[VK_CONTROL] & 0xc0)
1196 {
1197 Msg.wParam |= MK_CONTROL;
1198 }
1199
1200 if(DoMove)
1201 {
1202 Msg.message = WM_MOUSEMOVE;
1203 MsqInsertSystemMessage(&Msg);
1204 }
1205
1206 Msg.message = 0;
1207 if(mi->dwFlags & MOUSEEVENTF_LEFTDOWN)
1208 {
1209 gQueueKeyStateTable[VK_LBUTTON] |= 0xc0;
1210 Msg.message = SwapBtnMsg[0][SwapButtons];
1211 CurInfo->ButtonsDown |= SwapBtn[SwapButtons];
1212 MsqInsertSystemMessage(&Msg);
1213 }
1214 else if(mi->dwFlags & MOUSEEVENTF_LEFTUP)
1215 {
1216 gQueueKeyStateTable[VK_LBUTTON] &= ~0x80;
1217 Msg.message = SwapBtnMsg[1][SwapButtons];
1218 CurInfo->ButtonsDown &= ~SwapBtn[SwapButtons];
1219 MsqInsertSystemMessage(&Msg);
1220 }
1221 if(mi->dwFlags & MOUSEEVENTF_MIDDLEDOWN)
1222 {
1223 gQueueKeyStateTable[VK_MBUTTON] |= 0xc0;
1224 Msg.message = WM_MBUTTONDOWN;
1225 CurInfo->ButtonsDown |= MK_MBUTTON;
1226 MsqInsertSystemMessage(&Msg);
1227 }
1228 else if(mi->dwFlags & MOUSEEVENTF_MIDDLEUP)
1229 {
1230 gQueueKeyStateTable[VK_MBUTTON] &= ~0x80;
1231 Msg.message = WM_MBUTTONUP;
1232 CurInfo->ButtonsDown &= ~MK_MBUTTON;
1233 MsqInsertSystemMessage(&Msg);
1234 }
1235 if(mi->dwFlags & MOUSEEVENTF_RIGHTDOWN)
1236 {
1237 gQueueKeyStateTable[VK_RBUTTON] |= 0xc0;
1238 Msg.message = SwapBtnMsg[0][!SwapButtons];
1239 CurInfo->ButtonsDown |= SwapBtn[!SwapButtons];
1240 MsqInsertSystemMessage(&Msg);
1241 }
1242 else if(mi->dwFlags & MOUSEEVENTF_RIGHTUP)
1243 {
1244 gQueueKeyStateTable[VK_RBUTTON] &= ~0x80;
1245 Msg.message = SwapBtnMsg[1][!SwapButtons];
1246 CurInfo->ButtonsDown &= ~SwapBtn[!SwapButtons];
1247 MsqInsertSystemMessage(&Msg);
1248 }
1249
1250 if((mi->dwFlags & (MOUSEEVENTF_XDOWN | MOUSEEVENTF_XUP)) &&
1251 (mi->dwFlags & MOUSEEVENTF_WHEEL))
1252 {
1253 /* fail because both types of events use the mouseData field */
1254 return FALSE;
1255 }
1256
1257 if(mi->dwFlags & MOUSEEVENTF_XDOWN)
1258 {
1259 Msg.message = WM_XBUTTONDOWN;
1260 if(mi->mouseData & XBUTTON1)
1261 {
1262 gQueueKeyStateTable[VK_XBUTTON1] |= 0xc0;
1263 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
1264 CurInfo->ButtonsDown |= XBUTTON1;
1265 MsqInsertSystemMessage(&Msg);
1266 }
1267 if(mi->mouseData & XBUTTON2)
1268 {
1269 gQueueKeyStateTable[VK_XBUTTON2] |= 0xc0;
1270 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
1271 CurInfo->ButtonsDown |= XBUTTON2;
1272 MsqInsertSystemMessage(&Msg);
1273 }
1274 }
1275 else if(mi->dwFlags & MOUSEEVENTF_XUP)
1276 {
1277 Msg.message = WM_XBUTTONUP;
1278 if(mi->mouseData & XBUTTON1)
1279 {
1280 gQueueKeyStateTable[VK_XBUTTON1] &= ~0x80;
1281 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
1282 CurInfo->ButtonsDown &= ~XBUTTON1;
1283 MsqInsertSystemMessage(&Msg);
1284 }
1285 if(mi->mouseData & XBUTTON2)
1286 {
1287 gQueueKeyStateTable[VK_XBUTTON2] &= ~0x80;
1288 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
1289 CurInfo->ButtonsDown &= ~XBUTTON2;
1290 MsqInsertSystemMessage(&Msg);
1291 }
1292 }
1293 if(mi->dwFlags & MOUSEEVENTF_WHEEL)
1294 {
1295 Msg.message = WM_MOUSEWHEEL;
1296 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, mi->mouseData);
1297 MsqInsertSystemMessage(&Msg);
1298 }
1299
1300 return TRUE;
1301 }
1302
1303 BOOL FASTCALL
1304 IntKeyboardInput(KEYBDINPUT *ki)
1305 {
1306 PUSER_MESSAGE_QUEUE FocusMessageQueue;
1307 PTHREADINFO pti;
1308 MSG Msg;
1309 LARGE_INTEGER LargeTickCount;
1310 KBDLLHOOKSTRUCT KbdHookData;
1311 WORD flags, wVkStripped, wVkL, wVkR, wVk = ki->wVk, vk_hook = ki->wVk;
1312 BOOLEAN Entered = FALSE;
1313
1314 Msg.lParam = 0;
1315
1316 // Condition may arise when calling MsqPostMessage and waiting for an event.
1317 if (!UserIsEntered())
1318 {
1319 // Fixme: Not sure ATM if this thread is locked.
1320 UserEnterExclusive();
1321 Entered = TRUE;
1322 }
1323
1324 wVk = LOBYTE(wVk);
1325 Msg.wParam = wVk;
1326 flags = LOBYTE(ki->wScan);
1327
1328 if (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) flags |= KF_EXTENDED;
1329 /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
1330
1331 /* strip left/right for menu, control, shift */
1332 switch (wVk)
1333 {
1334 case VK_MENU:
1335 case VK_LMENU:
1336 case VK_RMENU:
1337 wVk = (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) ? VK_RMENU : VK_LMENU;
1338 wVkStripped = VK_MENU;
1339 wVkL = VK_LMENU;
1340 wVkR = VK_RMENU;
1341 break;
1342 case VK_CONTROL:
1343 case VK_LCONTROL:
1344 case VK_RCONTROL:
1345 wVk = (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) ? VK_RCONTROL : VK_LCONTROL;
1346 wVkStripped = VK_CONTROL;
1347 wVkL = VK_LCONTROL;
1348 wVkR = VK_RCONTROL;
1349 break;
1350 case VK_SHIFT:
1351 case VK_LSHIFT:
1352 case VK_RSHIFT:
1353 wVk = (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) ? VK_RSHIFT : VK_LSHIFT;
1354 wVkStripped = VK_SHIFT;
1355 wVkL = VK_LSHIFT;
1356 wVkR = VK_RSHIFT;
1357 break;
1358 default:
1359 wVkStripped = wVkL = wVkR = wVk;
1360 }
1361
1362 if (ki->dwFlags & KEYEVENTF_KEYUP)
1363 {
1364 Msg.message = WM_KEYUP;
1365 if ((gQueueKeyStateTable[VK_MENU] & 0x80) &&
1366 ((wVkStripped == VK_MENU) || (wVkStripped == VK_CONTROL)
1367 || !(gQueueKeyStateTable[VK_CONTROL] & 0x80)))
1368 {
1369 if( TrackSysKey == VK_MENU || /* <ALT>-down/<ALT>-up sequence */
1370 (wVkStripped != VK_MENU)) /* <ALT>-down...<something else>-up */
1371 Msg.message = WM_SYSKEYUP;
1372 TrackSysKey = 0;
1373 }
1374 flags |= KF_REPEAT | KF_UP;
1375 }
1376 else
1377 {
1378 Msg.message = WM_KEYDOWN;
1379 if ((gQueueKeyStateTable[VK_MENU] & 0x80 || wVkStripped == VK_MENU) &&
1380 !(gQueueKeyStateTable[VK_CONTROL] & 0x80 || wVkStripped == VK_CONTROL))
1381 {
1382 Msg.message = WM_SYSKEYDOWN;
1383 TrackSysKey = wVkStripped;
1384 }
1385 if (!(ki->dwFlags & KEYEVENTF_UNICODE) && gQueueKeyStateTable[wVk] & 0x80) flags |= KF_REPEAT;
1386 }
1387
1388 if (ki->dwFlags & KEYEVENTF_UNICODE)
1389 {
1390 vk_hook = Msg.wParam = wVk = VK_PACKET;
1391 Msg.lParam = MAKELPARAM(1 /* repeat count */, ki->wScan);
1392 }
1393
1394 FocusMessageQueue = IntGetFocusMessageQueue();
1395
1396 Msg.hwnd = 0;
1397
1398 if (FocusMessageQueue && (FocusMessageQueue->FocusWindow != (HWND)0))
1399 Msg.hwnd = FocusMessageQueue->FocusWindow;
1400
1401 if (!ki->time)
1402 {
1403 KeQueryTickCount(&LargeTickCount);
1404 Msg.time = MsqCalculateMessageTime(&LargeTickCount);
1405 }
1406 else
1407 Msg.time = ki->time;
1408
1409 /* All messages have to contain the cursor point. */
1410 pti = PsGetCurrentThreadWin32Thread();
1411 Msg.pt = gpsi->ptCursor;
1412
1413 DPRINT1("Kbd Hook msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1414 Msg.message, vk_hook, Msg.lParam);
1415
1416 KbdHookData.vkCode = vk_hook;
1417 KbdHookData.scanCode = ki->wScan;
1418 KbdHookData.flags = flags >> 8;
1419 KbdHookData.time = Msg.time;
1420 KbdHookData.dwExtraInfo = ki->dwExtraInfo;
1421 if (co_HOOK_CallHooks(WH_KEYBOARD_LL, HC_ACTION, Msg.message, (LPARAM) &KbdHookData))
1422 {
1423 DPRINT("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1424 Msg.message, vk_hook, Msg.lParam);
1425 if (Entered) UserLeave();
1426 return FALSE;
1427 }
1428
1429 if (!(ki->dwFlags & KEYEVENTF_UNICODE))
1430 {
1431 if (ki->dwFlags & KEYEVENTF_KEYUP)
1432 {
1433 gQueueKeyStateTable[wVk] &= ~0x80;
1434 gQueueKeyStateTable[wVkStripped] = gQueueKeyStateTable[wVkL] | gQueueKeyStateTable[wVkR];
1435 }
1436 else
1437 {
1438 if (!(gQueueKeyStateTable[wVk] & 0x80)) gQueueKeyStateTable[wVk] ^= 0x01;
1439 gQueueKeyStateTable[wVk] |= 0xc0;
1440 gQueueKeyStateTable[wVkStripped] = gQueueKeyStateTable[wVkL] | gQueueKeyStateTable[wVkR];
1441 }
1442
1443 if (gQueueKeyStateTable[VK_MENU] & 0x80) flags |= KF_ALTDOWN;
1444
1445 if (wVkStripped == VK_SHIFT) flags &= ~KF_EXTENDED;
1446
1447 Msg.lParam = MAKELPARAM(1 /* repeat count */, flags);
1448 }
1449
1450 if (FocusMessageQueue == NULL)
1451 {
1452 DPRINT("No focus message queue\n");
1453 if (Entered) UserLeave();
1454 return FALSE;
1455 }
1456
1457 if (FocusMessageQueue->FocusWindow != (HWND)0)
1458 {
1459 Msg.hwnd = FocusMessageQueue->FocusWindow;
1460 DPRINT("Msg.hwnd = %x\n", Msg.hwnd);
1461
1462 FocusMessageQueue->Desktop->pDeskInfo->LastInputWasKbd = TRUE;
1463
1464 Msg.pt = gpsi->ptCursor;
1465
1466 MsqPostMessage(FocusMessageQueue, &Msg, FALSE, QS_KEY);
1467 }
1468 else
1469 {
1470 DPRINT("Invalid focus window handle\n");
1471 }
1472
1473 if (Entered) UserLeave();
1474
1475 return TRUE;
1476 }
1477
1478 BOOL FASTCALL
1479 UserAttachThreadInput( PTHREADINFO pti, PTHREADINFO ptiTo, BOOL fAttach)
1480 {
1481 PATTACHINFO pai;
1482
1483 /* Can not be the same thread.*/
1484 if (pti == ptiTo) return FALSE;
1485
1486 /* Do not attach to system threads or between different desktops. */
1487 if ( pti->TIF_flags & TIF_DONTATTACHQUEUE ||
1488 ptiTo->TIF_flags & TIF_DONTATTACHQUEUE ||
1489 pti->Desktop != ptiTo->Desktop )
1490 return FALSE;
1491
1492 /* If Attach set, allocate and link. */
1493 if ( fAttach )
1494 {
1495 pai = ExAllocatePoolWithTag(PagedPool, sizeof(ATTACHINFO), TAG_ATTACHINFO);
1496 if ( !pai ) return FALSE;
1497
1498 pai->paiNext = gpai;
1499 pai->pti1 = pti;
1500 pai->pti2 = ptiTo;
1501 gpai = pai;
1502 }
1503 else /* If clear, unlink and free it. */
1504 {
1505 PATTACHINFO paiprev = NULL;
1506
1507 if ( !gpai ) return FALSE;
1508
1509 pai = gpai;
1510
1511 /* Search list and free if found or return false. */
1512 do
1513 {
1514 if ( pai->pti2 == ptiTo && pai->pti1 == pti ) break;
1515 paiprev = pai;
1516 pai = pai->paiNext;
1517 } while (pai);
1518
1519 if ( !pai ) return FALSE;
1520
1521 if (paiprev) paiprev->paiNext = pai->paiNext;
1522
1523 ExFreePoolWithTag(pai, TAG_ATTACHINFO);
1524 }
1525
1526 return TRUE;
1527 }
1528
1529 UINT
1530 APIENTRY
1531 NtUserSendInput(
1532 UINT nInputs,
1533 LPINPUT pInput,
1534 INT cbSize)
1535 {
1536 PTHREADINFO W32Thread;
1537 UINT cnt;
1538 DECLARE_RETURN(UINT);
1539
1540 DPRINT("Enter NtUserSendInput\n");
1541 UserEnterExclusive();
1542
1543 W32Thread = PsGetCurrentThreadWin32Thread();
1544 ASSERT(W32Thread);
1545
1546 if(!W32Thread->Desktop)
1547 {
1548 RETURN( 0);
1549 }
1550
1551 if(!nInputs || !pInput || (cbSize != sizeof(INPUT)))
1552 {
1553 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1554 RETURN( 0);
1555 }
1556
1557 /*
1558 * FIXME - check access rights of the window station
1559 * e.g. services running in the service window station cannot block input
1560 */
1561 if(!ThreadHasInputAccess(W32Thread) ||
1562 !IntIsActiveDesktop(W32Thread->Desktop))
1563 {
1564 SetLastWin32Error(ERROR_ACCESS_DENIED);
1565 RETURN( 0);
1566 }
1567
1568 cnt = 0;
1569 while(nInputs--)
1570 {
1571 INPUT SafeInput;
1572 NTSTATUS Status;
1573
1574 Status = MmCopyFromCaller(&SafeInput, pInput++, sizeof(INPUT));
1575 if(!NT_SUCCESS(Status))
1576 {
1577 SetLastNtError(Status);
1578 RETURN( cnt);
1579 }
1580
1581 switch(SafeInput.type)
1582 {
1583 case INPUT_MOUSE:
1584 if(IntMouseInput(&SafeInput.mi))
1585 {
1586 cnt++;
1587 }
1588 break;
1589 case INPUT_KEYBOARD:
1590 if(IntKeyboardInput(&SafeInput.ki))
1591 {
1592 cnt++;
1593 }
1594 break;
1595 case INPUT_HARDWARE:
1596 break;
1597 #ifndef NDEBUG
1598
1599 default:
1600 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput.type);
1601 break;
1602 #endif
1603
1604 }
1605 }
1606
1607 RETURN( cnt);
1608
1609 CLEANUP:
1610 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_);
1611 UserLeave();
1612 END_CLEANUP;
1613 }
1614
1615 /* EOF */