[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: 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 {
1304 if( TrackSysKey == VK_MENU || /* <ALT>-down/<ALT>-up sequence */
1305 (wVkStripped != VK_MENU)) /* <ALT>-down...<something else>-up */
1306 Msg.message = WM_SYSKEYUP;
1307 TrackSysKey = 0;
1308 }
1309 flags |= KF_REPEAT | KF_UP;
1310 }
1311 else
1312 {
1313 Msg.message = WM_KEYDOWN;
1314 if ((gQueueKeyStateTable[VK_MENU] & 0x80 || wVkStripped == VK_MENU) &&
1315 !(gQueueKeyStateTable[VK_CONTROL] & 0x80 || wVkStripped == VK_CONTROL))
1316 {
1317 Msg.message = WM_SYSKEYDOWN;
1318 TrackSysKey = wVkStripped;
1319 }
1320 if (!(ki->dwFlags & KEYEVENTF_UNICODE) && gQueueKeyStateTable[wVk] & 0x80) flags |= KF_REPEAT;
1321 }
1322
1323 if (ki->dwFlags & KEYEVENTF_UNICODE)
1324 {
1325 vk_hook = Msg.wParam = wVk = VK_PACKET;
1326 Msg.lParam = MAKELPARAM(1 /* repeat count */, ki->wScan);
1327 }
1328
1329 FocusMessageQueue = IntGetFocusMessageQueue();
1330
1331 Msg.hwnd = 0;
1332
1333 if (FocusMessageQueue && (FocusMessageQueue->FocusWindow != (HWND)0))
1334 Msg.hwnd = FocusMessageQueue->FocusWindow;
1335
1336 if (!ki->time)
1337 {
1338 KeQueryTickCount(&LargeTickCount);
1339 Msg.time = MsqCalculateMessageTime(&LargeTickCount);
1340 }
1341 else
1342 Msg.time = ki->time;
1343
1344 /* All messages have to contain the cursor point. */
1345 Msg.pt = gpsi->ptCursor;
1346
1347 KbdHookData.vkCode = vk_hook;
1348 KbdHookData.scanCode = ki->wScan;
1349 KbdHookData.flags = flags >> 8;
1350 if (Injected) KbdHookData.flags |= LLKHF_INJECTED;
1351 KbdHookData.time = Msg.time;
1352 KbdHookData.dwExtraInfo = ki->dwExtraInfo;
1353 if (co_HOOK_CallHooks(WH_KEYBOARD_LL, HC_ACTION, Msg.message, (LPARAM) &KbdHookData))
1354 {
1355 DPRINT1("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1356 Msg.message, vk_hook, Msg.lParam);
1357
1358 return FALSE;
1359 }
1360
1361 if (!(ki->dwFlags & KEYEVENTF_UNICODE))
1362 {
1363 if (ki->dwFlags & KEYEVENTF_KEYUP)
1364 {
1365 gQueueKeyStateTable[wVk] &= ~0x80;
1366 gQueueKeyStateTable[wVkStripped] = gQueueKeyStateTable[wVkL] | gQueueKeyStateTable[wVkR];
1367 }
1368 else
1369 {
1370 if (!(gQueueKeyStateTable[wVk] & 0x80)) gQueueKeyStateTable[wVk] ^= 0x01;
1371 gQueueKeyStateTable[wVk] |= 0xc0;
1372 gQueueKeyStateTable[wVkStripped] = gQueueKeyStateTable[wVkL] | gQueueKeyStateTable[wVkR];
1373 }
1374
1375 if (gQueueKeyStateTable[VK_MENU] & 0x80) flags |= KF_ALTDOWN;
1376
1377 if (wVkStripped == VK_SHIFT) flags &= ~KF_EXTENDED;
1378
1379 Msg.lParam = MAKELPARAM(1 /* repeat count */, flags);
1380 }
1381
1382 if (FocusMessageQueue == NULL)
1383 {
1384 DPRINT("No focus message queue\n");
1385
1386 return FALSE;
1387 }
1388
1389 if (FocusMessageQueue->FocusWindow != (HWND)0)
1390 {
1391 Msg.hwnd = FocusMessageQueue->FocusWindow;
1392 DPRINT("Msg.hwnd = %x\n", Msg.hwnd);
1393
1394 FocusMessageQueue->Desktop->pDeskInfo->LastInputWasKbd = TRUE;
1395
1396 Msg.pt = gpsi->ptCursor;
1397 // Post to hardware queue, based on the first part of wine "some GetMessage tests"
1398 // in test_PeekMessage()
1399 MsqPostMessage(FocusMessageQueue, &Msg, TRUE, QS_KEY);
1400 }
1401 else
1402 {
1403 DPRINT("Invalid focus window handle\n");
1404 }
1405
1406 return TRUE;
1407 }
1408
1409 BOOL FASTCALL
1410 UserAttachThreadInput( PTHREADINFO pti, PTHREADINFO ptiTo, BOOL fAttach)
1411 {
1412 PATTACHINFO pai;
1413
1414 /* Can not be the same thread.*/
1415 if (pti == ptiTo) return FALSE;
1416
1417 /* Do not attach to system threads or between different desktops. */
1418 if ( pti->TIF_flags & TIF_DONTATTACHQUEUE ||
1419 ptiTo->TIF_flags & TIF_DONTATTACHQUEUE ||
1420 pti->rpdesk != ptiTo->rpdesk )
1421 return FALSE;
1422
1423 /* If Attach set, allocate and link. */
1424 if ( fAttach )
1425 {
1426 pai = ExAllocatePoolWithTag(PagedPool, sizeof(ATTACHINFO), USERTAG_ATTACHINFO);
1427 if ( !pai ) return FALSE;
1428
1429 pai->paiNext = gpai;
1430 pai->pti1 = pti;
1431 pai->pti2 = ptiTo;
1432 gpai = pai;
1433 }
1434 else /* If clear, unlink and free it. */
1435 {
1436 PATTACHINFO paiprev = NULL;
1437
1438 if ( !gpai ) return FALSE;
1439
1440 pai = gpai;
1441
1442 /* Search list and free if found or return false. */
1443 do
1444 {
1445 if ( pai->pti2 == ptiTo && pai->pti1 == pti ) break;
1446 paiprev = pai;
1447 pai = pai->paiNext;
1448 } while (pai);
1449
1450 if ( !pai ) return FALSE;
1451
1452 if (paiprev) paiprev->paiNext = pai->paiNext;
1453
1454 ExFreePoolWithTag(pai, USERTAG_ATTACHINFO);
1455 }
1456
1457 return TRUE;
1458 }
1459
1460 UINT
1461 APIENTRY
1462 NtUserSendInput(
1463 UINT nInputs,
1464 LPINPUT pInput,
1465 INT cbSize)
1466 {
1467 PTHREADINFO W32Thread;
1468 UINT cnt;
1469 DECLARE_RETURN(UINT);
1470
1471 DPRINT("Enter NtUserSendInput\n");
1472 UserEnterExclusive();
1473
1474 W32Thread = PsGetCurrentThreadWin32Thread();
1475 ASSERT(W32Thread);
1476
1477 if(!W32Thread->rpdesk)
1478 {
1479 RETURN( 0);
1480 }
1481
1482 if(!nInputs || !pInput || (cbSize != sizeof(INPUT)))
1483 {
1484 EngSetLastError(ERROR_INVALID_PARAMETER);
1485 RETURN( 0);
1486 }
1487
1488 /*
1489 * FIXME - check access rights of the window station
1490 * e.g. services running in the service window station cannot block input
1491 */
1492 if(!ThreadHasInputAccess(W32Thread) ||
1493 !IntIsActiveDesktop(W32Thread->rpdesk))
1494 {
1495 EngSetLastError(ERROR_ACCESS_DENIED);
1496 RETURN( 0);
1497 }
1498
1499 cnt = 0;
1500 while(nInputs--)
1501 {
1502 INPUT SafeInput;
1503 NTSTATUS Status;
1504
1505 Status = MmCopyFromCaller(&SafeInput, pInput++, sizeof(INPUT));
1506 if(!NT_SUCCESS(Status))
1507 {
1508 SetLastNtError(Status);
1509 RETURN( cnt);
1510 }
1511
1512 switch(SafeInput.type)
1513 {
1514 case INPUT_MOUSE:
1515 if(IntMouseInput(&SafeInput.mi, TRUE))
1516 {
1517 cnt++;
1518 }
1519 break;
1520 case INPUT_KEYBOARD:
1521 if(IntKeyboardInput(&SafeInput.ki, TRUE))
1522 {
1523 cnt++;
1524 }
1525 break;
1526 case INPUT_HARDWARE:
1527 break;
1528 #ifndef NDEBUG
1529
1530 default:
1531 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput.type);
1532 break;
1533 #endif
1534
1535 }
1536 }
1537
1538 RETURN( cnt);
1539
1540 CLEANUP:
1541 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_);
1542 UserLeave();
1543 END_CLEANUP;
1544 }
1545
1546 BOOL
1547 FASTCALL
1548 IntQueryTrackMouseEvent(
1549 LPTRACKMOUSEEVENT lpEventTrack)
1550 {
1551 PDESKTOP pDesk;
1552 PTHREADINFO pti;
1553
1554 pti = PsGetCurrentThreadWin32Thread();
1555 pDesk = pti->rpdesk;
1556
1557 /* Always cleared with size set and return true. */
1558 RtlZeroMemory(lpEventTrack ,sizeof(TRACKMOUSEEVENT));
1559 lpEventTrack->cbSize = sizeof(TRACKMOUSEEVENT);
1560
1561 if ( pDesk->dwDTFlags & (DF_TME_LEAVE|DF_TME_HOVER) &&
1562 pDesk->spwndTrack &&
1563 pti->MessageQueue == pDesk->spwndTrack->head.pti->MessageQueue )
1564 {
1565 if ( pDesk->htEx != HTCLIENT )
1566 lpEventTrack->dwFlags |= TME_NONCLIENT;
1567
1568 if ( pDesk->dwDTFlags & DF_TME_LEAVE )
1569 lpEventTrack->dwFlags |= TME_LEAVE;
1570
1571 if ( pDesk->dwDTFlags & DF_TME_HOVER )
1572 {
1573 lpEventTrack->dwFlags |= TME_HOVER;
1574 lpEventTrack->dwHoverTime = pDesk->dwMouseHoverTime;
1575 }
1576 lpEventTrack->hwndTrack = UserHMGetHandle(pDesk->spwndTrack);
1577 }
1578 return TRUE;
1579 }
1580
1581 BOOL
1582 FASTCALL
1583 IntTrackMouseEvent(
1584 LPTRACKMOUSEEVENT lpEventTrack)
1585 {
1586 PDESKTOP pDesk;
1587 PTHREADINFO pti;
1588 PWND pWnd;
1589 POINT point;
1590
1591 pti = PsGetCurrentThreadWin32Thread();
1592 pDesk = pti->rpdesk;
1593
1594 if (!(pWnd = UserGetWindowObject(lpEventTrack->hwndTrack)))
1595 return FALSE;
1596
1597 if ( pDesk->spwndTrack != pWnd ||
1598 (pDesk->htEx != HTCLIENT) ^ !!(lpEventTrack->dwFlags & TME_NONCLIENT) )
1599 {
1600 if ( lpEventTrack->dwFlags & TME_LEAVE && !(lpEventTrack->dwFlags & TME_CANCEL) )
1601 {
1602 UserPostMessage( lpEventTrack->hwndTrack,
1603 lpEventTrack->dwFlags & TME_NONCLIENT ? WM_NCMOUSELEAVE : WM_MOUSELEAVE,
1604 0, 0);
1605 }
1606 DPRINT("IntTrackMouseEvent spwndTrack 0x%x pwnd 0x%x\n", pDesk->spwndTrack,pWnd);
1607 return TRUE;
1608 }
1609
1610 /* Tracking spwndTrack same as pWnd */
1611 if ( lpEventTrack->dwFlags & TME_CANCEL ) // Canceled mode.
1612 {
1613 if ( lpEventTrack->dwFlags & TME_LEAVE )
1614 pDesk->dwDTFlags &= ~DF_TME_LEAVE;
1615
1616 if ( lpEventTrack->dwFlags & TME_HOVER )
1617 {
1618 if ( pDesk->dwDTFlags & DF_TME_HOVER )
1619 { // Kill hover timer.
1620 IntKillTimer(pWnd, ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE);
1621 pDesk->dwDTFlags &= ~DF_TME_HOVER;
1622 }
1623 }
1624 }
1625 else // Not Canceled.
1626 {
1627 if ( lpEventTrack->dwFlags & TME_LEAVE )
1628 pDesk->dwDTFlags |= DF_TME_LEAVE;
1629
1630 if ( lpEventTrack->dwFlags & TME_HOVER )
1631 {
1632 pDesk->dwDTFlags |= DF_TME_HOVER;
1633
1634 if ( !lpEventTrack->dwHoverTime || lpEventTrack->dwHoverTime == HOVER_DEFAULT )
1635 pDesk->dwMouseHoverTime = gspv.iMouseHoverTime; // use the system default hover time-out.
1636 else
1637 pDesk->dwMouseHoverTime = lpEventTrack->dwHoverTime;
1638 // Start timer for the hover period.
1639 IntSetTimer( pWnd, ID_EVENT_SYSTIMER_MOUSEHOVER, pDesk->dwMouseHoverTime, SystemTimerProc, TMRF_SYSTEM);
1640 // Get windows thread message points.
1641 point = pWnd->head.pti->ptLast;
1642 // Set desktop mouse hover from the system default hover rectangle.
1643 RECTL_vSetRect(&pDesk->rcMouseHover,
1644 point.x - gspv.iMouseHoverWidth / 2,
1645 point.y - gspv.iMouseHoverHeight / 2,
1646 point.x + gspv.iMouseHoverWidth / 2,
1647 point.y + gspv.iMouseHoverHeight / 2);
1648 }
1649 }
1650 return TRUE;
1651 }
1652
1653 BOOL
1654 APIENTRY
1655 NtUserTrackMouseEvent(
1656 LPTRACKMOUSEEVENT lpEventTrack)
1657 {
1658 TRACKMOUSEEVENT saveTME;
1659 BOOL Ret = FALSE;
1660
1661 DPRINT("Enter NtUserTrackMouseEvent\n");
1662 UserEnterExclusive();
1663
1664 _SEH2_TRY
1665 {
1666 ProbeForRead(lpEventTrack, sizeof(TRACKMOUSEEVENT), 1);
1667 RtlCopyMemory(&saveTME, lpEventTrack, sizeof(TRACKMOUSEEVENT));
1668 }
1669 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1670 {
1671 SetLastNtError(_SEH2_GetExceptionCode());
1672 _SEH2_YIELD(goto Exit;)
1673 }
1674 _SEH2_END;
1675
1676 if ( saveTME.cbSize != sizeof(TRACKMOUSEEVENT) )
1677 {
1678 EngSetLastError(ERROR_INVALID_PARAMETER);
1679 goto Exit;
1680 }
1681
1682 if (saveTME.dwFlags & ~(TME_CANCEL|TME_QUERY|TME_NONCLIENT|TME_LEAVE|TME_HOVER) )
1683 {
1684 EngSetLastError(ERROR_INVALID_FLAGS);
1685 goto Exit;
1686 }
1687
1688 if ( saveTME.dwFlags & TME_QUERY )
1689 {
1690 Ret = IntQueryTrackMouseEvent(&saveTME);
1691 _SEH2_TRY
1692 {
1693 ProbeForWrite(lpEventTrack, sizeof(TRACKMOUSEEVENT), 1);
1694 RtlCopyMemory(lpEventTrack, &saveTME, sizeof(TRACKMOUSEEVENT));
1695 }
1696 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1697 {
1698 SetLastNtError(_SEH2_GetExceptionCode());
1699 Ret = FALSE;
1700 }
1701 _SEH2_END;
1702 }
1703 else
1704 {
1705 Ret = IntTrackMouseEvent(&saveTME);
1706 }
1707
1708 Exit:
1709 DPRINT("Leave NtUserTrackMouseEvent, ret=%i\n",Ret);
1710 UserLeave();
1711 return Ret;
1712 }
1713
1714 extern MOUSEMOVEPOINT MouseHistoryOfMoves[];
1715 extern INT gcur_count;
1716
1717 DWORD
1718 APIENTRY
1719 NtUserGetMouseMovePointsEx(
1720 UINT cbSize,
1721 LPMOUSEMOVEPOINT lpptIn,
1722 LPMOUSEMOVEPOINT lpptOut,
1723 int nBufPoints,
1724 DWORD resolution)
1725 {
1726 MOUSEMOVEPOINT Safeppt;
1727 BOOL Hit;
1728 INT Count = -1;
1729 DECLARE_RETURN(DWORD);
1730
1731 DPRINT("Enter NtUserGetMouseMovePointsEx\n");
1732 UserEnterExclusive();
1733
1734 if ((cbSize != sizeof(MOUSEMOVEPOINT)) || (nBufPoints < 0) || (nBufPoints > 64))
1735 {
1736 EngSetLastError(ERROR_INVALID_PARAMETER);
1737 RETURN( -1);
1738 }
1739
1740 if (!lpptIn || (!lpptOut && nBufPoints))
1741 {
1742 EngSetLastError(ERROR_NOACCESS);
1743 RETURN( -1);
1744 }
1745
1746 _SEH2_TRY
1747 {
1748 ProbeForRead( lpptIn, cbSize, 1);
1749 RtlCopyMemory(&Safeppt, lpptIn, cbSize);
1750 }
1751 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1752 {
1753 SetLastNtError(_SEH2_GetExceptionCode());
1754 _SEH2_YIELD(RETURN( -1))
1755 }
1756 _SEH2_END;
1757
1758 // http://msdn.microsoft.com/en-us/library/ms646259(v=vs.85).aspx
1759 // This explains the math issues in transforming points.
1760 Count = gcur_count; // FIFO is forward so retrieve backward.
1761 Hit = FALSE;
1762 do
1763 {
1764 if (Safeppt.x == 0 && Safeppt.y == 0)
1765 break; // No test.
1766 // Finds the point, it returns the last nBufPoints prior to and including the supplied point.
1767 if (MouseHistoryOfMoves[Count].x == Safeppt.x && MouseHistoryOfMoves[Count].y == Safeppt.y)
1768 {
1769 if ( Safeppt.time ) // Now test time and it seems to be absolute.
1770 {
1771 if (Safeppt.time == MouseHistoryOfMoves[Count].time)
1772 {
1773 Hit = TRUE;
1774 break;
1775 }
1776 else
1777 {
1778 if (--Count < 0) Count = 63;
1779 continue;
1780 }
1781 }
1782 Hit = TRUE;
1783 break;
1784 }
1785 if (--Count < 0) Count = 63;
1786 }
1787 while ( Count != gcur_count);
1788
1789 switch(resolution)
1790 {
1791 case GMMP_USE_DISPLAY_POINTS:
1792 if (nBufPoints)
1793 {
1794 _SEH2_TRY
1795 {
1796 ProbeForWrite(lpptOut, cbSize, 1);
1797 }
1798 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1799 {
1800 SetLastNtError(_SEH2_GetExceptionCode());
1801 _SEH2_YIELD(RETURN( -1))
1802 }
1803 _SEH2_END;
1804 }
1805 Count = nBufPoints;
1806 break;
1807 case GMMP_USE_HIGH_RESOLUTION_POINTS:
1808 break;
1809 default:
1810 EngSetLastError(ERROR_POINT_NOT_FOUND);
1811 RETURN( -1);
1812 }
1813
1814 RETURN( Count);
1815
1816 CLEANUP:
1817 DPRINT("Leave NtUserGetMouseMovePointsEx, ret=%i\n",_ret_);
1818 UserLeave();
1819 END_CLEANUP;
1820 }
1821
1822 /* EOF */