[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 DBG_DEFAULT_CHANNEL(UserInput);
17
18 extern BYTE gKeyStateTable[];
19 extern NTSTATUS Win32kInitWin32Thread(PETHREAD Thread);
20 extern PPROCESSINFO ppiScrnSaver;
21
22 /* GLOBALS *******************************************************************/
23
24 PTHREADINFO ptiRawInput;
25 PTHREADINFO ptiKeyboard;
26 PTHREADINFO ptiMouse;
27 PKTIMER MasterTimer = NULL;
28 PATTACHINFO gpai = NULL;
29
30 static DWORD LastInputTick = 0;
31 static HANDLE MouseDeviceHandle;
32 static HANDLE MouseThreadHandle;
33 static CLIENT_ID MouseThreadId;
34 static HANDLE KeyboardThreadHandle;
35 static CLIENT_ID KeyboardThreadId;
36 static HANDLE KeyboardDeviceHandle;
37 static HANDLE RawInputThreadHandle;
38 static CLIENT_ID RawInputThreadId;
39 static KEVENT InputThreadsStart;
40 static BOOLEAN InputThreadsRunning = FALSE;
41 static BYTE TrackSysKey = 0; /* determine whether ALT key up will cause a WM_SYSKEYUP
42 or a WM_KEYUP message */
43
44 /* FUNCTIONS *****************************************************************/
45 DWORD IntLastInputTick(BOOL LastInputTickSetGet);
46
47 #define ClearMouseInput(mi) \
48 mi.dx = 0; \
49 mi.dy = 0; \
50 mi.mouseData = 0; \
51 mi.dwFlags = 0;
52
53 #define SendMouseEvent(mi) \
54 if(mi.dx != 0 || mi.dy != 0) \
55 mi.dwFlags |= MOUSEEVENTF_MOVE; \
56 if(mi.dwFlags) \
57 IntMouseInput(&mi,FALSE); \
58 ClearMouseInput(mi);
59
60
61 DWORD IntLastInputTick(BOOL LastInputTickSetGet)
62 {
63 if (LastInputTickSetGet == TRUE)
64 {
65 LARGE_INTEGER TickCount;
66 KeQueryTickCount(&TickCount);
67 LastInputTick = MsqCalculateMessageTime(&TickCount);
68 if (gpsi) gpsi->dwLastRITEventTickCount = LastInputTick;
69 }
70 return LastInputTick;
71 }
72
73
74 VOID FASTCALL DoTheScreenSaver(VOID)
75 {
76 LARGE_INTEGER TickCount;
77 DWORD Test, TO;
78
79 if (gspv.iScrSaverTimeout > 0) // Zero means Off.
80 {
81 KeQueryTickCount(&TickCount);
82 Test = MsqCalculateMessageTime(&TickCount);
83 Test = Test - LastInputTick;
84 TO = 1000 * gspv.iScrSaverTimeout;
85 if (Test > TO)
86 {
87 TRACE("Screensaver Message Start! Tick %d Timeout %d \n", Test, gspv.iScrSaverTimeout);
88
89 if (ppiScrnSaver) // We are or we are not the screensaver, prevent reentry...
90 {
91 if (!(ppiScrnSaver->W32PF_flags & W32PF_IDLESCREENSAVER))
92 {
93 ppiScrnSaver->W32PF_flags |= W32PF_IDLESCREENSAVER;
94 ERR("Screensaver is Idle\n");
95 }
96 }
97 else
98 {
99 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
100 if (ForegroundQueue && ForegroundQueue->ActiveWindow)
101 UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_START_SCREENSAVE, 1); // lParam 1 == Secure
102 else
103 UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_START_SCREENSAVE, 0);
104 }
105 }
106 }
107 }
108
109 VOID FASTCALL
110 ProcessMouseInputData(PMOUSE_INPUT_DATA Data, ULONG InputCount)
111 {
112 PMOUSE_INPUT_DATA mid;
113 MOUSEINPUT mi;
114 ULONG i;
115
116 ClearMouseInput(mi);
117 mi.time = 0;
118 mi.dwExtraInfo = 0;
119 for(i = 0; i < InputCount; i++)
120 {
121 mid = (Data + i);
122 mi.dx += mid->LastX;
123 mi.dy += mid->LastY;
124
125 /* Check if the mouse move is absolute */
126 if (mid->Flags == MOUSE_MOVE_ABSOLUTE)
127 {
128 /* Set flag to convert to screen location */
129 mi.dwFlags |= MOUSEEVENTF_ABSOLUTE;
130 }
131
132 if(mid->ButtonFlags)
133 {
134 if(mid->ButtonFlags & MOUSE_LEFT_BUTTON_DOWN)
135 {
136 mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
137 SendMouseEvent(mi);
138 }
139 if(mid->ButtonFlags & MOUSE_LEFT_BUTTON_UP)
140 {
141 mi.dwFlags |= MOUSEEVENTF_LEFTUP;
142 SendMouseEvent(mi);
143 }
144 if(mid->ButtonFlags & MOUSE_MIDDLE_BUTTON_DOWN)
145 {
146 mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
147 SendMouseEvent(mi);
148 }
149 if(mid->ButtonFlags & MOUSE_MIDDLE_BUTTON_UP)
150 {
151 mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
152 SendMouseEvent(mi);
153 }
154 if(mid->ButtonFlags & MOUSE_RIGHT_BUTTON_DOWN)
155 {
156 mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
157 SendMouseEvent(mi);
158 }
159 if(mid->ButtonFlags & MOUSE_RIGHT_BUTTON_UP)
160 {
161 mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
162 SendMouseEvent(mi);
163 }
164 if(mid->ButtonFlags & MOUSE_BUTTON_4_DOWN)
165 {
166 mi.mouseData |= XBUTTON1;
167 mi.dwFlags |= MOUSEEVENTF_XDOWN;
168 SendMouseEvent(mi);
169 }
170 if(mid->ButtonFlags & MOUSE_BUTTON_4_UP)
171 {
172 mi.mouseData |= XBUTTON1;
173 mi.dwFlags |= MOUSEEVENTF_XUP;
174 SendMouseEvent(mi);
175 }
176 if(mid->ButtonFlags & MOUSE_BUTTON_5_DOWN)
177 {
178 mi.mouseData |= XBUTTON2;
179 mi.dwFlags |= MOUSEEVENTF_XDOWN;
180 SendMouseEvent(mi);
181 }
182 if(mid->ButtonFlags & MOUSE_BUTTON_5_UP)
183 {
184 mi.mouseData |= XBUTTON2;
185 mi.dwFlags |= MOUSEEVENTF_XUP;
186 SendMouseEvent(mi);
187 }
188 if(mid->ButtonFlags & MOUSE_WHEEL)
189 {
190 mi.mouseData = mid->ButtonData;
191 mi.dwFlags |= MOUSEEVENTF_WHEEL;
192 SendMouseEvent(mi);
193 }
194 }
195 }
196
197 SendMouseEvent(mi);
198 }
199
200
201
202
203 VOID APIENTRY
204 MouseThreadMain(PVOID StartContext)
205 {
206 UNICODE_STRING MouseDeviceName = RTL_CONSTANT_STRING(L"\\Device\\PointerClass0");
207 OBJECT_ATTRIBUTES MouseObjectAttributes;
208 IO_STATUS_BLOCK Iosb;
209 NTSTATUS Status;
210 MOUSE_ATTRIBUTES MouseAttr;
211
212 KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
213 LOW_REALTIME_PRIORITY + 3);
214
215 InitializeObjectAttributes(&MouseObjectAttributes,
216 &MouseDeviceName,
217 0,
218 NULL,
219 NULL);
220 do
221 {
222 LARGE_INTEGER DueTime;
223 KEVENT Event;
224 DueTime.QuadPart = (LONGLONG)(-10000000);
225 KeInitializeEvent(&Event, NotificationEvent, FALSE);
226 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime);
227 Status = NtOpenFile(&MouseDeviceHandle,
228 FILE_ALL_ACCESS,
229 &MouseObjectAttributes,
230 &Iosb,
231 0,
232 FILE_SYNCHRONOUS_IO_ALERT);
233 } while (!NT_SUCCESS(Status));
234
235 /* Need to setup basic win32k for this thread to process WH_MOUSE_LL messages. */
236 Status = Win32kInitWin32Thread(PsGetCurrentThread());
237 if (!NT_SUCCESS(Status))
238 {
239 ERR("Win32K: Failed making mouse thread a win32 thread.\n");
240 return; //(Status);
241 }
242
243 ptiMouse = PsGetCurrentThreadWin32Thread();
244 ptiMouse->TIF_flags |= TIF_SYSTEMTHREAD;
245 TRACE("Mouse Thread 0x%x \n", ptiMouse);
246
247 KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
248 LOW_REALTIME_PRIORITY + 3);
249
250 for(;;)
251 {
252 /*
253 * Wait to start input.
254 */
255 TRACE("Mouse Input Thread Waiting for start event\n");
256 Status = KeWaitForSingleObject(&InputThreadsStart,
257 0,
258 KernelMode,
259 TRUE,
260 NULL);
261 TRACE("Mouse Input Thread Starting...\n");
262
263 /*FIXME: Does mouse attributes need to be used for anything */
264 Status = NtDeviceIoControlFile(MouseDeviceHandle,
265 NULL,
266 NULL,
267 NULL,
268 &Iosb,
269 IOCTL_MOUSE_QUERY_ATTRIBUTES,
270 &MouseAttr, sizeof(MOUSE_ATTRIBUTES),
271 NULL, 0);
272 if(!NT_SUCCESS(Status))
273 {
274 TRACE("Failed to get mouse attributes\n");
275 }
276
277 /*
278 * Receive and process mouse input.
279 */
280 while(InputThreadsRunning)
281 {
282 MOUSE_INPUT_DATA MouseInput;
283 Status = NtReadFile(MouseDeviceHandle,
284 NULL,
285 NULL,
286 NULL,
287 &Iosb,
288 &MouseInput,
289 sizeof(MOUSE_INPUT_DATA),
290 NULL,
291 NULL);
292 if(Status == STATUS_ALERTED && !InputThreadsRunning)
293 {
294 break;
295 }
296 if(Status == STATUS_PENDING)
297 {
298 NtWaitForSingleObject(MouseDeviceHandle, FALSE, NULL);
299 Status = Iosb.Status;
300 }
301 if(!NT_SUCCESS(Status))
302 {
303 ERR("Win32K: Failed to read from mouse.\n");
304 return; //(Status);
305 }
306 TRACE("MouseEvent\n");
307 IntLastInputTick(TRUE);
308
309 UserEnterExclusive();
310
311 ProcessMouseInputData(&MouseInput, Iosb.Information / sizeof(MOUSE_INPUT_DATA));
312
313 UserLeave();
314 }
315 TRACE("Mouse Input Thread Stopped...\n");
316 }
317 }
318
319 /* Returns a value that indicates if the key is a modifier key, and
320 * which one.
321 */
322 static UINT APIENTRY
323 IntKeyboardGetModifiers(KEYBOARD_INPUT_DATA *InputData)
324 {
325 if (InputData->Flags & KEY_E1)
326 return 0;
327
328 if (!(InputData->Flags & KEY_E0))
329 {
330 switch (InputData->MakeCode)
331 {
332 case 0x2a: /* left shift */
333 case 0x36: /* right shift */
334 return MOD_SHIFT;
335
336 case 0x1d: /* left control */
337 return MOD_CONTROL;
338
339 case 0x38: /* left alt */
340 return MOD_ALT;
341
342 default:
343 return 0;
344 }
345 }
346 else
347 {
348 switch (InputData->MakeCode)
349 {
350 case 0x1d: /* right control */
351 return MOD_CONTROL;
352
353 case 0x38: /* right alt */
354 return MOD_ALT;
355
356 case 0x5b: /* left gui (windows) */
357 case 0x5c: /* right gui (windows) */
358 return MOD_WIN;
359
360 default:
361 return 0;
362 }
363 }
364 }
365
366 /* Asks the keyboard driver to send a small table that shows which
367 * lights should connect with which scancodes
368 */
369 static NTSTATUS APIENTRY
370 IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle,
371 PKEYBOARD_INDICATOR_TRANSLATION *IndicatorTrans)
372 {
373 NTSTATUS Status;
374 DWORD Size = 0;
375 IO_STATUS_BLOCK Block;
376 PKEYBOARD_INDICATOR_TRANSLATION Ret;
377
378 Size = sizeof(KEYBOARD_INDICATOR_TRANSLATION);
379
380 Ret = ExAllocatePoolWithTag(PagedPool,
381 Size,
382 USERTAG_KBDTABLE);
383
384 while (Ret)
385 {
386 Status = NtDeviceIoControlFile(KeyboardDeviceHandle,
387 NULL,
388 NULL,
389 NULL,
390 &Block,
391 IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION,
392 NULL, 0,
393 Ret, Size);
394
395 if (Status != STATUS_BUFFER_TOO_SMALL)
396 break;
397
398 ExFreePoolWithTag(Ret, USERTAG_KBDTABLE);
399
400 Size += sizeof(KEYBOARD_INDICATOR_TRANSLATION);
401
402 Ret = ExAllocatePoolWithTag(PagedPool,
403 Size,
404 USERTAG_KBDTABLE);
405 }
406
407 if (!Ret)
408 return STATUS_INSUFFICIENT_RESOURCES;
409
410 if (Status != STATUS_SUCCESS)
411 {
412 ExFreePoolWithTag(Ret, USERTAG_KBDTABLE);
413 return Status;
414 }
415
416 *IndicatorTrans = Ret;
417 return Status;
418 }
419
420 /* Sends the keyboard commands to turn on/off the lights.
421 */
422 static NTSTATUS APIENTRY
423 IntKeyboardUpdateLeds(HANDLE KeyboardDeviceHandle,
424 PKEYBOARD_INPUT_DATA KeyInput,
425 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans)
426 {
427 NTSTATUS Status;
428 UINT Count;
429 static KEYBOARD_INDICATOR_PARAMETERS Indicators;
430 IO_STATUS_BLOCK Block;
431
432 if (!IndicatorTrans)
433 return STATUS_NOT_SUPPORTED;
434
435 if (KeyInput->Flags & (KEY_E0 | KEY_E1 | KEY_BREAK))
436 return STATUS_SUCCESS;
437
438 for (Count = 0; Count < IndicatorTrans->NumberOfIndicatorKeys; Count++)
439 {
440 if (KeyInput->MakeCode == IndicatorTrans->IndicatorList[Count].MakeCode)
441 {
442 Indicators.LedFlags ^=
443 IndicatorTrans->IndicatorList[Count].IndicatorFlags;
444
445 /* Update the lights on the hardware */
446
447 Status = NtDeviceIoControlFile(KeyboardDeviceHandle,
448 NULL,
449 NULL,
450 NULL,
451 &Block,
452 IOCTL_KEYBOARD_SET_INDICATORS,
453 &Indicators, sizeof(Indicators),
454 NULL, 0);
455
456 return Status;
457 }
458 }
459
460 return STATUS_SUCCESS;
461 }
462
463 static VOID APIENTRY
464 IntKeyboardSendWinKeyMsg()
465 {
466 PWND Window;
467 MSG Mesg;
468
469 if (!(Window = UserGetWindowObject(InputWindowStation->ShellWindow)))
470 {
471 ERR("Couldn't find window to send Windows key message!\n");
472 return;
473 }
474
475 Mesg.hwnd = InputWindowStation->ShellWindow;
476 Mesg.message = WM_SYSCOMMAND;
477 Mesg.wParam = SC_TASKLIST;
478 Mesg.lParam = 0;
479
480 /* The QS_HOTKEY is just a guess */
481 MsqPostMessage(Window->head.pti->MessageQueue, &Mesg, FALSE, QS_HOTKEY);
482 }
483
484 static VOID APIENTRY
485 co_IntKeyboardSendAltKeyMsg()
486 {
487 ERR("co_IntKeyboardSendAltKeyMsg\n");
488 // co_MsqPostKeyboardMessage(WM_SYSCOMMAND,SC_KEYMENU,0); // This sends everything into a msg loop!
489 }
490
491 static VOID APIENTRY
492 KeyboardThreadMain(PVOID StartContext)
493 {
494 UNICODE_STRING KeyboardDeviceName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardClass0");
495 OBJECT_ATTRIBUTES KeyboardObjectAttributes;
496 IO_STATUS_BLOCK Iosb;
497 NTSTATUS Status;
498 MSG msg;
499 PUSER_MESSAGE_QUEUE FocusQueue;
500 struct _ETHREAD *FocusThread;
501
502 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans = NULL;
503 UINT ModifierState = 0;
504 USHORT LastMakeCode = 0;
505 USHORT LastFlags = 0;
506 UINT RepeatCount = 0;
507
508 InitializeObjectAttributes(&KeyboardObjectAttributes,
509 &KeyboardDeviceName,
510 0,
511 NULL,
512 NULL);
513 do
514 {
515 LARGE_INTEGER DueTime;
516 KEVENT Event;
517 DueTime.QuadPart = (LONGLONG)(-10000000);
518 KeInitializeEvent(&Event, NotificationEvent, FALSE);
519 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime);
520 Status = NtOpenFile(&KeyboardDeviceHandle,
521 FILE_ALL_ACCESS,
522 &KeyboardObjectAttributes,
523 &Iosb,
524 0,
525 FILE_SYNCHRONOUS_IO_ALERT);
526 } while (!NT_SUCCESS(Status));
527
528 /* Not sure if converting this thread to a win32 thread is such
529 a great idea. Since we're posting keyboard messages to the focus
530 window message queue, we'll be (indirectly) doing sendmessage
531 stuff from this thread (for WH_KEYBOARD_LL processing), which
532 means we need our own message queue. If keyboard messages were
533 instead queued to the system message queue, the thread removing
534 the message from the system message queue would be responsible
535 for WH_KEYBOARD_LL processing and we wouldn't need this thread
536 to be a win32 thread. */
537 Status = Win32kInitWin32Thread(PsGetCurrentThread());
538 if (!NT_SUCCESS(Status))
539 {
540 ERR("Win32K: Failed making keyboard thread a win32 thread.\n");
541 return; //(Status);
542 }
543
544 ptiKeyboard = PsGetCurrentThreadWin32Thread();
545 ptiKeyboard->TIF_flags |= TIF_SYSTEMTHREAD;
546 TRACE("Keyboard Thread 0x%x \n", ptiKeyboard);
547
548 KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
549 LOW_REALTIME_PRIORITY + 3);
550
551 IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle,
552 &IndicatorTrans);
553
554 for (;;)
555 {
556 /*
557 * Wait to start input.
558 */
559 TRACE( "Keyboard Input Thread Waiting for start event\n" );
560 Status = KeWaitForSingleObject(&InputThreadsStart,
561 0,
562 KernelMode,
563 TRUE,
564 NULL);
565
566 TRACE( "Keyboard Input Thread Starting...\n" );
567 /*
568 * Receive and process keyboard input.
569 */
570 while (InputThreadsRunning)
571 {
572 BOOLEAN NumKeys = 1;
573 BOOLEAN bLeftAlt;
574 KEYBOARD_INPUT_DATA KeyInput;
575 KEYBOARD_INPUT_DATA NextKeyInput;
576 LPARAM lParam = 0;
577 UINT fsModifiers, fsNextModifiers;
578 struct _ETHREAD *Thread;
579 HWND hWnd;
580 int id;
581
582 TRACE("KeyInput @ %08x\n", &KeyInput);
583
584 Status = NtReadFile (KeyboardDeviceHandle,
585 NULL,
586 NULL,
587 NULL,
588 &Iosb,
589 &KeyInput,
590 sizeof(KEYBOARD_INPUT_DATA),
591 NULL,
592 NULL);
593
594 if(Status == STATUS_ALERTED && !InputThreadsRunning)
595 {
596 break;
597 }
598 if(Status == STATUS_PENDING)
599 {
600 NtWaitForSingleObject(KeyboardDeviceHandle, FALSE, NULL);
601 Status = Iosb.Status;
602 }
603 if(!NT_SUCCESS(Status))
604 {
605 ERR("Win32K: Failed to read from keyboard.\n");
606 return; //(Status);
607 }
608
609 TRACE("KeyRaw: %s %04x\n",
610 (KeyInput.Flags & KEY_BREAK) ? "up" : "down",
611 KeyInput.MakeCode );
612
613 if (Status == STATUS_ALERTED && !InputThreadsRunning)
614 break;
615
616 if (!NT_SUCCESS(Status))
617 {
618 ERR("Win32K: Failed to read from keyboard.\n");
619 return; //(Status);
620 }
621
622 /* Set LastInputTick */
623 IntLastInputTick(TRUE);
624
625 /* Update modifier state */
626 fsModifiers = IntKeyboardGetModifiers(&KeyInput);
627
628 if (fsModifiers)
629 {
630 if (KeyInput.Flags & KEY_BREAK)
631 {
632 ModifierState &= ~fsModifiers;
633 if(fsModifiers == MOD_ALT)
634 {
635 if(KeyInput.Flags & KEY_E0)
636 {
637 gKeyStateTable[VK_RMENU] = 0;
638 }
639 else
640 {
641 gKeyStateTable[VK_LMENU] = 0;
642 }
643 if (gKeyStateTable[VK_RMENU] == 0 &&
644 gKeyStateTable[VK_LMENU] == 0)
645 {
646 gKeyStateTable[VK_MENU] = 0;
647 }
648 }
649 }
650 else
651 {
652 ModifierState |= fsModifiers;
653
654 if (ModifierState == fsModifiers &&
655 (fsModifiers == MOD_ALT || fsModifiers == MOD_WIN))
656 {
657 /* First send out special notifications
658 * (For alt, the message that turns on accelerator
659 * display, not sure what for win. Both TODO though.)
660 */
661 bLeftAlt = FALSE;
662 if(fsModifiers == MOD_ALT)
663 {
664 if(KeyInput.Flags & KEY_E0)
665 {
666 gKeyStateTable[VK_RMENU] = KS_DOWN_BIT;
667 }
668 else
669 {
670 gKeyStateTable[VK_LMENU] = KS_DOWN_BIT;
671 bLeftAlt = TRUE;
672 }
673
674 gKeyStateTable[VK_MENU] = KS_DOWN_BIT;
675 }
676
677 /* Read the next key before sending this one */
678 do
679 {
680 Status = NtReadFile (KeyboardDeviceHandle,
681 NULL,
682 NULL,
683 NULL,
684 &Iosb,
685 &NextKeyInput,
686 sizeof(KEYBOARD_INPUT_DATA),
687 NULL,
688 NULL);
689 TRACE("KeyRaw: %s %04x\n",
690 (NextKeyInput.Flags & KEY_BREAK) ? "up" : "down",
691 NextKeyInput.MakeCode );
692
693 if (Status == STATUS_ALERTED && !InputThreadsRunning)
694 goto KeyboardEscape;
695
696 }
697 while ((!(NextKeyInput.Flags & KEY_BREAK)) &&
698 NextKeyInput.MakeCode == KeyInput.MakeCode);
699 /* ^ Ignore repeats, they'll be KEY_MAKE and the same
700 * code. I'm not caring about the counting, not sure
701 * if that matters. I think not.
702 */
703
704 /* If the ModifierState is now empty again, send a
705 * special notification and eat both keypresses
706 */
707
708 fsNextModifiers = IntKeyboardGetModifiers(&NextKeyInput);
709
710 if (fsNextModifiers)
711 ModifierState ^= fsNextModifiers;
712
713 if (ModifierState == 0)
714 {
715 UserEnterExclusive();
716 if (fsModifiers == MOD_WIN)
717 IntKeyboardSendWinKeyMsg();
718 else if (fsModifiers == MOD_ALT)
719 {
720 gKeyStateTable[VK_MENU] = 0;
721 if(bLeftAlt)
722 {
723 gKeyStateTable[VK_LMENU] = 0;
724 }
725 else
726 {
727 gKeyStateTable[VK_RMENU] = 0;
728 }
729 co_IntKeyboardSendAltKeyMsg();
730 }
731 UserLeave();
732 continue;
733 }
734
735 NumKeys = 2;
736 }
737 }
738 }
739
740 UserEnterExclusive();
741
742 for (; NumKeys; memcpy(&KeyInput, &NextKeyInput, sizeof(KeyInput)),
743 NumKeys--)
744 {
745 PKBL keyboardLayout = NULL;
746 lParam = 0;
747
748 IntKeyboardUpdateLeds(KeyboardDeviceHandle,
749 &KeyInput,
750 IndicatorTrans);
751
752 /* While we are working, we set up lParam. The format is:
753 * 0-15: The number of times this key has autorepeated
754 * 16-23: The keyboard scancode
755 * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
756 * Note that E1 is only used for PAUSE (E1-1D-45) and
757 * E0-45 happens not to be anything.
758 * 29: Alt is pressed ('Context code')
759 * 30: Previous state, if the key was down before this message
760 * This is a cheap way to ignore autorepeat keys
761 * 31: 1 if the key is being pressed
762 */
763
764 /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
765 * and it's the same key as the last one, increase the repeat
766 * count.
767 */
768
769 if (!(KeyInput.Flags & KEY_BREAK))
770 {
771 if (((KeyInput.Flags & (KEY_E0 | KEY_E1)) == LastFlags) &&
772 (KeyInput.MakeCode == LastMakeCode))
773 {
774 RepeatCount++;
775 lParam |= (KF_REPEAT << 16);
776 }
777 else
778 {
779 RepeatCount = 1;
780 LastFlags = KeyInput.Flags & (KEY_E0 | KEY_E1);
781 LastMakeCode = KeyInput.MakeCode;
782 }
783 }
784 else
785 {
786 LastFlags = 0;
787 LastMakeCode = 0; /* Should never match */
788 lParam |= (KF_UP << 16) | (KF_REPEAT << 16);
789 }
790
791 lParam |= RepeatCount;
792
793 lParam |= (KeyInput.MakeCode & 0xff) << 16;
794
795 if (KeyInput.Flags & KEY_E0)
796 lParam |= (KF_EXTENDED << 16);
797
798 if (ModifierState & MOD_ALT)
799 {
800 lParam |= (KF_ALTDOWN << 16);
801
802 if (!(KeyInput.Flags & KEY_BREAK))
803 msg.message = WM_SYSKEYDOWN;
804 else
805 msg.message = WM_SYSKEYUP;
806 }
807 else
808 {
809 if (!(KeyInput.Flags & KEY_BREAK))
810 msg.message = WM_KEYDOWN;
811 else
812 msg.message = WM_KEYUP;
813 }
814
815 /* Find the target thread whose locale is in effect */
816 FocusQueue = IntGetFocusMessageQueue();
817
818 if (FocusQueue)
819 {
820 msg.hwnd = FocusQueue->FocusWindow;
821
822 FocusThread = FocusQueue->Thread;
823 if (FocusThread && FocusThread->Tcb.Win32Thread)
824 {
825 keyboardLayout = ((PTHREADINFO)FocusThread->Tcb.Win32Thread)->KeyboardLayout;
826 }
827 if ( FocusQueue->QF_flags & QF_DIALOGACTIVE )
828 lParam |= (KF_DLGMODE << 16);
829 if ( FocusQueue->MenuOwner )//FocusQueue->MenuState ) // MenuState needs a start flag...
830 lParam |= (KF_MENUMODE << 16);
831 }
832 if (!keyboardLayout)
833 {
834 keyboardLayout = W32kGetDefaultKeyLayout();
835 }
836
837 msg.lParam = lParam;
838
839 /* This function uses lParam to fill wParam according to the
840 * keyboard layout in use.
841 */
842 W32kKeyProcessMessage(&msg,
843 keyboardLayout->KBTables,
844 KeyInput.Flags & KEY_E0 ? 0xE0 :
845 (KeyInput.Flags & KEY_E1 ? 0xE1 : 0));
846
847 if (GetHotKey(ModifierState,
848 msg.wParam,
849 &Thread,
850 &hWnd,
851 &id))
852 {
853 if (!(KeyInput.Flags & KEY_BREAK))
854 {
855 TRACE("Hot key pressed (hWnd %lx, id %d)\n", hWnd, id);
856 MsqPostHotKeyMessage (Thread,
857 hWnd,
858 (WPARAM)id,
859 MAKELPARAM((WORD)ModifierState,
860 (WORD)msg.wParam));
861 }
862 continue; /* Eat key up motion too */
863 }
864
865 if (!FocusQueue)
866 {
867 /* There is no focused window to receive a keyboard message */
868 continue;
869 }
870 if ( msg.wParam == VK_F10 ) // Bypass this key before it is in the queue.
871 {
872 if (msg.message == WM_KEYUP) msg.message = WM_SYSKEYUP;
873 if (msg.message == WM_KEYDOWN) msg.message = WM_SYSKEYDOWN;
874 }
875 /*
876 * Post a keyboard message.
877 */
878 co_MsqPostKeyboardMessage(msg.message, msg.wParam, msg.lParam);
879 }
880
881 UserLeave();
882 }
883
884 KeyboardEscape:
885 TRACE( "KeyboardInput Thread Stopped...\n" );
886 }
887 }
888
889
890 static PVOID Objects[2];
891 /*
892 Raw Input Thread.
893 Since this relies on InputThreadsStart, just fake it.
894 */
895 static VOID APIENTRY
896 RawInputThreadMain(PVOID StartContext)
897 {
898 NTSTATUS Status;
899 LARGE_INTEGER DueTime;
900
901 DueTime.QuadPart = (LONGLONG)(-10000000);
902
903 do
904 {
905 KEVENT Event;
906 KeInitializeEvent(&Event, NotificationEvent, FALSE);
907 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime);
908 } while (!NT_SUCCESS(Status));
909
910
911 Objects[0] = &InputThreadsStart;
912 Objects[1] = MasterTimer;
913
914 // This thread requires win32k!
915 Status = Win32kInitWin32Thread(PsGetCurrentThread());
916 if (!NT_SUCCESS(Status))
917 {
918 ERR("Win32K: Failed making Raw Input thread a win32 thread.\n");
919 return; //(Status);
920 }
921
922 ptiRawInput = PsGetCurrentThreadWin32Thread();
923 ptiRawInput->TIF_flags |= TIF_SYSTEMTHREAD;
924 TRACE("Raw Input Thread 0x%x \n", ptiRawInput);
925
926 KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
927 LOW_REALTIME_PRIORITY + 3);
928
929 UserEnterExclusive();
930 StartTheTimers();
931 UserLeave();
932
933 //
934 // ATM, we just have one job to handle, merge the other two later.
935 //
936 for(;;)
937 {
938 TRACE( "Raw Input Thread Waiting for start event\n" );
939
940 Status = KeWaitForMultipleObjects( 2,
941 Objects,
942 WaitAll, //WaitAny,
943 WrUserRequest,
944 KernelMode,
945 TRUE,
946 NULL,
947 NULL);
948 TRACE( "Raw Input Thread Starting...\n" );
949
950 ProcessTimers();
951 }
952 ERR("Raw Input Thread Exit!\n");
953 }
954
955 INIT_FUNCTION
956 NTSTATUS
957 NTAPI
958 InitInputImpl(VOID)
959 {
960 NTSTATUS Status;
961
962 KeInitializeEvent(&InputThreadsStart, NotificationEvent, FALSE);
963
964 MasterTimer = ExAllocatePoolWithTag(NonPagedPool, sizeof(KTIMER), USERTAG_SYSTEM);
965 if (!MasterTimer)
966 {
967 ERR("Win32K: Failed making Raw Input thread a win32 thread.\n");
968 ASSERT(FALSE);
969 return STATUS_UNSUCCESSFUL;
970 }
971 KeInitializeTimer(MasterTimer);
972
973 /* Initialize the default keyboard layout */
974 if(!UserInitDefaultKeyboardLayout())
975 {
976 ERR("Failed to initialize default keyboard layout!\n");
977 }
978
979 Status = PsCreateSystemThread(&RawInputThreadHandle,
980 THREAD_ALL_ACCESS,
981 NULL,
982 NULL,
983 &RawInputThreadId,
984 RawInputThreadMain,
985 NULL);
986 if (!NT_SUCCESS(Status))
987 {
988 ERR("Win32K: Failed to create raw thread.\n");
989 }
990
991 Status = PsCreateSystemThread(&KeyboardThreadHandle,
992 THREAD_ALL_ACCESS,
993 NULL,
994 NULL,
995 &KeyboardThreadId,
996 KeyboardThreadMain,
997 NULL);
998 if (!NT_SUCCESS(Status))
999 {
1000 ERR("Win32K: Failed to create keyboard thread.\n");
1001 }
1002
1003 Status = PsCreateSystemThread(&MouseThreadHandle,
1004 THREAD_ALL_ACCESS,
1005 NULL,
1006 NULL,
1007 &MouseThreadId,
1008 MouseThreadMain,
1009 NULL);
1010 if (!NT_SUCCESS(Status))
1011 {
1012 ERR("Win32K: Failed to create mouse thread.\n");
1013 }
1014
1015 InputThreadsRunning = TRUE;
1016 KeSetEvent(&InputThreadsStart, IO_NO_INCREMENT, FALSE);
1017
1018 return STATUS_SUCCESS;
1019 }
1020
1021 NTSTATUS FASTCALL
1022 CleanupInputImp(VOID)
1023 {
1024 return(STATUS_SUCCESS);
1025 }
1026
1027 BOOL FASTCALL
1028 IntBlockInput(PTHREADINFO W32Thread, BOOL BlockIt)
1029 {
1030 PTHREADINFO OldBlock;
1031 ASSERT(W32Thread);
1032
1033 if(!W32Thread->rpdesk || ((W32Thread->TIF_flags & TIF_INCLEANUP) && BlockIt))
1034 {
1035 /*
1036 * fail blocking if exiting the thread
1037 */
1038
1039 return FALSE;
1040 }
1041
1042 /*
1043 * FIXME - check access rights of the window station
1044 * e.g. services running in the service window station cannot block input
1045 */
1046 if(!ThreadHasInputAccess(W32Thread) ||
1047 !IntIsActiveDesktop(W32Thread->rpdesk))
1048 {
1049 EngSetLastError(ERROR_ACCESS_DENIED);
1050 return FALSE;
1051 }
1052
1053 ASSERT(W32Thread->rpdesk);
1054 OldBlock = W32Thread->rpdesk->BlockInputThread;
1055 if(OldBlock)
1056 {
1057 if(OldBlock != W32Thread)
1058 {
1059 EngSetLastError(ERROR_ACCESS_DENIED);
1060 return FALSE;
1061 }
1062 W32Thread->rpdesk->BlockInputThread = (BlockIt ? W32Thread : NULL);
1063 return OldBlock == NULL;
1064 }
1065
1066 W32Thread->rpdesk->BlockInputThread = (BlockIt ? W32Thread : NULL);
1067 return OldBlock == NULL;
1068 }
1069
1070 BOOL
1071 APIENTRY
1072 NtUserBlockInput(
1073 BOOL BlockIt)
1074 {
1075 DECLARE_RETURN(BOOLEAN);
1076
1077 TRACE("Enter NtUserBlockInput\n");
1078 UserEnterExclusive();
1079
1080 RETURN( IntBlockInput(PsGetCurrentThreadWin32Thread(), BlockIt));
1081
1082 CLEANUP:
1083 TRACE("Leave NtUserBlockInput, ret=%i\n", _ret_);
1084 UserLeave();
1085 END_CLEANUP;
1086 }
1087
1088 BOOL FASTCALL
1089 IntMouseInput(MOUSEINPUT *mi, BOOL Injected)
1090 {
1091 const UINT SwapBtnMsg[2][2] =
1092 {
1093 {WM_LBUTTONDOWN, WM_RBUTTONDOWN},
1094 {WM_LBUTTONUP, WM_RBUTTONUP}
1095 };
1096 const WPARAM SwapBtn[2] =
1097 {
1098 MK_LBUTTON, MK_RBUTTON
1099 };
1100 POINT MousePos;
1101 PSYSTEM_CURSORINFO CurInfo;
1102 BOOL SwapButtons;
1103 MSG Msg;
1104
1105 ASSERT(mi);
1106
1107 CurInfo = IntGetSysCursorInfo();
1108
1109 if(!mi->time)
1110 {
1111 LARGE_INTEGER LargeTickCount;
1112 KeQueryTickCount(&LargeTickCount);
1113 mi->time = MsqCalculateMessageTime(&LargeTickCount);
1114 }
1115
1116 SwapButtons = gspv.bMouseBtnSwap;
1117
1118 MousePos = gpsi->ptCursor;
1119
1120 if(mi->dwFlags & MOUSEEVENTF_MOVE)
1121 {
1122 if(mi->dwFlags & MOUSEEVENTF_ABSOLUTE)
1123 {
1124 MousePos.x = mi->dx * UserGetSystemMetrics(SM_CXVIRTUALSCREEN) >> 16;
1125 MousePos.y = mi->dy * UserGetSystemMetrics(SM_CYVIRTUALSCREEN) >> 16;
1126 }
1127 else
1128 {
1129 MousePos.x += mi->dx;
1130 MousePos.y += mi->dy;
1131 }
1132 }
1133
1134 /*
1135 * Insert the messages into the system queue
1136 */
1137 Msg.wParam = 0;
1138 Msg.lParam = MAKELPARAM(MousePos.x, MousePos.y);
1139 Msg.pt = MousePos;
1140
1141 if (gKeyStateTable[VK_SHIFT] & KS_DOWN_BIT)
1142 {
1143 Msg.wParam |= MK_SHIFT;
1144 }
1145
1146 if (gKeyStateTable[VK_CONTROL] & KS_DOWN_BIT)
1147 {
1148 Msg.wParam |= MK_CONTROL;
1149 }
1150
1151 if(mi->dwFlags & MOUSEEVENTF_MOVE)
1152 {
1153 UserSetCursorPos(MousePos.x, MousePos.y, Injected, mi->dwExtraInfo, TRUE);
1154 }
1155 if(mi->dwFlags & MOUSEEVENTF_LEFTDOWN)
1156 {
1157 gKeyStateTable[VK_LBUTTON] |= KS_DOWN_BIT;
1158 Msg.message = SwapBtnMsg[0][SwapButtons];
1159 CurInfo->ButtonsDown |= SwapBtn[SwapButtons];
1160 Msg.wParam |= CurInfo->ButtonsDown;
1161 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1162 }
1163 else if(mi->dwFlags & MOUSEEVENTF_LEFTUP)
1164 {
1165 gKeyStateTable[VK_LBUTTON] &= ~KS_DOWN_BIT;
1166 Msg.message = SwapBtnMsg[1][SwapButtons];
1167 CurInfo->ButtonsDown &= ~SwapBtn[SwapButtons];
1168 Msg.wParam |= CurInfo->ButtonsDown;
1169 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1170 }
1171 if(mi->dwFlags & MOUSEEVENTF_MIDDLEDOWN)
1172 {
1173 gKeyStateTable[VK_MBUTTON] |= KS_DOWN_BIT;
1174 Msg.message = WM_MBUTTONDOWN;
1175 CurInfo->ButtonsDown |= MK_MBUTTON;
1176 Msg.wParam |= CurInfo->ButtonsDown;
1177 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1178 }
1179 else if(mi->dwFlags & MOUSEEVENTF_MIDDLEUP)
1180 {
1181 gKeyStateTable[VK_MBUTTON] &= ~KS_DOWN_BIT;
1182 Msg.message = WM_MBUTTONUP;
1183 CurInfo->ButtonsDown &= ~MK_MBUTTON;
1184 Msg.wParam |= CurInfo->ButtonsDown;
1185 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1186 }
1187 if(mi->dwFlags & MOUSEEVENTF_RIGHTDOWN)
1188 {
1189 gKeyStateTable[VK_RBUTTON] |= KS_DOWN_BIT;
1190 Msg.message = SwapBtnMsg[0][!SwapButtons];
1191 CurInfo->ButtonsDown |= SwapBtn[!SwapButtons];
1192 Msg.wParam |= CurInfo->ButtonsDown;
1193 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1194 }
1195 else if(mi->dwFlags & MOUSEEVENTF_RIGHTUP)
1196 {
1197 gKeyStateTable[VK_RBUTTON] &= ~KS_DOWN_BIT;
1198 Msg.message = SwapBtnMsg[1][!SwapButtons];
1199 CurInfo->ButtonsDown &= ~SwapBtn[!SwapButtons];
1200 Msg.wParam |= CurInfo->ButtonsDown;
1201 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1202 }
1203
1204 if((mi->dwFlags & (MOUSEEVENTF_XDOWN | MOUSEEVENTF_XUP)) &&
1205 (mi->dwFlags & MOUSEEVENTF_WHEEL))
1206 {
1207 /* fail because both types of events use the mouseData field */
1208 return FALSE;
1209 }
1210
1211 if(mi->dwFlags & MOUSEEVENTF_XDOWN)
1212 {
1213 Msg.message = WM_XBUTTONDOWN;
1214 if(mi->mouseData & XBUTTON1)
1215 {
1216 gKeyStateTable[VK_XBUTTON1] |= KS_DOWN_BIT;
1217 CurInfo->ButtonsDown |= MK_XBUTTON1;
1218 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
1219 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1220 }
1221 if(mi->mouseData & XBUTTON2)
1222 {
1223 gKeyStateTable[VK_XBUTTON2] |= KS_DOWN_BIT;
1224 CurInfo->ButtonsDown |= MK_XBUTTON2;
1225 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
1226 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1227 }
1228 }
1229 else if(mi->dwFlags & MOUSEEVENTF_XUP)
1230 {
1231 Msg.message = WM_XBUTTONUP;
1232 if(mi->mouseData & XBUTTON1)
1233 {
1234 gKeyStateTable[VK_XBUTTON1] &= ~KS_DOWN_BIT;
1235 CurInfo->ButtonsDown &= ~MK_XBUTTON1;
1236 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
1237 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1238 }
1239 if(mi->mouseData & XBUTTON2)
1240 {
1241 gKeyStateTable[VK_XBUTTON2] &= ~KS_DOWN_BIT;
1242 CurInfo->ButtonsDown &= ~MK_XBUTTON2;
1243 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
1244 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1245 }
1246 }
1247 if(mi->dwFlags & MOUSEEVENTF_WHEEL)
1248 {
1249 Msg.message = WM_MOUSEWHEEL;
1250 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, mi->mouseData);
1251 co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
1252 }
1253
1254 return TRUE;
1255 }
1256
1257 BOOL FASTCALL
1258 IntKeyboardInput(KEYBDINPUT *ki, BOOL Injected)
1259 {
1260 PUSER_MESSAGE_QUEUE FocusMessageQueue;
1261 MSG Msg;
1262 LARGE_INTEGER LargeTickCount;
1263 KBDLLHOOKSTRUCT KbdHookData;
1264 WORD flags, wVkStripped, wVkL, wVkR, wVk = ki->wVk, vk_hook = ki->wVk;
1265
1266 Msg.lParam = 0;
1267
1268 // Condition may arise when calling MsqPostMessage and waiting for an event.
1269 ASSERT (UserIsEntered());
1270
1271 wVk = LOBYTE(wVk);
1272 Msg.wParam = wVk;
1273 flags = LOBYTE(ki->wScan);
1274
1275 FocusMessageQueue = IntGetFocusMessageQueue();
1276
1277 if (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) flags |= KF_EXTENDED;
1278 /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
1279 if ( FocusMessageQueue && FocusMessageQueue->QF_flags & QF_DIALOGACTIVE )
1280 flags |= KF_DLGMODE;
1281 if ( FocusMessageQueue && FocusMessageQueue->MenuOwner )//FocusMessageQueue->MenuState ) // MenuState needs a start flag...
1282 flags |= KF_MENUMODE;
1283
1284 /* strip left/right for menu, control, shift */
1285 switch (wVk)
1286 {
1287 case VK_MENU:
1288 case VK_LMENU:
1289 case VK_RMENU:
1290 wVk = (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) ? VK_RMENU : VK_LMENU;
1291 wVkStripped = VK_MENU;
1292 wVkL = VK_LMENU;
1293 wVkR = VK_RMENU;
1294 break;
1295 case VK_CONTROL:
1296 case VK_LCONTROL:
1297 case VK_RCONTROL:
1298 wVk = (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) ? VK_RCONTROL : VK_LCONTROL;
1299 wVkStripped = VK_CONTROL;
1300 wVkL = VK_LCONTROL;
1301 wVkR = VK_RCONTROL;
1302 break;
1303 case VK_SHIFT:
1304 case VK_LSHIFT:
1305 case VK_RSHIFT:
1306 wVk = (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) ? VK_RSHIFT : VK_LSHIFT;
1307 wVkStripped = VK_SHIFT;
1308 wVkL = VK_LSHIFT;
1309 wVkR = VK_RSHIFT;
1310 break;
1311 default:
1312 wVkStripped = wVkL = wVkR = wVk;
1313 }
1314
1315 if (ki->dwFlags & KEYEVENTF_KEYUP)
1316 {
1317 Msg.message = WM_KEYUP;
1318 if (((gKeyStateTable[VK_MENU] & KS_DOWN_BIT) &&
1319 ((wVkStripped == VK_MENU) || (wVkStripped == VK_CONTROL)
1320 || !(gKeyStateTable[VK_CONTROL] & KS_DOWN_BIT)))
1321 || (wVkStripped == VK_F10))
1322 {
1323 if( TrackSysKey == VK_MENU || /* <ALT>-down/<ALT>-up sequence */
1324 (wVkStripped != VK_MENU)) /* <ALT>-down...<something else>-up */
1325 Msg.message = WM_SYSKEYUP;
1326 TrackSysKey = 0;
1327 }
1328 flags |= KF_REPEAT | KF_UP;
1329 }
1330 else
1331 {
1332 Msg.message = WM_KEYDOWN;
1333 if (((gKeyStateTable[VK_MENU] & KS_DOWN_BIT || wVkStripped == VK_MENU) &&
1334 !(gKeyStateTable[VK_CONTROL] & KS_DOWN_BIT || wVkStripped == VK_CONTROL))
1335 || (wVkStripped == VK_F10))
1336 {
1337 Msg.message = WM_SYSKEYDOWN;
1338 TrackSysKey = wVkStripped;
1339 }
1340 if (!(ki->dwFlags & KEYEVENTF_UNICODE) && gKeyStateTable[wVk] & KS_DOWN_BIT) flags |= KF_REPEAT;
1341 }
1342
1343 if (ki->dwFlags & KEYEVENTF_UNICODE)
1344 {
1345 vk_hook = Msg.wParam = wVk = VK_PACKET;
1346 Msg.lParam = MAKELPARAM(1 /* repeat count */, ki->wScan);
1347 }
1348
1349 if (!(ki->dwFlags & KEYEVENTF_UNICODE))
1350 {
1351 if (ki->dwFlags & KEYEVENTF_KEYUP)
1352 {
1353 gKeyStateTable[wVk] &= ~KS_DOWN_BIT;
1354 gKeyStateTable[wVkStripped] = gKeyStateTable[wVkL] | gKeyStateTable[wVkR];
1355 }
1356 else
1357 {
1358 if (!(gKeyStateTable[wVk] & KS_DOWN_BIT)) gKeyStateTable[wVk] ^= KS_LOCK_BIT;
1359 gKeyStateTable[wVk] |= KS_DOWN_BIT;
1360 gKeyStateTable[wVkStripped] = gKeyStateTable[wVkL] | gKeyStateTable[wVkR];
1361 }
1362
1363 if (gKeyStateTable[VK_MENU] & KS_DOWN_BIT) flags |= KF_ALTDOWN;
1364
1365 if (wVkStripped == VK_SHIFT) flags &= ~KF_EXTENDED;
1366
1367 Msg.lParam = MAKELPARAM(1 /* repeat count */, flags);
1368 }
1369
1370 Msg.hwnd = 0;
1371
1372 if (FocusMessageQueue && (FocusMessageQueue->FocusWindow != (HWND)0))
1373 Msg.hwnd = FocusMessageQueue->FocusWindow;
1374
1375 if (!ki->time)
1376 {
1377 KeQueryTickCount(&LargeTickCount);
1378 Msg.time = MsqCalculateMessageTime(&LargeTickCount);
1379 }
1380 else
1381 Msg.time = ki->time;
1382
1383 /* All messages have to contain the cursor point. */
1384 Msg.pt = gpsi->ptCursor;
1385
1386 KbdHookData.vkCode = vk_hook;
1387 KbdHookData.scanCode = ki->wScan;
1388 KbdHookData.flags = (flags & (KF_EXTENDED | KF_ALTDOWN | KF_UP)) >> 8;
1389 if (Injected) KbdHookData.flags |= LLKHF_INJECTED;
1390 KbdHookData.time = Msg.time;
1391 KbdHookData.dwExtraInfo = ki->dwExtraInfo;
1392 if (co_HOOK_CallHooks(WH_KEYBOARD_LL, HC_ACTION, Msg.message, (LPARAM) &KbdHookData))
1393 {
1394 ERR("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1395 Msg.message, vk_hook, Msg.lParam);
1396
1397 return FALSE;
1398 }
1399
1400 if (FocusMessageQueue == NULL)
1401 {
1402 TRACE("No focus message queue\n");
1403
1404 return FALSE;
1405 }
1406
1407 if (FocusMessageQueue->FocusWindow != (HWND)0)
1408 {
1409 Msg.hwnd = FocusMessageQueue->FocusWindow;
1410 TRACE("Msg.hwnd = %x\n", Msg.hwnd);
1411
1412 FocusMessageQueue->Desktop->pDeskInfo->LastInputWasKbd = TRUE;
1413
1414 // Post to hardware queue, based on the first part of wine "some GetMessage tests"
1415 // in test_PeekMessage()
1416 MsqPostMessage(FocusMessageQueue, &Msg, TRUE, QS_KEY);
1417 }
1418 else
1419 {
1420 TRACE("Invalid focus window handle\n");
1421 }
1422
1423 return TRUE;
1424 }
1425
1426 BOOL FASTCALL
1427 UserAttachThreadInput( PTHREADINFO pti, PTHREADINFO ptiTo, BOOL fAttach)
1428 {
1429 PATTACHINFO pai;
1430
1431 /* Can not be the same thread.*/
1432 if (pti == ptiTo) return FALSE;
1433
1434 /* Do not attach to system threads or between different desktops. */
1435 if ( pti->TIF_flags & TIF_DONTATTACHQUEUE ||
1436 ptiTo->TIF_flags & TIF_DONTATTACHQUEUE ||
1437 pti->rpdesk != ptiTo->rpdesk )
1438 return FALSE;
1439
1440 /* If Attach set, allocate and link. */
1441 if ( fAttach )
1442 {
1443 pai = ExAllocatePoolWithTag(PagedPool, sizeof(ATTACHINFO), USERTAG_ATTACHINFO);
1444 if ( !pai ) return FALSE;
1445
1446 pai->paiNext = gpai;
1447 pai->pti1 = pti;
1448 pai->pti2 = ptiTo;
1449 gpai = pai;
1450 }
1451 else /* If clear, unlink and free it. */
1452 {
1453 PATTACHINFO paiprev = NULL;
1454
1455 if ( !gpai ) return FALSE;
1456
1457 pai = gpai;
1458
1459 /* Search list and free if found or return false. */
1460 do
1461 {
1462 if ( pai->pti2 == ptiTo && pai->pti1 == pti ) break;
1463 paiprev = pai;
1464 pai = pai->paiNext;
1465 } while (pai);
1466
1467 if ( !pai ) return FALSE;
1468
1469 if (paiprev) paiprev->paiNext = pai->paiNext;
1470
1471 ExFreePoolWithTag(pai, USERTAG_ATTACHINFO);
1472 }
1473
1474 return TRUE;
1475 }
1476
1477 UINT
1478 APIENTRY
1479 NtUserSendInput(
1480 UINT nInputs,
1481 LPINPUT pInput,
1482 INT cbSize)
1483 {
1484 PTHREADINFO W32Thread;
1485 UINT cnt;
1486 DECLARE_RETURN(UINT);
1487
1488 TRACE("Enter NtUserSendInput\n");
1489 UserEnterExclusive();
1490
1491 W32Thread = PsGetCurrentThreadWin32Thread();
1492 ASSERT(W32Thread);
1493
1494 if(!W32Thread->rpdesk)
1495 {
1496 RETURN( 0);
1497 }
1498
1499 if(!nInputs || !pInput || (cbSize != sizeof(INPUT)))
1500 {
1501 EngSetLastError(ERROR_INVALID_PARAMETER);
1502 RETURN( 0);
1503 }
1504
1505 /*
1506 * FIXME - check access rights of the window station
1507 * e.g. services running in the service window station cannot block input
1508 */
1509 if(!ThreadHasInputAccess(W32Thread) ||
1510 !IntIsActiveDesktop(W32Thread->rpdesk))
1511 {
1512 EngSetLastError(ERROR_ACCESS_DENIED);
1513 RETURN( 0);
1514 }
1515
1516 cnt = 0;
1517 while(nInputs--)
1518 {
1519 INPUT SafeInput;
1520 NTSTATUS Status;
1521
1522 Status = MmCopyFromCaller(&SafeInput, pInput++, sizeof(INPUT));
1523 if(!NT_SUCCESS(Status))
1524 {
1525 SetLastNtError(Status);
1526 RETURN( cnt);
1527 }
1528
1529 switch(SafeInput.type)
1530 {
1531 case INPUT_MOUSE:
1532 if(IntMouseInput(&SafeInput.mi, TRUE))
1533 {
1534 cnt++;
1535 }
1536 break;
1537 case INPUT_KEYBOARD:
1538 if(IntKeyboardInput(&SafeInput.ki, TRUE))
1539 {
1540 cnt++;
1541 }
1542 break;
1543 case INPUT_HARDWARE:
1544 break;
1545 #ifndef NDEBUG
1546
1547 default:
1548 ERR("SendInput(): Invalid input type: 0x%x\n", SafeInput.type);
1549 break;
1550 #endif
1551
1552 }
1553 }
1554
1555 RETURN( cnt);
1556
1557 CLEANUP:
1558 TRACE("Leave NtUserSendInput, ret=%i\n", _ret_);
1559 UserLeave();
1560 END_CLEANUP;
1561 }
1562
1563 BOOL
1564 FASTCALL
1565 IntQueryTrackMouseEvent(
1566 LPTRACKMOUSEEVENT lpEventTrack)
1567 {
1568 PDESKTOP pDesk;
1569 PTHREADINFO pti;
1570
1571 pti = PsGetCurrentThreadWin32Thread();
1572 pDesk = pti->rpdesk;
1573
1574 /* Always cleared with size set and return true. */
1575 RtlZeroMemory(lpEventTrack , sizeof(TRACKMOUSEEVENT));
1576 lpEventTrack->cbSize = sizeof(TRACKMOUSEEVENT);
1577
1578 if ( pDesk->dwDTFlags & (DF_TME_LEAVE | DF_TME_HOVER) &&
1579 pDesk->spwndTrack &&
1580 pti->MessageQueue == pDesk->spwndTrack->head.pti->MessageQueue )
1581 {
1582 if ( pDesk->htEx != HTCLIENT )
1583 lpEventTrack->dwFlags |= TME_NONCLIENT;
1584
1585 if ( pDesk->dwDTFlags & DF_TME_LEAVE )
1586 lpEventTrack->dwFlags |= TME_LEAVE;
1587
1588 if ( pDesk->dwDTFlags & DF_TME_HOVER )
1589 {
1590 lpEventTrack->dwFlags |= TME_HOVER;
1591 lpEventTrack->dwHoverTime = pDesk->dwMouseHoverTime;
1592 }
1593 lpEventTrack->hwndTrack = UserHMGetHandle(pDesk->spwndTrack);
1594 }
1595 return TRUE;
1596 }
1597
1598 BOOL
1599 FASTCALL
1600 IntTrackMouseEvent(
1601 LPTRACKMOUSEEVENT lpEventTrack)
1602 {
1603 PDESKTOP pDesk;
1604 PTHREADINFO pti;
1605 PWND pWnd;
1606 POINT point;
1607
1608 pti = PsGetCurrentThreadWin32Thread();
1609 pDesk = pti->rpdesk;
1610
1611 if (!(pWnd = UserGetWindowObject(lpEventTrack->hwndTrack)))
1612 return FALSE;
1613
1614 /* Tracking spwndTrack same as pWnd */
1615 if ( lpEventTrack->dwFlags & TME_CANCEL ) // Canceled mode.
1616 {
1617 if ( lpEventTrack->dwFlags & TME_LEAVE )
1618 pDesk->dwDTFlags &= ~DF_TME_LEAVE;
1619
1620 if ( lpEventTrack->dwFlags & TME_HOVER )
1621 {
1622 if ( pDesk->dwDTFlags & DF_TME_HOVER )
1623 { // Kill hover timer.
1624 IntKillTimer(pWnd, ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE);
1625 pDesk->dwDTFlags &= ~DF_TME_HOVER;
1626 }
1627 }
1628 }
1629 else // Not Canceled.
1630 {
1631 pDesk->spwndTrack = pWnd;
1632 if ( lpEventTrack->dwFlags & TME_LEAVE )
1633 pDesk->dwDTFlags |= DF_TME_LEAVE;
1634
1635 if ( lpEventTrack->dwFlags & TME_HOVER )
1636 {
1637 pDesk->dwDTFlags |= DF_TME_HOVER;
1638
1639 if ( !lpEventTrack->dwHoverTime || lpEventTrack->dwHoverTime == HOVER_DEFAULT )
1640 pDesk->dwMouseHoverTime = gspv.iMouseHoverTime; // use the system default hover time-out.
1641 else
1642 pDesk->dwMouseHoverTime = lpEventTrack->dwHoverTime;
1643 // Start timer for the hover period.
1644 IntSetTimer( pWnd, ID_EVENT_SYSTIMER_MOUSEHOVER, pDesk->dwMouseHoverTime, SystemTimerProc, TMRF_SYSTEM);
1645 // Get windows thread message points.
1646 point = pWnd->head.pti->ptLast;
1647 // Set desktop mouse hover from the system default hover rectangle.
1648 RECTL_vSetRect(&pDesk->rcMouseHover,
1649 point.x - gspv.iMouseHoverWidth / 2,
1650 point.y - gspv.iMouseHoverHeight / 2,
1651 point.x + gspv.iMouseHoverWidth / 2,
1652 point.y + gspv.iMouseHoverHeight / 2);
1653 }
1654 }
1655 return TRUE;
1656 }
1657
1658 BOOL
1659 APIENTRY
1660 NtUserTrackMouseEvent(
1661 LPTRACKMOUSEEVENT lpEventTrack)
1662 {
1663 TRACKMOUSEEVENT saveTME;
1664 BOOL Ret = FALSE;
1665
1666 TRACE("Enter NtUserTrackMouseEvent\n");
1667 UserEnterExclusive();
1668
1669 _SEH2_TRY
1670 {
1671 ProbeForRead(lpEventTrack, sizeof(TRACKMOUSEEVENT), 1);
1672 RtlCopyMemory(&saveTME, lpEventTrack, sizeof(TRACKMOUSEEVENT));
1673 }
1674 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1675 {
1676 SetLastNtError(_SEH2_GetExceptionCode());
1677 _SEH2_YIELD(goto Exit;)
1678 }
1679 _SEH2_END;
1680
1681 if ( saveTME.cbSize != sizeof(TRACKMOUSEEVENT) )
1682 {
1683 EngSetLastError(ERROR_INVALID_PARAMETER);
1684 goto Exit;
1685 }
1686
1687 if (saveTME.dwFlags & ~(TME_CANCEL | TME_QUERY | TME_NONCLIENT | TME_LEAVE | TME_HOVER) )
1688 {
1689 EngSetLastError(ERROR_INVALID_FLAGS);
1690 goto Exit;
1691 }
1692
1693 if ( saveTME.dwFlags & TME_QUERY )
1694 {
1695 Ret = IntQueryTrackMouseEvent(&saveTME);
1696 _SEH2_TRY
1697 {
1698 ProbeForWrite(lpEventTrack, sizeof(TRACKMOUSEEVENT), 1);
1699 RtlCopyMemory(lpEventTrack, &saveTME, sizeof(TRACKMOUSEEVENT));
1700 }
1701 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1702 {
1703 SetLastNtError(_SEH2_GetExceptionCode());
1704 Ret = FALSE;
1705 }
1706 _SEH2_END;
1707 }
1708 else
1709 {
1710 Ret = IntTrackMouseEvent(&saveTME);
1711 }
1712
1713 Exit:
1714 TRACE("Leave NtUserTrackMouseEvent, ret=%i\n", Ret);
1715 UserLeave();
1716 return Ret;
1717 }
1718
1719 extern MOUSEMOVEPOINT MouseHistoryOfMoves[];
1720 extern INT gcur_count;
1721
1722 DWORD
1723 APIENTRY
1724 NtUserGetMouseMovePointsEx(
1725 UINT cbSize,
1726 LPMOUSEMOVEPOINT lpptIn,
1727 LPMOUSEMOVEPOINT lpptOut,
1728 int nBufPoints,
1729 DWORD resolution)
1730 {
1731 MOUSEMOVEPOINT Safeppt;
1732 //BOOL Hit;
1733 INT Count = -1;
1734 DECLARE_RETURN(DWORD);
1735
1736 TRACE("Enter NtUserGetMouseMovePointsEx\n");
1737 UserEnterExclusive();
1738
1739 if ((cbSize != sizeof(MOUSEMOVEPOINT)) || (nBufPoints < 0) || (nBufPoints > 64))
1740 {
1741 EngSetLastError(ERROR_INVALID_PARAMETER);
1742 RETURN( -1);
1743 }
1744
1745 if (!lpptIn || (!lpptOut && nBufPoints))
1746 {
1747 EngSetLastError(ERROR_NOACCESS);
1748 RETURN( -1);
1749 }
1750
1751 _SEH2_TRY
1752 {
1753 ProbeForRead( lpptIn, cbSize, 1);
1754 RtlCopyMemory(&Safeppt, lpptIn, cbSize);
1755 }
1756 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1757 {
1758 SetLastNtError(_SEH2_GetExceptionCode());
1759 _SEH2_YIELD(RETURN( -1))
1760 }
1761 _SEH2_END;
1762
1763 // http://msdn.microsoft.com/en-us/library/ms646259(v=vs.85).aspx
1764 // This explains the math issues in transforming points.
1765 Count = gcur_count; // FIFO is forward so retrieve backward.
1766 //Hit = FALSE;
1767 do
1768 {
1769 if (Safeppt.x == 0 && Safeppt.y == 0)
1770 break; // No test.
1771 // Finds the point, it returns the last nBufPoints prior to and including the supplied point.
1772 if (MouseHistoryOfMoves[Count].x == Safeppt.x && MouseHistoryOfMoves[Count].y == Safeppt.y)
1773 {
1774 if ( Safeppt.time ) // Now test time and it seems to be absolute.
1775 {
1776 if (Safeppt.time == MouseHistoryOfMoves[Count].time)
1777 {
1778 //Hit = TRUE;
1779 break;
1780 }
1781 else
1782 {
1783 if (--Count < 0) Count = 63;
1784 continue;
1785 }
1786 }
1787 //Hit = TRUE;
1788 break;
1789 }
1790 if (--Count < 0) Count = 63;
1791 }
1792 while ( Count != gcur_count);
1793
1794 switch(resolution)
1795 {
1796 case GMMP_USE_DISPLAY_POINTS:
1797 if (nBufPoints)
1798 {
1799 _SEH2_TRY
1800 {
1801 ProbeForWrite(lpptOut, cbSize, 1);
1802 }
1803 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1804 {
1805 SetLastNtError(_SEH2_GetExceptionCode());
1806 _SEH2_YIELD(RETURN( -1))
1807 }
1808 _SEH2_END;
1809 }
1810 Count = nBufPoints;
1811 break;
1812 case GMMP_USE_HIGH_RESOLUTION_POINTS:
1813 break;
1814 default:
1815 EngSetLastError(ERROR_POINT_NOT_FOUND);
1816 RETURN( -1);
1817 }
1818
1819 RETURN( Count);
1820
1821 CLEANUP:
1822 TRACE("Leave NtUserGetMouseMovePointsEx, ret=%i\n", _ret_);
1823 UserLeave();
1824 END_CLEANUP;
1825 }
1826
1827 /* EOF */