[CMAKE]
[reactos.git] / subsystems / win32 / win32k / ntuser / input.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Window classes
5 * FILE: subsystems/win32/win32k/ntuser/input.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISION HISTORY:
8 * 06-06-2001 CSH Created
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <win32k.h>
14 #include <ntddkbd.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19 extern BYTE gQueueKeyStateTable[];
20 extern NTSTATUS Win32kInitWin32Thread(PETHREAD Thread);
21
22 /* GLOBALS *******************************************************************/
23
24 PTHREADINFO ptiRawInput;
25 PTHREADINFO ptiKeyboard;
26 PTHREADINFO ptiMouse;
27 PKTIMER MasterTimer = NULL;
28 PATTACHINFO gpai = NULL;
29
30 static HANDLE MouseDeviceHandle;
31 static HANDLE MouseThreadHandle;
32 static CLIENT_ID MouseThreadId;
33 static HANDLE KeyboardThreadHandle;
34 static CLIENT_ID KeyboardThreadId;
35 static HANDLE KeyboardDeviceHandle;
36 static HANDLE RawInputThreadHandle;
37 static CLIENT_ID RawInputThreadId;
38 static KEVENT InputThreadsStart;
39 static BOOLEAN InputThreadsRunning = FALSE;
40 static BYTE TrackSysKey = 0; /* determine whether ALT key up will cause a WM_SYSKEYUP
41 or a WM_KEYUP message */
42
43 /* FUNCTIONS *****************************************************************/
44 DWORD IntLastInputTick(BOOL LastInputTickSetGet);
45
46 #define ClearMouseInput(mi) \
47 mi.dx = 0; \
48 mi.dy = 0; \
49 mi.mouseData = 0; \
50 mi.dwFlags = 0;
51
52 #define SendMouseEvent(mi) \
53 if(mi.dx != 0 || mi.dy != 0) \
54 mi.dwFlags |= MOUSEEVENTF_MOVE; \
55 if(mi.dwFlags) \
56 IntMouseInput(&mi,FALSE); \
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 DPRINT1("co_IntKeyboardSendAltKeyMsg\n");
485 // co_MsqPostKeyboardMessage(WM_SYSCOMMAND,SC_KEYMENU,0); This sends everything into a msg loop!
486 }
487
488 static VOID APIENTRY
489 KeyboardThreadMain(PVOID StartContext)
490 {
491 UNICODE_STRING KeyboardDeviceName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardClass0");
492 OBJECT_ATTRIBUTES KeyboardObjectAttributes;
493 IO_STATUS_BLOCK Iosb;
494 NTSTATUS Status;
495 MSG msg;
496 PUSER_MESSAGE_QUEUE FocusQueue;
497 struct _ETHREAD *FocusThread;
498
499 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans = NULL;
500 UINT ModifierState = 0;
501 USHORT LastMakeCode = 0;
502 USHORT LastFlags = 0;
503 UINT RepeatCount = 0;
504
505 InitializeObjectAttributes(&KeyboardObjectAttributes,
506 &KeyboardDeviceName,
507 0,
508 NULL,
509 NULL);
510 do
511 {
512 LARGE_INTEGER DueTime;
513 KEVENT Event;
514 DueTime.QuadPart = (LONGLONG)(-10000000);
515 KeInitializeEvent(&Event, NotificationEvent, FALSE);
516 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime);
517 Status = NtOpenFile(&KeyboardDeviceHandle,
518 FILE_ALL_ACCESS,
519 &KeyboardObjectAttributes,
520 &Iosb,
521 0,
522 FILE_SYNCHRONOUS_IO_ALERT);
523 } while (!NT_SUCCESS(Status));
524
525 /* Not sure if converting this thread to a win32 thread is such
526 a great idea. Since we're posting keyboard messages to the focus
527 window message queue, we'll be (indirectly) doing sendmessage
528 stuff from this thread (for WH_KEYBOARD_LL processing), which
529 means we need our own message queue. If keyboard messages were
530 instead queued to the system message queue, the thread removing
531 the message from the system message queue would be responsible
532 for WH_KEYBOARD_LL processing and we wouldn't need this thread
533 to be a win32 thread. */
534 Status = Win32kInitWin32Thread(PsGetCurrentThread());
535 if (!NT_SUCCESS(Status))
536 {
537 DPRINT1("Win32K: Failed making keyboard thread a win32 thread.\n");
538 return; //(Status);
539 }
540
541 ptiKeyboard = PsGetCurrentThreadWin32Thread();
542 ptiKeyboard->TIF_flags |= TIF_SYSTEMTHREAD;
543 DPRINT("Keyboard Thread 0x%x \n", ptiKeyboard);
544
545 KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
546 LOW_REALTIME_PRIORITY + 3);
547
548 IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle,
549 &IndicatorTrans);
550
551 for (;;)
552 {
553 /*
554 * Wait to start input.
555 */
556 DPRINT( "Keyboard Input Thread Waiting for start event\n" );
557 Status = KeWaitForSingleObject(&InputThreadsStart,
558 0,
559 KernelMode,
560 TRUE,
561 NULL);
562
563 DPRINT( "Keyboard Input Thread Starting...\n" );
564 /*
565 * Receive and process keyboard input.
566 */
567 while (InputThreadsRunning)
568 {
569 BOOLEAN NumKeys = 1;
570 BOOLEAN bLeftAlt;
571 KEYBOARD_INPUT_DATA KeyInput;
572 KEYBOARD_INPUT_DATA NextKeyInput;
573 LPARAM lParam = 0;
574 UINT fsModifiers, fsNextModifiers;
575 struct _ETHREAD *Thread;
576 HWND hWnd;
577 int id;
578
579 DPRINT("KeyInput @ %08x\n", &KeyInput);
580
581 Status = NtReadFile (KeyboardDeviceHandle,
582 NULL,
583 NULL,
584 NULL,
585 &Iosb,
586 &KeyInput,
587 sizeof(KEYBOARD_INPUT_DATA),
588 NULL,
589 NULL);
590
591 if(Status == STATUS_ALERTED && !InputThreadsRunning)
592 {
593 break;
594 }
595 if(Status == STATUS_PENDING)
596 {
597 NtWaitForSingleObject(KeyboardDeviceHandle, FALSE, NULL);
598 Status = Iosb.Status;
599 }
600 if(!NT_SUCCESS(Status))
601 {
602 DPRINT1("Win32K: Failed to read from mouse.\n");
603 return; //(Status);
604 }
605
606 DPRINT("KeyRaw: %s %04x\n",
607 (KeyInput.Flags & KEY_BREAK) ? "up" : "down",
608 KeyInput.MakeCode );
609
610 if (Status == STATUS_ALERTED && !InputThreadsRunning)
611 break;
612
613 if (!NT_SUCCESS(Status))
614 {
615 DPRINT1("Win32K: Failed to read from keyboard.\n");
616 return; //(Status);
617 }
618
619 /* Set LastInputTick */
620 IntLastInputTick(TRUE);
621
622 /* Update modifier state */
623 fsModifiers = IntKeyboardGetModifiers(&KeyInput);
624
625 if (fsModifiers)
626 {
627 if (KeyInput.Flags & KEY_BREAK)
628 {
629 ModifierState &= ~fsModifiers;
630 if(fsModifiers == MOD_ALT)
631 {
632 if(KeyInput.Flags & KEY_E0)
633 {
634 gQueueKeyStateTable[VK_RMENU] = 0;
635 }
636 else
637 {
638 gQueueKeyStateTable[VK_LMENU] = 0;
639 }
640 if (gQueueKeyStateTable[VK_RMENU] == 0 &&
641 gQueueKeyStateTable[VK_LMENU] == 0)
642 {
643 gQueueKeyStateTable[VK_MENU] = 0;
644 }
645 }
646 }
647 else
648 {
649 ModifierState |= fsModifiers;
650
651 if (ModifierState == fsModifiers &&
652 (fsModifiers == MOD_ALT || fsModifiers == MOD_WIN))
653 {
654 /* First send out special notifications
655 * (For alt, the message that turns on accelerator
656 * display, not sure what for win. Both TODO though.)
657 */
658 bLeftAlt = FALSE;
659 if(fsModifiers == MOD_ALT)
660 {
661 if(KeyInput.Flags & KEY_E0)
662 {
663 gQueueKeyStateTable[VK_RMENU] = 0x80;
664 }
665 else
666 {
667 gQueueKeyStateTable[VK_LMENU] = 0x80;
668 bLeftAlt = TRUE;
669 }
670
671 gQueueKeyStateTable[VK_MENU] = 0x80;
672 }
673
674 /* Read the next key before sending this one */
675 do
676 {
677 Status = NtReadFile (KeyboardDeviceHandle,
678 NULL,
679 NULL,
680 NULL,
681 &Iosb,
682 &NextKeyInput,
683 sizeof(KEYBOARD_INPUT_DATA),
684 NULL,
685 NULL);
686 DPRINT("KeyRaw: %s %04x\n",
687 (NextKeyInput.Flags & KEY_BREAK) ? "up":"down",
688 NextKeyInput.MakeCode );
689
690 if (Status == STATUS_ALERTED && !InputThreadsRunning)
691 goto KeyboardEscape;
692
693 }
694 while ((!(NextKeyInput.Flags & KEY_BREAK)) &&
695 NextKeyInput.MakeCode == KeyInput.MakeCode);
696 /* ^ Ignore repeats, they'll be KEY_MAKE and the same
697 * code. I'm not caring about the counting, not sure
698 * if that matters. I think not.
699 */
700
701 /* If the ModifierState is now empty again, send a
702 * special notification and eat both keypresses
703 */
704
705 fsNextModifiers = IntKeyboardGetModifiers(&NextKeyInput);
706
707 if (fsNextModifiers)
708 ModifierState ^= fsNextModifiers;
709
710 if (ModifierState == 0)
711 {
712 UserEnterExclusive();
713 if (fsModifiers == MOD_WIN)
714 IntKeyboardSendWinKeyMsg();
715 else if (fsModifiers == MOD_ALT)
716 {
717 gQueueKeyStateTable[VK_MENU] = 0;
718 if(bLeftAlt)
719 {
720 gQueueKeyStateTable[VK_LMENU] = 0;
721 }
722 else
723 {
724 gQueueKeyStateTable[VK_RMENU] = 0;
725 }
726 co_IntKeyboardSendAltKeyMsg();
727 }
728 UserLeave();
729 continue;
730 }
731
732 NumKeys = 2;
733 }
734 }
735 }
736
737 UserEnterExclusive();
738
739 for (;NumKeys;memcpy(&KeyInput, &NextKeyInput, sizeof(KeyInput)),
740 NumKeys--)
741 {
742 PKBL keyboardLayout = NULL;
743 lParam = 0;
744
745 IntKeyboardUpdateLeds(KeyboardDeviceHandle,
746 &KeyInput,
747 IndicatorTrans);
748
749 /* While we are working, we set up lParam. The format is:
750 * 0-15: The number of times this key has autorepeated
751 * 16-23: The keyboard scancode
752 * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
753 * Note that E1 is only used for PAUSE (E1-1D-45) and
754 * E0-45 happens not to be anything.
755 * 29: Alt is pressed ('Context code')
756 * 30: Previous state, if the key was down before this message
757 * This is a cheap way to ignore autorepeat keys
758 * 31: 1 if the key is being pressed
759 */
760
761 /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
762 * and it's the same key as the last one, increase the repeat
763 * count.
764 */
765
766 if (!(KeyInput.Flags & KEY_BREAK))
767 {
768 if (((KeyInput.Flags & (KEY_E0 | KEY_E1)) == LastFlags) &&
769 (KeyInput.MakeCode == LastMakeCode))
770 {
771 RepeatCount++;
772 lParam |= (1 << 30);
773 }
774 else
775 {
776 RepeatCount = 1;
777 LastFlags = KeyInput.Flags & (KEY_E0 | KEY_E1);
778 LastMakeCode = KeyInput.MakeCode;
779 }
780 }
781 else
782 {
783 LastFlags = 0;
784 LastMakeCode = 0; /* Should never match */
785 lParam |= (1 << 30) | (1 << 31);
786 }
787
788 lParam |= RepeatCount;
789
790 lParam |= (KeyInput.MakeCode & 0xff) << 16;
791
792 if (KeyInput.Flags & KEY_E0)
793 lParam |= (1 << 24);
794
795 if (ModifierState & MOD_ALT)
796 {
797 lParam |= (1 << 29); // wine -> (HIWORD(lParam) & KEYDATA_ALT) #define KEYDATA_ALT 0x2000
798
799 if (!(KeyInput.Flags & KEY_BREAK))
800 msg.message = WM_SYSKEYDOWN;
801 else
802 msg.message = WM_SYSKEYUP;
803 }
804 else
805 {
806 if (!(KeyInput.Flags & KEY_BREAK))
807 msg.message = WM_KEYDOWN;
808 else
809 msg.message = WM_KEYUP;
810 }
811
812 /* Find the target thread whose locale is in effect */
813 FocusQueue = IntGetFocusMessageQueue();
814
815 if (FocusQueue)
816 {
817 msg.hwnd = FocusQueue->FocusWindow;
818
819 FocusThread = FocusQueue->Thread;
820 if (FocusThread && FocusThread->Tcb.Win32Thread)
821 {
822 keyboardLayout = ((PTHREADINFO)FocusThread->Tcb.Win32Thread)->KeyboardLayout;
823 }
824 }
825 if (!keyboardLayout)
826 {
827 keyboardLayout = W32kGetDefaultKeyLayout();
828 }
829
830 msg.lParam = lParam;
831
832 /* This function uses lParam to fill wParam according to the
833 * keyboard layout in use.
834 */
835 W32kKeyProcessMessage(&msg,
836 keyboardLayout->KBTables,
837 KeyInput.Flags & KEY_E0 ? 0xE0 :
838 (KeyInput.Flags & KEY_E1 ? 0xE1 : 0));
839
840 if (GetHotKey(ModifierState,
841 msg.wParam,
842 &Thread,
843 &hWnd,
844 &id))
845 {
846 if (!(KeyInput.Flags & KEY_BREAK))
847 {
848 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd, id);
849 MsqPostHotKeyMessage (Thread,
850 hWnd,
851 (WPARAM)id,
852 MAKELPARAM((WORD)ModifierState,
853 (WORD)msg.wParam));
854 }
855 continue; /* Eat key up motion too */
856 }
857
858 if (!FocusQueue)
859 {
860 /* There is no focused window to receive a keyboard message */
861 continue;
862 }
863 /*
864 * Post a keyboard message.
865 */
866 co_MsqPostKeyboardMessage(msg.message,msg.wParam,msg.lParam);
867 }
868
869 UserLeave();
870 }
871
872 KeyboardEscape:
873 DPRINT( "KeyboardInput Thread Stopped...\n" );
874 }
875 }
876
877
878 static PVOID Objects[2];
879 /*
880 Raw Input Thread.
881 Since this relies on InputThreadsStart, just fake it.
882 */
883 static VOID APIENTRY
884 RawInputThreadMain(PVOID StartContext)
885 {
886 NTSTATUS Status;
887 LARGE_INTEGER DueTime;
888
889 DueTime.QuadPart = (LONGLONG)(-10000000);
890
891 do
892 {
893 KEVENT Event;
894 KeInitializeEvent(&Event, NotificationEvent, FALSE);
895 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime);
896 } while (!NT_SUCCESS(Status));
897
898
899 Objects[0] = &InputThreadsStart;
900 Objects[1] = MasterTimer;
901
902 // This thread requires win32k!
903 Status = Win32kInitWin32Thread(PsGetCurrentThread());
904 if (!NT_SUCCESS(Status))
905 {
906 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
907 return; //(Status);
908 }
909
910 ptiRawInput = PsGetCurrentThreadWin32Thread();
911 ptiRawInput->TIF_flags |= TIF_SYSTEMTHREAD;
912 DPRINT("Raw Input Thread 0x%x \n", ptiRawInput);
913
914 KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
915 LOW_REALTIME_PRIORITY + 3);
916
917 UserEnterExclusive();
918 StartTheTimers();
919 UserLeave();
920
921 //
922 // ATM, we just have one job to handle, merge the other two later.
923 //
924 for(;;)
925 {
926 DPRINT( "Raw Input Thread Waiting for start event\n" );
927
928 Status = KeWaitForMultipleObjects( 2,
929 Objects,
930 WaitAll, //WaitAny,
931 WrUserRequest,
932 KernelMode,
933 TRUE,
934 NULL,
935 NULL);
936 DPRINT( "Raw Input Thread Starting...\n" );
937
938 ProcessTimers();
939 }
940 DPRINT1("Raw Input Thread Exit!\n");
941 }
942
943 INIT_FUNCTION
944 NTSTATUS
945 NTAPI
946 InitInputImpl(VOID)
947 {
948 NTSTATUS Status;
949
950 KeInitializeEvent(&InputThreadsStart, NotificationEvent, FALSE);
951
952 MasterTimer = ExAllocatePoolWithTag(NonPagedPool, sizeof(KTIMER), USERTAG_SYSTEM);
953 if (!MasterTimer)
954 {
955 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
956 ASSERT(FALSE);
957 return STATUS_UNSUCCESSFUL;
958 }
959 KeInitializeTimer(MasterTimer);
960
961 /* Initialize the default keyboard layout */
962 if(!UserInitDefaultKeyboardLayout())
963 {
964 DPRINT1("Failed to initialize default keyboard layout!\n");
965 }
966
967 Status = PsCreateSystemThread(&RawInputThreadHandle,
968 THREAD_ALL_ACCESS,
969 NULL,
970 NULL,
971 &RawInputThreadId,
972 RawInputThreadMain,
973 NULL);
974 if (!NT_SUCCESS(Status))
975 {
976 DPRINT1("Win32K: Failed to create raw thread.\n");
977 }
978
979 Status = PsCreateSystemThread(&KeyboardThreadHandle,
980 THREAD_ALL_ACCESS,
981 NULL,
982 NULL,
983 &KeyboardThreadId,
984 KeyboardThreadMain,
985 NULL);
986 if (!NT_SUCCESS(Status))
987 {
988 DPRINT1("Win32K: Failed to create keyboard thread.\n");
989 }
990
991 Status = PsCreateSystemThread(&MouseThreadHandle,
992 THREAD_ALL_ACCESS,
993 NULL,
994 NULL,
995 &MouseThreadId,
996 MouseThreadMain,
997 NULL);
998 if (!NT_SUCCESS(Status))
999 {
1000 DPRINT1("Win32K: Failed to create mouse thread.\n");
1001 }
1002
1003 InputThreadsRunning = TRUE;
1004 KeSetEvent(&InputThreadsStart, IO_NO_INCREMENT, FALSE);
1005
1006 return STATUS_SUCCESS;
1007 }
1008
1009 NTSTATUS FASTCALL
1010 CleanupInputImp(VOID)
1011 {
1012 return(STATUS_SUCCESS);
1013 }
1014
1015 BOOL FASTCALL
1016 IntBlockInput(PTHREADINFO W32Thread, BOOL BlockIt)
1017 {
1018 PTHREADINFO OldBlock;
1019 ASSERT(W32Thread);
1020
1021 if(!W32Thread->rpdesk || ((W32Thread->TIF_flags & TIF_INCLEANUP) && BlockIt))
1022 {
1023 /*
1024 * fail blocking if exiting the thread
1025 */
1026
1027 return FALSE;
1028 }
1029
1030 /*
1031 * FIXME - check access rights of the window station
1032 * e.g. services running in the service window station cannot block input
1033 */
1034 if(!ThreadHasInputAccess(W32Thread) ||
1035 !IntIsActiveDesktop(W32Thread->rpdesk))
1036 {
1037 EngSetLastError(ERROR_ACCESS_DENIED);
1038 return FALSE;
1039 }
1040
1041 ASSERT(W32Thread->rpdesk);
1042 OldBlock = W32Thread->rpdesk->BlockInputThread;
1043 if(OldBlock)
1044 {
1045 if(OldBlock != W32Thread)
1046 {
1047 EngSetLastError(ERROR_ACCESS_DENIED);
1048 return FALSE;
1049 }
1050 W32Thread->rpdesk->BlockInputThread = (BlockIt ? W32Thread : NULL);
1051 return OldBlock == NULL;
1052 }
1053
1054 W32Thread->rpdesk->BlockInputThread = (BlockIt ? W32Thread : NULL);
1055 return OldBlock == NULL;
1056 }
1057
1058 BOOL
1059 APIENTRY
1060 NtUserBlockInput(
1061 BOOL BlockIt)
1062 {
1063 DECLARE_RETURN(BOOLEAN);
1064
1065 DPRINT("Enter NtUserBlockInput\n");
1066 UserEnterExclusive();
1067
1068 RETURN( IntBlockInput(PsGetCurrentThreadWin32Thread(), BlockIt));
1069
1070 CLEANUP:
1071 DPRINT("Leave NtUserBlockInput, ret=%i\n",_ret_);
1072 UserLeave();
1073 END_CLEANUP;
1074 }
1075
1076 BOOL FASTCALL
1077 IntMouseInput(MOUSEINPUT *mi, BOOL Injected)
1078 {
1079 const UINT SwapBtnMsg[2][2] =
1080 {
1081 {WM_LBUTTONDOWN, WM_RBUTTONDOWN},
1082 {WM_LBUTTONUP, WM_RBUTTONUP}
1083 };
1084 const WPARAM SwapBtn[2] =
1085 {
1086 MK_LBUTTON, MK_RBUTTON
1087 };
1088 POINT MousePos;
1089 PSYSTEM_CURSORINFO CurInfo;
1090 BOOL SwapButtons;
1091 MSG Msg;
1092
1093 ASSERT(mi);
1094
1095 CurInfo = IntGetSysCursorInfo();
1096
1097 if(!mi->time)
1098 {
1099 LARGE_INTEGER LargeTickCount;
1100 KeQueryTickCount(&LargeTickCount);
1101 mi->time = MsqCalculateMessageTime(&LargeTickCount);
1102 }
1103
1104 SwapButtons = gspv.bMouseBtnSwap;
1105
1106 MousePos = gpsi->ptCursor;
1107
1108 if(mi->dwFlags & MOUSEEVENTF_MOVE)
1109 {
1110 if(mi->dwFlags & MOUSEEVENTF_ABSOLUTE)
1111 {
1112 MousePos.x = mi->dx * UserGetSystemMetrics(SM_CXVIRTUALSCREEN) >> 16;
1113 MousePos.y = mi->dy * UserGetSystemMetrics(SM_CYVIRTUALSCREEN) >> 16;
1114 }
1115 else
1116 {
1117 MousePos.x += mi->dx;
1118 MousePos.y += mi->dy;
1119 }
1120 }
1121
1122 /*
1123 * Insert the messages into the system queue
1124 */
1125 Msg.wParam = 0;
1126 Msg.lParam = MAKELPARAM(MousePos.x, MousePos.y);
1127 Msg.pt = MousePos;
1128
1129 if (gQueueKeyStateTable[VK_SHIFT] & 0xc0)
1130 {
1131 Msg.wParam |= MK_SHIFT;
1132 }
1133
1134 if (gQueueKeyStateTable[VK_CONTROL] & 0xc0)
1135 {
1136 Msg.wParam |= MK_CONTROL;
1137 }
1138
1139 if(mi->dwFlags & MOUSEEVENTF_MOVE)
1140 {
1141 UserSetCursorPos(MousePos.x, MousePos.y, Injected, mi->dwExtraInfo, TRUE);
1142 }
1143 if(mi->dwFlags & MOUSEEVENTF_LEFTDOWN)
1144 {
1145 gQueueKeyStateTable[VK_LBUTTON] |= 0xc0;
1146 Msg.message = SwapBtnMsg[0][SwapButtons];
1147 CurInfo->ButtonsDown |= SwapBtn[SwapButtons];
1148 Msg.wParam |= CurInfo->ButtonsDown;
1149 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1150 }
1151 else if(mi->dwFlags & MOUSEEVENTF_LEFTUP)
1152 {
1153 gQueueKeyStateTable[VK_LBUTTON] &= ~0x80;
1154 Msg.message = SwapBtnMsg[1][SwapButtons];
1155 CurInfo->ButtonsDown &= ~SwapBtn[SwapButtons];
1156 Msg.wParam |= CurInfo->ButtonsDown;
1157 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1158 }
1159 if(mi->dwFlags & MOUSEEVENTF_MIDDLEDOWN)
1160 {
1161 gQueueKeyStateTable[VK_MBUTTON] |= 0xc0;
1162 Msg.message = WM_MBUTTONDOWN;
1163 CurInfo->ButtonsDown |= MK_MBUTTON;
1164 Msg.wParam |= CurInfo->ButtonsDown;
1165 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1166 }
1167 else if(mi->dwFlags & MOUSEEVENTF_MIDDLEUP)
1168 {
1169 gQueueKeyStateTable[VK_MBUTTON] &= ~0x80;
1170 Msg.message = WM_MBUTTONUP;
1171 CurInfo->ButtonsDown &= ~MK_MBUTTON;
1172 Msg.wParam |= CurInfo->ButtonsDown;
1173 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1174 }
1175 if(mi->dwFlags & MOUSEEVENTF_RIGHTDOWN)
1176 {
1177 gQueueKeyStateTable[VK_RBUTTON] |= 0xc0;
1178 Msg.message = SwapBtnMsg[0][!SwapButtons];
1179 CurInfo->ButtonsDown |= SwapBtn[!SwapButtons];
1180 Msg.wParam |= CurInfo->ButtonsDown;
1181 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1182 }
1183 else if(mi->dwFlags & MOUSEEVENTF_RIGHTUP)
1184 {
1185 gQueueKeyStateTable[VK_RBUTTON] &= ~0x80;
1186 Msg.message = SwapBtnMsg[1][!SwapButtons];
1187 CurInfo->ButtonsDown &= ~SwapBtn[!SwapButtons];
1188 Msg.wParam |= CurInfo->ButtonsDown;
1189 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1190 }
1191
1192 if((mi->dwFlags & (MOUSEEVENTF_XDOWN | MOUSEEVENTF_XUP)) &&
1193 (mi->dwFlags & MOUSEEVENTF_WHEEL))
1194 {
1195 /* fail because both types of events use the mouseData field */
1196 return FALSE;
1197 }
1198
1199 if(mi->dwFlags & MOUSEEVENTF_XDOWN)
1200 {
1201 Msg.message = WM_XBUTTONDOWN;
1202 if(mi->mouseData & XBUTTON1)
1203 {
1204 gQueueKeyStateTable[VK_XBUTTON1] |= 0xc0;
1205 CurInfo->ButtonsDown |= MK_XBUTTON1;
1206 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
1207 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1208 }
1209 if(mi->mouseData & XBUTTON2)
1210 {
1211 gQueueKeyStateTable[VK_XBUTTON2] |= 0xc0;
1212 CurInfo->ButtonsDown |= MK_XBUTTON2;
1213 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
1214 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1215 }
1216 }
1217 else if(mi->dwFlags & MOUSEEVENTF_XUP)
1218 {
1219 Msg.message = WM_XBUTTONUP;
1220 if(mi->mouseData & XBUTTON1)
1221 {
1222 gQueueKeyStateTable[VK_XBUTTON1] &= ~0x80;
1223 CurInfo->ButtonsDown &= ~MK_XBUTTON1;
1224 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
1225 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1226 }
1227 if(mi->mouseData & XBUTTON2)
1228 {
1229 gQueueKeyStateTable[VK_XBUTTON2] &= ~0x80;
1230 CurInfo->ButtonsDown &= ~MK_XBUTTON2;
1231 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
1232 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1233 }
1234 }
1235 if(mi->dwFlags & MOUSEEVENTF_WHEEL)
1236 {
1237 Msg.message = WM_MOUSEWHEEL;
1238 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, mi->mouseData);
1239 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1240 }
1241
1242 return TRUE;
1243 }
1244
1245 BOOL FASTCALL
1246 IntKeyboardInput(KEYBDINPUT *ki, BOOL Injected)
1247 {
1248 PUSER_MESSAGE_QUEUE FocusMessageQueue;
1249 MSG Msg;
1250 LARGE_INTEGER LargeTickCount;
1251 KBDLLHOOKSTRUCT KbdHookData;
1252 WORD flags, wVkStripped, wVkL, wVkR, wVk = ki->wVk, vk_hook = ki->wVk;
1253
1254 Msg.lParam = 0;
1255
1256 // Condition may arise when calling MsqPostMessage and waiting for an event.
1257 ASSERT (UserIsEntered());
1258
1259 wVk = LOBYTE(wVk);
1260 Msg.wParam = wVk;
1261 flags = LOBYTE(ki->wScan);
1262
1263 if (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) flags |= KF_EXTENDED;
1264 /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
1265
1266 /* strip left/right for menu, control, shift */
1267 switch (wVk)
1268 {
1269 case VK_MENU:
1270 case VK_LMENU:
1271 case VK_RMENU:
1272 wVk = (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) ? VK_RMENU : VK_LMENU;
1273 wVkStripped = VK_MENU;
1274 wVkL = VK_LMENU;
1275 wVkR = VK_RMENU;
1276 break;
1277 case VK_CONTROL:
1278 case VK_LCONTROL:
1279 case VK_RCONTROL:
1280 wVk = (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) ? VK_RCONTROL : VK_LCONTROL;
1281 wVkStripped = VK_CONTROL;
1282 wVkL = VK_LCONTROL;
1283 wVkR = VK_RCONTROL;
1284 break;
1285 case VK_SHIFT:
1286 case VK_LSHIFT:
1287 case VK_RSHIFT:
1288 wVk = (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) ? VK_RSHIFT : VK_LSHIFT;
1289 wVkStripped = VK_SHIFT;
1290 wVkL = VK_LSHIFT;
1291 wVkR = VK_RSHIFT;
1292 break;
1293 default:
1294 wVkStripped = wVkL = wVkR = wVk;
1295 }
1296
1297 if (ki->dwFlags & KEYEVENTF_KEYUP)
1298 {
1299 Msg.message = WM_KEYUP;
1300 if (((gQueueKeyStateTable[VK_MENU] & 0x80) &&
1301 ((wVkStripped == VK_MENU) || (wVkStripped == VK_CONTROL)
1302 || !(gQueueKeyStateTable[VK_CONTROL] & 0x80)))
1303 || (wVkStripped == VK_F10))
1304 {
1305 if( TrackSysKey == VK_MENU || /* <ALT>-down/<ALT>-up sequence */
1306 (wVkStripped != VK_MENU)) /* <ALT>-down...<something else>-up */
1307 Msg.message = WM_SYSKEYUP;
1308 TrackSysKey = 0;
1309 }
1310 flags |= KF_REPEAT | KF_UP;
1311 }
1312 else
1313 {
1314 Msg.message = WM_KEYDOWN;
1315 if (((gQueueKeyStateTable[VK_MENU] & 0x80 || wVkStripped == VK_MENU) &&
1316 !(gQueueKeyStateTable[VK_CONTROL] & 0x80 || wVkStripped == VK_CONTROL))
1317 || (wVkStripped == VK_F10))
1318 {
1319 Msg.message = WM_SYSKEYDOWN;
1320 TrackSysKey = wVkStripped;
1321 }
1322 if (!(ki->dwFlags & KEYEVENTF_UNICODE) && gQueueKeyStateTable[wVk] & 0x80) flags |= KF_REPEAT;
1323 }
1324
1325 if (ki->dwFlags & KEYEVENTF_UNICODE)
1326 {
1327 vk_hook = Msg.wParam = wVk = VK_PACKET;
1328 Msg.lParam = MAKELPARAM(1 /* repeat count */, ki->wScan);
1329 }
1330
1331 FocusMessageQueue = IntGetFocusMessageQueue();
1332
1333 Msg.hwnd = 0;
1334
1335 if (FocusMessageQueue && (FocusMessageQueue->FocusWindow != (HWND)0))
1336 Msg.hwnd = FocusMessageQueue->FocusWindow;
1337
1338 if (!ki->time)
1339 {
1340 KeQueryTickCount(&LargeTickCount);
1341 Msg.time = MsqCalculateMessageTime(&LargeTickCount);
1342 }
1343 else
1344 Msg.time = ki->time;
1345
1346 /* All messages have to contain the cursor point. */
1347 Msg.pt = gpsi->ptCursor;
1348
1349 KbdHookData.vkCode = vk_hook;
1350 KbdHookData.scanCode = ki->wScan;
1351 KbdHookData.flags = flags >> 8;
1352 if (Injected) KbdHookData.flags |= LLKHF_INJECTED;
1353 KbdHookData.time = Msg.time;
1354 KbdHookData.dwExtraInfo = ki->dwExtraInfo;
1355 if (co_HOOK_CallHooks(WH_KEYBOARD_LL, HC_ACTION, Msg.message, (LPARAM) &KbdHookData))
1356 {
1357 DPRINT1("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1358 Msg.message, vk_hook, Msg.lParam);
1359
1360 return FALSE;
1361 }
1362
1363 if (!(ki->dwFlags & KEYEVENTF_UNICODE))
1364 {
1365 if (ki->dwFlags & KEYEVENTF_KEYUP)
1366 {
1367 gQueueKeyStateTable[wVk] &= ~0x80;
1368 gQueueKeyStateTable[wVkStripped] = gQueueKeyStateTable[wVkL] | gQueueKeyStateTable[wVkR];
1369 }
1370 else
1371 {
1372 if (!(gQueueKeyStateTable[wVk] & 0x80)) gQueueKeyStateTable[wVk] ^= 0x01;
1373 gQueueKeyStateTable[wVk] |= 0xc0;
1374 gQueueKeyStateTable[wVkStripped] = gQueueKeyStateTable[wVkL] | gQueueKeyStateTable[wVkR];
1375 }
1376
1377 if (gQueueKeyStateTable[VK_MENU] & 0x80) flags |= KF_ALTDOWN;
1378
1379 if (wVkStripped == VK_SHIFT) flags &= ~KF_EXTENDED;
1380
1381 Msg.lParam = MAKELPARAM(1 /* repeat count */, flags);
1382 }
1383
1384 if (FocusMessageQueue == NULL)
1385 {
1386 DPRINT("No focus message queue\n");
1387
1388 return FALSE;
1389 }
1390
1391 if (FocusMessageQueue->FocusWindow != (HWND)0)
1392 {
1393 Msg.hwnd = FocusMessageQueue->FocusWindow;
1394 DPRINT("Msg.hwnd = %x\n", Msg.hwnd);
1395
1396 FocusMessageQueue->Desktop->pDeskInfo->LastInputWasKbd = TRUE;
1397
1398 Msg.pt = gpsi->ptCursor;
1399 // Post to hardware queue, based on the first part of wine "some GetMessage tests"
1400 // in test_PeekMessage()
1401 MsqPostMessage(FocusMessageQueue, &Msg, TRUE, QS_KEY);
1402 }
1403 else
1404 {
1405 DPRINT("Invalid focus window handle\n");
1406 }
1407
1408 return TRUE;
1409 }
1410
1411 BOOL FASTCALL
1412 UserAttachThreadInput( PTHREADINFO pti, PTHREADINFO ptiTo, BOOL fAttach)
1413 {
1414 PATTACHINFO pai;
1415
1416 /* Can not be the same thread.*/
1417 if (pti == ptiTo) return FALSE;
1418
1419 /* Do not attach to system threads or between different desktops. */
1420 if ( pti->TIF_flags & TIF_DONTATTACHQUEUE ||
1421 ptiTo->TIF_flags & TIF_DONTATTACHQUEUE ||
1422 pti->rpdesk != ptiTo->rpdesk )
1423 return FALSE;
1424
1425 /* If Attach set, allocate and link. */
1426 if ( fAttach )
1427 {
1428 pai = ExAllocatePoolWithTag(PagedPool, sizeof(ATTACHINFO), USERTAG_ATTACHINFO);
1429 if ( !pai ) return FALSE;
1430
1431 pai->paiNext = gpai;
1432 pai->pti1 = pti;
1433 pai->pti2 = ptiTo;
1434 gpai = pai;
1435 }
1436 else /* If clear, unlink and free it. */
1437 {
1438 PATTACHINFO paiprev = NULL;
1439
1440 if ( !gpai ) return FALSE;
1441
1442 pai = gpai;
1443
1444 /* Search list and free if found or return false. */
1445 do
1446 {
1447 if ( pai->pti2 == ptiTo && pai->pti1 == pti ) break;
1448 paiprev = pai;
1449 pai = pai->paiNext;
1450 } while (pai);
1451
1452 if ( !pai ) return FALSE;
1453
1454 if (paiprev) paiprev->paiNext = pai->paiNext;
1455
1456 ExFreePoolWithTag(pai, USERTAG_ATTACHINFO);
1457 }
1458
1459 return TRUE;
1460 }
1461
1462 UINT
1463 APIENTRY
1464 NtUserSendInput(
1465 UINT nInputs,
1466 LPINPUT pInput,
1467 INT cbSize)
1468 {
1469 PTHREADINFO W32Thread;
1470 UINT cnt;
1471 DECLARE_RETURN(UINT);
1472
1473 DPRINT("Enter NtUserSendInput\n");
1474 UserEnterExclusive();
1475
1476 W32Thread = PsGetCurrentThreadWin32Thread();
1477 ASSERT(W32Thread);
1478
1479 if(!W32Thread->rpdesk)
1480 {
1481 RETURN( 0);
1482 }
1483
1484 if(!nInputs || !pInput || (cbSize != sizeof(INPUT)))
1485 {
1486 EngSetLastError(ERROR_INVALID_PARAMETER);
1487 RETURN( 0);
1488 }
1489
1490 /*
1491 * FIXME - check access rights of the window station
1492 * e.g. services running in the service window station cannot block input
1493 */
1494 if(!ThreadHasInputAccess(W32Thread) ||
1495 !IntIsActiveDesktop(W32Thread->rpdesk))
1496 {
1497 EngSetLastError(ERROR_ACCESS_DENIED);
1498 RETURN( 0);
1499 }
1500
1501 cnt = 0;
1502 while(nInputs--)
1503 {
1504 INPUT SafeInput;
1505 NTSTATUS Status;
1506
1507 Status = MmCopyFromCaller(&SafeInput, pInput++, sizeof(INPUT));
1508 if(!NT_SUCCESS(Status))
1509 {
1510 SetLastNtError(Status);
1511 RETURN( cnt);
1512 }
1513
1514 switch(SafeInput.type)
1515 {
1516 case INPUT_MOUSE:
1517 if(IntMouseInput(&SafeInput.mi, TRUE))
1518 {
1519 cnt++;
1520 }
1521 break;
1522 case INPUT_KEYBOARD:
1523 if(IntKeyboardInput(&SafeInput.ki, TRUE))
1524 {
1525 cnt++;
1526 }
1527 break;
1528 case INPUT_HARDWARE:
1529 break;
1530 #ifndef NDEBUG
1531
1532 default:
1533 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput.type);
1534 break;
1535 #endif
1536
1537 }
1538 }
1539
1540 RETURN( cnt);
1541
1542 CLEANUP:
1543 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_);
1544 UserLeave();
1545 END_CLEANUP;
1546 }
1547
1548 BOOL
1549 FASTCALL
1550 IntQueryTrackMouseEvent(
1551 LPTRACKMOUSEEVENT lpEventTrack)
1552 {
1553 PDESKTOP pDesk;
1554 PTHREADINFO pti;
1555
1556 pti = PsGetCurrentThreadWin32Thread();
1557 pDesk = pti->rpdesk;
1558
1559 /* Always cleared with size set and return true. */
1560 RtlZeroMemory(lpEventTrack ,sizeof(TRACKMOUSEEVENT));
1561 lpEventTrack->cbSize = sizeof(TRACKMOUSEEVENT);
1562
1563 if ( pDesk->dwDTFlags & (DF_TME_LEAVE|DF_TME_HOVER) &&
1564 pDesk->spwndTrack &&
1565 pti->MessageQueue == pDesk->spwndTrack->head.pti->MessageQueue )
1566 {
1567 if ( pDesk->htEx != HTCLIENT )
1568 lpEventTrack->dwFlags |= TME_NONCLIENT;
1569
1570 if ( pDesk->dwDTFlags & DF_TME_LEAVE )
1571 lpEventTrack->dwFlags |= TME_LEAVE;
1572
1573 if ( pDesk->dwDTFlags & DF_TME_HOVER )
1574 {
1575 lpEventTrack->dwFlags |= TME_HOVER;
1576 lpEventTrack->dwHoverTime = pDesk->dwMouseHoverTime;
1577 }
1578 lpEventTrack->hwndTrack = UserHMGetHandle(pDesk->spwndTrack);
1579 }
1580 return TRUE;
1581 }
1582
1583 BOOL
1584 FASTCALL
1585 IntTrackMouseEvent(
1586 LPTRACKMOUSEEVENT lpEventTrack)
1587 {
1588 PDESKTOP pDesk;
1589 PTHREADINFO pti;
1590 PWND pWnd;
1591 POINT point;
1592
1593 pti = PsGetCurrentThreadWin32Thread();
1594 pDesk = pti->rpdesk;
1595
1596 if (!(pWnd = UserGetWindowObject(lpEventTrack->hwndTrack)))
1597 return FALSE;
1598
1599 if ( pDesk->spwndTrack != pWnd ||
1600 (pDesk->htEx != HTCLIENT) ^ !!(lpEventTrack->dwFlags & TME_NONCLIENT) )
1601 {
1602 if ( lpEventTrack->dwFlags & TME_LEAVE && !(lpEventTrack->dwFlags & TME_CANCEL) )
1603 {
1604 UserPostMessage( lpEventTrack->hwndTrack,
1605 lpEventTrack->dwFlags & TME_NONCLIENT ? WM_NCMOUSELEAVE : WM_MOUSELEAVE,
1606 0, 0);
1607 }
1608 DPRINT("IntTrackMouseEvent spwndTrack 0x%x pwnd 0x%x\n", pDesk->spwndTrack,pWnd);
1609 return TRUE;
1610 }
1611
1612 /* Tracking spwndTrack same as pWnd */
1613 if ( lpEventTrack->dwFlags & TME_CANCEL ) // Canceled mode.
1614 {
1615 if ( lpEventTrack->dwFlags & TME_LEAVE )
1616 pDesk->dwDTFlags &= ~DF_TME_LEAVE;
1617
1618 if ( lpEventTrack->dwFlags & TME_HOVER )
1619 {
1620 if ( pDesk->dwDTFlags & DF_TME_HOVER )
1621 { // Kill hover timer.
1622 IntKillTimer(pWnd, ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE);
1623 pDesk->dwDTFlags &= ~DF_TME_HOVER;
1624 }
1625 }
1626 }
1627 else // Not Canceled.
1628 {
1629 if ( lpEventTrack->dwFlags & TME_LEAVE )
1630 pDesk->dwDTFlags |= DF_TME_LEAVE;
1631
1632 if ( lpEventTrack->dwFlags & TME_HOVER )
1633 {
1634 pDesk->dwDTFlags |= DF_TME_HOVER;
1635
1636 if ( !lpEventTrack->dwHoverTime || lpEventTrack->dwHoverTime == HOVER_DEFAULT )
1637 pDesk->dwMouseHoverTime = gspv.iMouseHoverTime; // use the system default hover time-out.
1638 else
1639 pDesk->dwMouseHoverTime = lpEventTrack->dwHoverTime;
1640 // Start timer for the hover period.
1641 IntSetTimer( pWnd, ID_EVENT_SYSTIMER_MOUSEHOVER, pDesk->dwMouseHoverTime, SystemTimerProc, TMRF_SYSTEM);
1642 // Get windows thread message points.
1643 point = pWnd->head.pti->ptLast;
1644 // Set desktop mouse hover from the system default hover rectangle.
1645 RECTL_vSetRect(&pDesk->rcMouseHover,
1646 point.x - gspv.iMouseHoverWidth / 2,
1647 point.y - gspv.iMouseHoverHeight / 2,
1648 point.x + gspv.iMouseHoverWidth / 2,
1649 point.y + gspv.iMouseHoverHeight / 2);
1650 }
1651 }
1652 return TRUE;
1653 }
1654
1655 BOOL
1656 APIENTRY
1657 NtUserTrackMouseEvent(
1658 LPTRACKMOUSEEVENT lpEventTrack)
1659 {
1660 TRACKMOUSEEVENT saveTME;
1661 BOOL Ret = FALSE;
1662
1663 DPRINT("Enter NtUserTrackMouseEvent\n");
1664 UserEnterExclusive();
1665
1666 _SEH2_TRY
1667 {
1668 ProbeForRead(lpEventTrack, sizeof(TRACKMOUSEEVENT), 1);
1669 RtlCopyMemory(&saveTME, lpEventTrack, sizeof(TRACKMOUSEEVENT));
1670 }
1671 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1672 {
1673 SetLastNtError(_SEH2_GetExceptionCode());
1674 _SEH2_YIELD(goto Exit;)
1675 }
1676 _SEH2_END;
1677
1678 if ( saveTME.cbSize != sizeof(TRACKMOUSEEVENT) )
1679 {
1680 EngSetLastError(ERROR_INVALID_PARAMETER);
1681 goto Exit;
1682 }
1683
1684 if (saveTME.dwFlags & ~(TME_CANCEL|TME_QUERY|TME_NONCLIENT|TME_LEAVE|TME_HOVER) )
1685 {
1686 EngSetLastError(ERROR_INVALID_FLAGS);
1687 goto Exit;
1688 }
1689
1690 if ( saveTME.dwFlags & TME_QUERY )
1691 {
1692 Ret = IntQueryTrackMouseEvent(&saveTME);
1693 _SEH2_TRY
1694 {
1695 ProbeForWrite(lpEventTrack, sizeof(TRACKMOUSEEVENT), 1);
1696 RtlCopyMemory(lpEventTrack, &saveTME, sizeof(TRACKMOUSEEVENT));
1697 }
1698 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1699 {
1700 SetLastNtError(_SEH2_GetExceptionCode());
1701 Ret = FALSE;
1702 }
1703 _SEH2_END;
1704 }
1705 else
1706 {
1707 Ret = IntTrackMouseEvent(&saveTME);
1708 }
1709
1710 Exit:
1711 DPRINT("Leave NtUserTrackMouseEvent, ret=%i\n",Ret);
1712 UserLeave();
1713 return Ret;
1714 }
1715
1716 extern MOUSEMOVEPOINT MouseHistoryOfMoves[];
1717 extern INT gcur_count;
1718
1719 DWORD
1720 APIENTRY
1721 NtUserGetMouseMovePointsEx(
1722 UINT cbSize,
1723 LPMOUSEMOVEPOINT lpptIn,
1724 LPMOUSEMOVEPOINT lpptOut,
1725 int nBufPoints,
1726 DWORD resolution)
1727 {
1728 MOUSEMOVEPOINT Safeppt;
1729 BOOL Hit;
1730 INT Count = -1;
1731 DECLARE_RETURN(DWORD);
1732
1733 DPRINT("Enter NtUserGetMouseMovePointsEx\n");
1734 UserEnterExclusive();
1735
1736 if ((cbSize != sizeof(MOUSEMOVEPOINT)) || (nBufPoints < 0) || (nBufPoints > 64))
1737 {
1738 EngSetLastError(ERROR_INVALID_PARAMETER);
1739 RETURN( -1);
1740 }
1741
1742 if (!lpptIn || (!lpptOut && nBufPoints))
1743 {
1744 EngSetLastError(ERROR_NOACCESS);
1745 RETURN( -1);
1746 }
1747
1748 _SEH2_TRY
1749 {
1750 ProbeForRead( lpptIn, cbSize, 1);
1751 RtlCopyMemory(&Safeppt, lpptIn, cbSize);
1752 }
1753 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1754 {
1755 SetLastNtError(_SEH2_GetExceptionCode());
1756 _SEH2_YIELD(RETURN( -1))
1757 }
1758 _SEH2_END;
1759
1760 // http://msdn.microsoft.com/en-us/library/ms646259(v=vs.85).aspx
1761 // This explains the math issues in transforming points.
1762 Count = gcur_count; // FIFO is forward so retrieve backward.
1763 Hit = FALSE;
1764 do
1765 {
1766 if (Safeppt.x == 0 && Safeppt.y == 0)
1767 break; // No test.
1768 // Finds the point, it returns the last nBufPoints prior to and including the supplied point.
1769 if (MouseHistoryOfMoves[Count].x == Safeppt.x && MouseHistoryOfMoves[Count].y == Safeppt.y)
1770 {
1771 if ( Safeppt.time ) // Now test time and it seems to be absolute.
1772 {
1773 if (Safeppt.time == MouseHistoryOfMoves[Count].time)
1774 {
1775 Hit = TRUE;
1776 break;
1777 }
1778 else
1779 {
1780 if (--Count < 0) Count = 63;
1781 continue;
1782 }
1783 }
1784 Hit = TRUE;
1785 break;
1786 }
1787 if (--Count < 0) Count = 63;
1788 }
1789 while ( Count != gcur_count);
1790
1791 switch(resolution)
1792 {
1793 case GMMP_USE_DISPLAY_POINTS:
1794 if (nBufPoints)
1795 {
1796 _SEH2_TRY
1797 {
1798 ProbeForWrite(lpptOut, cbSize, 1);
1799 }
1800 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1801 {
1802 SetLastNtError(_SEH2_GetExceptionCode());
1803 _SEH2_YIELD(RETURN( -1))
1804 }
1805 _SEH2_END;
1806 }
1807 Count = nBufPoints;
1808 break;
1809 case GMMP_USE_HIGH_RESOLUTION_POINTS:
1810 break;
1811 default:
1812 EngSetLastError(ERROR_POINT_NOT_FOUND);
1813 RETURN( -1);
1814 }
1815
1816 RETURN( Count);
1817
1818 CLEANUP:
1819 DPRINT("Leave NtUserGetMouseMovePointsEx, ret=%i\n",_ret_);
1820 UserLeave();
1821 END_CLEANUP;
1822 }
1823
1824 /* EOF */