- fix the mouse swap button issue
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / input.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Window classes
24 * FILE: subsys/win32k/ntuser/class.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * REVISION HISTORY:
27 * 06-06-2001 CSH Created
28 */
29
30 /* INCLUDES ******************************************************************/
31
32 #include <w32k.h>
33 #include <ntddkbd.h>
34
35 #define NDEBUG
36 #include <debug.h>
37
38 extern BYTE gQueueKeyStateTable[];
39 extern NTSTATUS Win32kInitWin32Thread(PETHREAD Thread);
40
41 /* GLOBALS *******************************************************************/
42
43 PTHREADINFO ptiRawInput;
44 PKTIMER MasterTimer;
45
46 static HANDLE MouseDeviceHandle;
47 static HANDLE MouseThreadHandle;
48 static CLIENT_ID MouseThreadId;
49 static HANDLE KeyboardThreadHandle;
50 static CLIENT_ID KeyboardThreadId;
51 static HANDLE KeyboardDeviceHandle;
52 static HANDLE RawInputThreadHandle;
53 static CLIENT_ID RawInputThreadId;
54 static KEVENT InputThreadsStart;
55 static BOOLEAN InputThreadsRunning = FALSE;
56
57 /* FUNCTIONS *****************************************************************/
58 DWORD IntLastInputTick(BOOL LastInputTickSetGet);
59
60 #define ClearMouseInput(mi) \
61 mi.dx = 0; \
62 mi.dy = 0; \
63 mi.mouseData = 0; \
64 mi.dwFlags = 0;
65
66 #define SendMouseEvent(mi) \
67 if(mi.dx != 0 || mi.dy != 0) \
68 mi.dwFlags |= MOUSEEVENTF_MOVE; \
69 if(mi.dwFlags) \
70 IntMouseInput(&mi); \
71 ClearMouseInput(mi);
72
73
74 DWORD IntLastInputTick(BOOL LastInputTickSetGet)
75 {
76 static DWORD LastInputTick = 0;
77 if (LastInputTickSetGet == TRUE)
78 {
79 LARGE_INTEGER TickCount;
80 KeQueryTickCount(&TickCount);
81 LastInputTick = TickCount.u.LowPart * (KeQueryTimeIncrement() / 10000);
82 }
83 return LastInputTick;
84 }
85
86 BOOL
87 APIENTRY
88 NtUserGetLastInputInfo(PLASTINPUTINFO plii)
89 {
90 BOOL ret = TRUE;
91
92 UserEnterShared();
93
94 _SEH2_TRY
95 {
96 if (ProbeForReadUint(&plii->cbSize) != sizeof(LASTINPUTINFO))
97 {
98 SetLastWin32Error(ERROR_INVALID_PARAMETER);
99 ret = FALSE;
100 _SEH2_LEAVE;
101 }
102
103 ProbeForWrite(plii, sizeof(LASTINPUTINFO), sizeof(DWORD));
104
105 plii->dwTime = IntLastInputTick(FALSE);
106 }
107 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
108 {
109 SetLastNtError(_SEH2_GetExceptionCode());
110 ret = FALSE;
111 }
112 _SEH2_END;
113
114 UserLeave();
115
116 return ret;
117 }
118
119
120 VOID FASTCALL
121 ProcessMouseInputData(PMOUSE_INPUT_DATA Data, ULONG InputCount)
122 {
123 PMOUSE_INPUT_DATA mid;
124 MOUSEINPUT mi;
125 ULONG i;
126
127 ClearMouseInput(mi);
128 mi.time = 0;
129 mi.dwExtraInfo = 0;
130 for(i = 0; i < InputCount; i++)
131 {
132 mid = (Data + i);
133 mi.dx += mid->LastX;
134 mi.dy += mid->LastY;
135
136 /* Check if the mouse move is absolute */
137 if (mid->Flags == MOUSE_MOVE_ABSOLUTE)
138 {
139 /* Set flag and convert to screen location */
140 mi.dwFlags |= MOUSEEVENTF_ABSOLUTE;
141 mi.dx = mi.dx / (65535 / (UserGetSystemMetrics(SM_CXVIRTUALSCREEN) - 1));
142 mi.dy = mi.dy / (65535 / (UserGetSystemMetrics(SM_CYVIRTUALSCREEN) - 1));
143 }
144
145 if(mid->ButtonFlags)
146 {
147 if(mid->ButtonFlags & MOUSE_LEFT_BUTTON_DOWN)
148 {
149 mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
150 SendMouseEvent(mi);
151 }
152 if(mid->ButtonFlags & MOUSE_LEFT_BUTTON_UP)
153 {
154 mi.dwFlags |= MOUSEEVENTF_LEFTUP;
155 SendMouseEvent(mi);
156 }
157 if(mid->ButtonFlags & MOUSE_MIDDLE_BUTTON_DOWN)
158 {
159 mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
160 SendMouseEvent(mi);
161 }
162 if(mid->ButtonFlags & MOUSE_MIDDLE_BUTTON_UP)
163 {
164 mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
165 SendMouseEvent(mi);
166 }
167 if(mid->ButtonFlags & MOUSE_RIGHT_BUTTON_DOWN)
168 {
169 mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
170 SendMouseEvent(mi);
171 }
172 if(mid->ButtonFlags & MOUSE_RIGHT_BUTTON_UP)
173 {
174 mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
175 SendMouseEvent(mi);
176 }
177 if(mid->ButtonFlags & MOUSE_BUTTON_4_DOWN)
178 {
179 mi.mouseData |= XBUTTON1;
180 mi.dwFlags |= MOUSEEVENTF_XDOWN;
181 SendMouseEvent(mi);
182 }
183 if(mid->ButtonFlags & MOUSE_BUTTON_4_UP)
184 {
185 mi.mouseData |= XBUTTON1;
186 mi.dwFlags |= MOUSEEVENTF_XUP;
187 SendMouseEvent(mi);
188 }
189 if(mid->ButtonFlags & MOUSE_BUTTON_5_DOWN)
190 {
191 mi.mouseData |= XBUTTON2;
192 mi.dwFlags |= MOUSEEVENTF_XDOWN;
193 SendMouseEvent(mi);
194 }
195 if(mid->ButtonFlags & MOUSE_BUTTON_5_UP)
196 {
197 mi.mouseData |= XBUTTON2;
198 mi.dwFlags |= MOUSEEVENTF_XUP;
199 SendMouseEvent(mi);
200 }
201 if(mid->ButtonFlags & MOUSE_WHEEL)
202 {
203 mi.mouseData = mid->ButtonData;
204 mi.dwFlags |= MOUSEEVENTF_WHEEL;
205 SendMouseEvent(mi);
206 }
207 }
208 }
209
210 SendMouseEvent(mi);
211 }
212
213
214
215
216 VOID APIENTRY
217 MouseThreadMain(PVOID StartContext)
218 {
219 UNICODE_STRING MouseDeviceName = RTL_CONSTANT_STRING(L"\\Device\\PointerClass0");
220 OBJECT_ATTRIBUTES MouseObjectAttributes;
221 IO_STATUS_BLOCK Iosb;
222 NTSTATUS Status;
223 MOUSE_ATTRIBUTES MouseAttr;
224
225 InitializeObjectAttributes(&MouseObjectAttributes,
226 &MouseDeviceName,
227 0,
228 NULL,
229 NULL);
230 do
231 {
232 LARGE_INTEGER DueTime;
233 KEVENT Event;
234 DueTime.QuadPart = (LONGLONG)(-10000000);
235 KeInitializeEvent(&Event, NotificationEvent, FALSE);
236 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime);
237 Status = NtOpenFile(&MouseDeviceHandle,
238 FILE_ALL_ACCESS,
239 &MouseObjectAttributes,
240 &Iosb,
241 0,
242 FILE_SYNCHRONOUS_IO_ALERT);
243 } while (!NT_SUCCESS(Status));
244
245 KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
246 LOW_REALTIME_PRIORITY + 3);
247
248 for(;;)
249 {
250 /*
251 * Wait to start input.
252 */
253 DPRINT("Mouse Input Thread Waiting for start event\n");
254 Status = KeWaitForSingleObject(&InputThreadsStart,
255 0,
256 KernelMode,
257 TRUE,
258 NULL);
259 DPRINT("Mouse Input Thread Starting...\n");
260
261 /*FIXME: Does mouse attributes need to be used for anything */
262 Status = NtDeviceIoControlFile(MouseDeviceHandle,
263 NULL,
264 NULL,
265 NULL,
266 &Iosb,
267 IOCTL_MOUSE_QUERY_ATTRIBUTES,
268 &MouseAttr, sizeof(MOUSE_ATTRIBUTES),
269 NULL, 0);
270 if(!NT_SUCCESS(Status))
271 {
272 DPRINT("Failed to get mouse attributes\n");
273 }
274
275 /*
276 * Receive and process mouse input.
277 */
278 while(InputThreadsRunning)
279 {
280 MOUSE_INPUT_DATA MouseInput;
281 Status = NtReadFile(MouseDeviceHandle,
282 NULL,
283 NULL,
284 NULL,
285 &Iosb,
286 &MouseInput,
287 sizeof(MOUSE_INPUT_DATA),
288 NULL,
289 NULL);
290 if(Status == STATUS_ALERTED && !InputThreadsRunning)
291 {
292 break;
293 }
294 if(Status == STATUS_PENDING)
295 {
296 NtWaitForSingleObject(MouseDeviceHandle, FALSE, NULL);
297 Status = Iosb.Status;
298 }
299 if(!NT_SUCCESS(Status))
300 {
301 DPRINT1("Win32K: Failed to read from mouse.\n");
302 return; //(Status);
303 }
304 DPRINT("MouseEvent\n");
305 IntLastInputTick(TRUE);
306
307 UserEnterExclusive();
308
309 ProcessMouseInputData(&MouseInput, Iosb.Information / sizeof(MOUSE_INPUT_DATA));
310
311 UserLeave();
312 }
313 DPRINT("Mouse Input Thread Stopped...\n");
314 }
315 }
316
317 /* Returns a value that indicates if the key is a modifier key, and
318 * which one.
319 */
320 static UINT APIENTRY
321 IntKeyboardGetModifiers(KEYBOARD_INPUT_DATA *InputData)
322 {
323 if (InputData->Flags & KEY_E1)
324 return 0;
325
326 if (!(InputData->Flags & KEY_E0))
327 {
328 switch (InputData->MakeCode)
329 {
330 case 0x2a: /* left shift */
331 case 0x36: /* right shift */
332 return MOD_SHIFT;
333
334 case 0x1d: /* left control */
335 return MOD_CONTROL;
336
337 case 0x38: /* left alt */
338 return MOD_ALT;
339
340 default:
341 return 0;
342 }
343 }
344 else
345 {
346 switch (InputData->MakeCode)
347 {
348 case 0x1d: /* right control */
349 return MOD_CONTROL;
350
351 case 0x38: /* right alt */
352 return MOD_ALT;
353
354 case 0x5b: /* left gui (windows) */
355 case 0x5c: /* right gui (windows) */
356 return MOD_WIN;
357
358 default:
359 return 0;
360 }
361 }
362 }
363
364 /* Asks the keyboard driver to send a small table that shows which
365 * lights should connect with which scancodes
366 */
367 static NTSTATUS APIENTRY
368 IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle,
369 PKEYBOARD_INDICATOR_TRANSLATION *IndicatorTrans)
370 {
371 NTSTATUS Status;
372 DWORD Size = 0;
373 IO_STATUS_BLOCK Block;
374 PKEYBOARD_INDICATOR_TRANSLATION Ret;
375
376 Size = sizeof(KEYBOARD_INDICATOR_TRANSLATION);
377
378 Ret = ExAllocatePoolWithTag(PagedPool,
379 Size,
380 TAG_KEYBOARD);
381
382 while (Ret)
383 {
384 Status = NtDeviceIoControlFile(KeyboardDeviceHandle,
385 NULL,
386 NULL,
387 NULL,
388 &Block,
389 IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION,
390 NULL, 0,
391 Ret, Size);
392
393 if (Status != STATUS_BUFFER_TOO_SMALL)
394 break;
395
396 ExFreePoolWithTag(Ret, TAG_KEYBOARD);
397
398 Size += sizeof(KEYBOARD_INDICATOR_TRANSLATION);
399
400 Ret = ExAllocatePoolWithTag(PagedPool,
401 Size,
402 TAG_KEYBOARD);
403 }
404
405 if (!Ret)
406 return STATUS_INSUFFICIENT_RESOURCES;
407
408 if (Status != STATUS_SUCCESS)
409 {
410 ExFreePoolWithTag(Ret, TAG_KEYBOARD);
411 return Status;
412 }
413
414 *IndicatorTrans = Ret;
415 return Status;
416 }
417
418 /* Sends the keyboard commands to turn on/off the lights.
419 */
420 static NTSTATUS APIENTRY
421 IntKeyboardUpdateLeds(HANDLE KeyboardDeviceHandle,
422 PKEYBOARD_INPUT_DATA KeyInput,
423 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans)
424 {
425 NTSTATUS Status;
426 UINT Count;
427 static KEYBOARD_INDICATOR_PARAMETERS Indicators;
428 IO_STATUS_BLOCK Block;
429
430 if (!IndicatorTrans)
431 return STATUS_NOT_SUPPORTED;
432
433 if (KeyInput->Flags & (KEY_E0 | KEY_E1 | KEY_BREAK))
434 return STATUS_SUCCESS;
435
436 for (Count = 0; Count < IndicatorTrans->NumberOfIndicatorKeys; Count++)
437 {
438 if (KeyInput->MakeCode == IndicatorTrans->IndicatorList[Count].MakeCode)
439 {
440 Indicators.LedFlags ^=
441 IndicatorTrans->IndicatorList[Count].IndicatorFlags;
442
443 /* Update the lights on the hardware */
444
445 Status = NtDeviceIoControlFile(KeyboardDeviceHandle,
446 NULL,
447 NULL,
448 NULL,
449 &Block,
450 IOCTL_KEYBOARD_SET_INDICATORS,
451 &Indicators, sizeof(Indicators),
452 NULL, 0);
453
454 return Status;
455 }
456 }
457
458 return STATUS_SUCCESS;
459 }
460
461 static VOID APIENTRY
462 IntKeyboardSendWinKeyMsg()
463 {
464 PWINDOW_OBJECT Window;
465 MSG Mesg;
466
467 if (!(Window = UserGetWindowObject(InputWindowStation->ShellWindow)))
468 {
469 DPRINT1("Couldn't find window to send Windows key message!\n");
470 return;
471 }
472
473 Mesg.hwnd = InputWindowStation->ShellWindow;
474 Mesg.message = WM_SYSCOMMAND;
475 Mesg.wParam = SC_TASKLIST;
476 Mesg.lParam = 0;
477
478 /* The QS_HOTKEY is just a guess */
479 MsqPostMessage(Window->MessageQueue, &Mesg, FALSE, QS_HOTKEY);
480 }
481
482 static VOID APIENTRY
483 co_IntKeyboardSendAltKeyMsg()
484 {
485 co_MsqPostKeyboardMessage(WM_SYSCOMMAND,SC_KEYMENU,0);
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 KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
542 LOW_REALTIME_PRIORITY + 3);
543
544 IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle,
545 &IndicatorTrans);
546
547 for (;;)
548 {
549 /*
550 * Wait to start input.
551 */
552 DPRINT( "Keyboard Input Thread Waiting for start event\n" );
553 Status = KeWaitForSingleObject(&InputThreadsStart,
554 0,
555 KernelMode,
556 TRUE,
557 NULL);
558
559 DPRINT( "Keyboard Input Thread Starting...\n" );
560 /*
561 * Receive and process keyboard input.
562 */
563 while (InputThreadsRunning)
564 {
565 BOOLEAN NumKeys = 1;
566 BOOLEAN bLeftAlt;
567 KEYBOARD_INPUT_DATA KeyInput;
568 KEYBOARD_INPUT_DATA NextKeyInput;
569 LPARAM lParam = 0;
570 UINT fsModifiers, fsNextModifiers;
571 struct _ETHREAD *Thread;
572 HWND hWnd;
573 int id;
574
575 DPRINT("KeyInput @ %08x\n", &KeyInput);
576
577 Status = NtReadFile (KeyboardDeviceHandle,
578 NULL,
579 NULL,
580 NULL,
581 &Iosb,
582 &KeyInput,
583 sizeof(KEYBOARD_INPUT_DATA),
584 NULL,
585 NULL);
586
587 if(Status == STATUS_ALERTED && !InputThreadsRunning)
588 {
589 break;
590 }
591 if(Status == STATUS_PENDING)
592 {
593 NtWaitForSingleObject(KeyboardDeviceHandle, FALSE, NULL);
594 Status = Iosb.Status;
595 }
596 if(!NT_SUCCESS(Status))
597 {
598 DPRINT1("Win32K: Failed to read from mouse.\n");
599 return; //(Status);
600 }
601
602 DPRINT("KeyRaw: %s %04x\n",
603 (KeyInput.Flags & KEY_BREAK) ? "up" : "down",
604 KeyInput.MakeCode );
605
606 if (Status == STATUS_ALERTED && !InputThreadsRunning)
607 break;
608
609 if (!NT_SUCCESS(Status))
610 {
611 DPRINT1("Win32K: Failed to read from keyboard.\n");
612 return; //(Status);
613 }
614
615 /* Set LastInputTick */
616 IntLastInputTick(TRUE);
617
618 /* Update modifier state */
619 fsModifiers = IntKeyboardGetModifiers(&KeyInput);
620
621 if (fsModifiers)
622 {
623 if (KeyInput.Flags & KEY_BREAK)
624 {
625 ModifierState &= ~fsModifiers;
626 if(fsModifiers == MOD_ALT)
627 {
628 if(KeyInput.Flags & KEY_E0)
629 {
630 gQueueKeyStateTable[VK_RMENU] = 0;
631 }
632 else
633 {
634 gQueueKeyStateTable[VK_LMENU] = 0;
635 }
636 if (gQueueKeyStateTable[VK_RMENU] == 0 &&
637 gQueueKeyStateTable[VK_LMENU] == 0)
638 {
639 gQueueKeyStateTable[VK_MENU] = 0;
640 }
641 }
642 }
643 else
644 {
645 ModifierState |= fsModifiers;
646
647 if (ModifierState == fsModifiers &&
648 (fsModifiers == MOD_ALT || fsModifiers == MOD_WIN))
649 {
650 /* First send out special notifications
651 * (For alt, the message that turns on accelerator
652 * display, not sure what for win. Both TODO though.)
653 */
654 bLeftAlt = FALSE;
655 if(fsModifiers == MOD_ALT)
656 {
657 if(KeyInput.Flags & KEY_E0)
658 {
659 gQueueKeyStateTable[VK_RMENU] = 0x80;
660 }
661 else
662 {
663 gQueueKeyStateTable[VK_LMENU] = 0x80;
664 bLeftAlt = TRUE;
665 }
666
667 gQueueKeyStateTable[VK_MENU] = 0x80;
668 }
669
670 /* Read the next key before sending this one */
671 do
672 {
673 Status = NtReadFile (KeyboardDeviceHandle,
674 NULL,
675 NULL,
676 NULL,
677 &Iosb,
678 &NextKeyInput,
679 sizeof(KEYBOARD_INPUT_DATA),
680 NULL,
681 NULL);
682 DPRINT("KeyRaw: %s %04x\n",
683 (NextKeyInput.Flags & KEY_BREAK) ? "up":"down",
684 NextKeyInput.MakeCode );
685
686 if (Status == STATUS_ALERTED && !InputThreadsRunning)
687 goto KeyboardEscape;
688
689 }
690 while ((!(NextKeyInput.Flags & KEY_BREAK)) &&
691 NextKeyInput.MakeCode == KeyInput.MakeCode);
692 /* ^ Ignore repeats, they'll be KEY_MAKE and the same
693 * code. I'm not caring about the counting, not sure
694 * if that matters. I think not.
695 */
696
697 /* If the ModifierState is now empty again, send a
698 * special notification and eat both keypresses
699 */
700
701 fsNextModifiers = IntKeyboardGetModifiers(&NextKeyInput);
702
703 if (fsNextModifiers)
704 ModifierState ^= fsNextModifiers;
705
706 if (ModifierState == 0)
707 {
708 if (fsModifiers == MOD_WIN)
709 IntKeyboardSendWinKeyMsg();
710 else if (fsModifiers == MOD_ALT)
711 {
712 gQueueKeyStateTable[VK_MENU] = 0;
713 if(bLeftAlt)
714 {
715 gQueueKeyStateTable[VK_LMENU] = 0;
716 }
717 else
718 {
719 gQueueKeyStateTable[VK_RMENU] = 0;
720 }
721 co_IntKeyboardSendAltKeyMsg();
722 }
723 continue;
724 }
725
726 NumKeys = 2;
727 }
728 }
729 }
730
731 for (;NumKeys;memcpy(&KeyInput, &NextKeyInput, sizeof(KeyInput)),
732 NumKeys--)
733 {
734 lParam = 0;
735
736 IntKeyboardUpdateLeds(KeyboardDeviceHandle,
737 &KeyInput,
738 IndicatorTrans);
739
740 /* While we are working, we set up lParam. The format is:
741 * 0-15: The number of times this key has autorepeated
742 * 16-23: The keyboard scancode
743 * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
744 * Note that E1 is only used for PAUSE (E1-1D-45) and
745 * E0-45 happens not to be anything.
746 * 29: Alt is pressed ('Context code')
747 * 30: Previous state, if the key was down before this message
748 * This is a cheap way to ignore autorepeat keys
749 * 31: 1 if the key is being pressed
750 */
751
752 /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
753 * and it's the same key as the last one, increase the repeat
754 * count.
755 */
756
757 if (!(KeyInput.Flags & KEY_BREAK))
758 {
759 if (((KeyInput.Flags & (KEY_E0 | KEY_E1)) == LastFlags) &&
760 (KeyInput.MakeCode == LastMakeCode))
761 {
762 RepeatCount++;
763 lParam |= (1 << 30);
764 }
765 else
766 {
767 RepeatCount = 0;
768 LastFlags = KeyInput.Flags & (KEY_E0 | KEY_E1);
769 LastMakeCode = KeyInput.MakeCode;
770 }
771 }
772 else
773 {
774 LastFlags = 0;
775 LastMakeCode = 0; /* Should never match */
776 lParam |= (1 << 30) | (1 << 31);
777 }
778
779 lParam |= RepeatCount;
780
781 lParam |= (KeyInput.MakeCode & 0xff) << 16;
782
783 if (KeyInput.Flags & KEY_E0)
784 lParam |= (1 << 24);
785
786 if (ModifierState & MOD_ALT)
787 {
788 lParam |= (1 << 29);
789
790 if (!(KeyInput.Flags & KEY_BREAK))
791 msg.message = WM_SYSKEYDOWN;
792 else
793 msg.message = WM_SYSKEYUP;
794 }
795 else
796 {
797 if (!(KeyInput.Flags & KEY_BREAK))
798 msg.message = WM_KEYDOWN;
799 else
800 msg.message = WM_KEYUP;
801 }
802
803 /* Find the target thread whose locale is in effect */
804 FocusQueue = IntGetFocusMessageQueue();
805
806 /* This might cause us to lose hot keys, which are important
807 * (ctrl-alt-del secure attention sequence). Not sure if it
808 * can happen though.
809 */
810 if (!FocusQueue)
811 continue;
812
813 msg.lParam = lParam;
814 msg.hwnd = FocusQueue->FocusWindow;
815
816 FocusThread = FocusQueue->Thread;
817
818 if (!(FocusThread && FocusThread->Tcb.Win32Thread &&
819 ((PTHREADINFO)FocusThread->Tcb.Win32Thread)->KeyboardLayout))
820 continue;
821
822 /* This function uses lParam to fill wParam according to the
823 * keyboard layout in use.
824 */
825 W32kKeyProcessMessage(&msg,
826 ((PTHREADINFO)FocusThread->Tcb.Win32Thread)->KeyboardLayout->KBTables,
827 KeyInput.Flags & KEY_E0 ? 0xE0 :
828 (KeyInput.Flags & KEY_E1 ? 0xE1 : 0));
829
830 if (GetHotKey(ModifierState,
831 msg.wParam,
832 &Thread,
833 &hWnd,
834 &id))
835 {
836 if (!(KeyInput.Flags & KEY_BREAK))
837 {
838 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd, id);
839 MsqPostHotKeyMessage (Thread,
840 hWnd,
841 (WPARAM)id,
842 MAKELPARAM((WORD)ModifierState,
843 (WORD)msg.wParam));
844 }
845 continue; /* Eat key up motion too */
846 }
847
848 /*
849 * Post a keyboard message.
850 */
851 co_MsqPostKeyboardMessage(msg.message,msg.wParam,msg.lParam);
852 }
853 }
854
855 KeyboardEscape:
856 DPRINT( "KeyboardInput Thread Stopped...\n" );
857 }
858 }
859
860
861 static PVOID Objects[2];
862 /*
863 Raw Input Thread.
864 Since this relies on InputThreadsStart, just fake it.
865 */
866 static VOID APIENTRY
867 RawInputThreadMain(PVOID StartContext)
868 {
869 NTSTATUS Status;
870 LARGE_INTEGER DueTime;
871
872 DueTime.QuadPart = (LONGLONG)(-10000000);
873
874 do
875 {
876 KEVENT Event;
877 KeInitializeEvent(&Event, NotificationEvent, FALSE);
878 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime);
879 } while (!NT_SUCCESS(Status));
880
881
882 Objects[0] = &InputThreadsStart;
883
884 MasterTimer = ExAllocatePoolWithTag(NonPagedPool, sizeof(KTIMER), TAG_INPUT);
885 if (!MasterTimer)
886 {
887 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
888 return;
889 }
890 KeInitializeTimer(MasterTimer);
891 Objects[1] = MasterTimer;
892
893 // This thread requires win32k!
894 Status = Win32kInitWin32Thread(PsGetCurrentThread());
895 if (!NT_SUCCESS(Status))
896 {
897 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
898 return; //(Status);
899 }
900
901 ptiRawInput = PsGetCurrentThreadWin32Thread();
902 DPRINT1("\nRaw Input Thread 0x%x \n", ptiRawInput);
903
904
905 KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
906 LOW_REALTIME_PRIORITY + 3);
907
908 UserEnterExclusive();
909 StartTheTimers();
910 UserLeave();
911
912 //
913 // ATM, we just have one job to handle, merge the other two later.
914 //
915 for(;;)
916 {
917 DPRINT( "Raw Input Thread Waiting for start event\n" );
918
919 Status = KeWaitForMultipleObjects( 2,
920 Objects,
921 WaitAll, //WaitAny,
922 WrUserRequest,
923 KernelMode,
924 TRUE,
925 NULL,
926 NULL);
927 DPRINT( "Raw Input Thread Starting...\n" );
928
929 ProcessTimers();
930 }
931 DPRINT1("Raw Input Thread Exit!\n");
932 }
933
934 NTSTATUS FASTCALL
935 InitInputImpl(VOID)
936 {
937 NTSTATUS Status;
938
939 KeInitializeEvent(&InputThreadsStart, NotificationEvent, FALSE);
940
941 /* Initialize the default keyboard layout */
942 if(!UserInitDefaultKeyboardLayout())
943 {
944 DPRINT1("Failed to initialize default keyboard layout!\n");
945 }
946
947 Status = PsCreateSystemThread(&RawInputThreadHandle,
948 THREAD_ALL_ACCESS,
949 NULL,
950 NULL,
951 &RawInputThreadId,
952 RawInputThreadMain,
953 NULL);
954 if (!NT_SUCCESS(Status))
955 {
956 DPRINT1("Win32K: Failed to create raw thread.\n");
957 }
958
959 Status = PsCreateSystemThread(&KeyboardThreadHandle,
960 THREAD_ALL_ACCESS,
961 NULL,
962 NULL,
963 &KeyboardThreadId,
964 KeyboardThreadMain,
965 NULL);
966 if (!NT_SUCCESS(Status))
967 {
968 DPRINT1("Win32K: Failed to create keyboard thread.\n");
969 }
970
971 Status = PsCreateSystemThread(&MouseThreadHandle,
972 THREAD_ALL_ACCESS,
973 NULL,
974 NULL,
975 &MouseThreadId,
976 MouseThreadMain,
977 NULL);
978 if (!NT_SUCCESS(Status))
979 {
980 DPRINT1("Win32K: Failed to create mouse thread.\n");
981 }
982
983 InputThreadsRunning = TRUE;
984 KeSetEvent(&InputThreadsStart, IO_NO_INCREMENT, FALSE);
985
986 return STATUS_SUCCESS;
987 }
988
989 NTSTATUS FASTCALL
990 CleanupInputImp(VOID)
991 {
992 return(STATUS_SUCCESS);
993 }
994
995 BOOL
996 APIENTRY
997 NtUserDragDetect(
998 HWND hWnd,
999 POINT pt) // Just like the User call.
1000 {
1001 UNIMPLEMENTED
1002 return 0;
1003 }
1004
1005 BOOL FASTCALL
1006 IntBlockInput(PTHREADINFO W32Thread, BOOL BlockIt)
1007 {
1008 PTHREADINFO OldBlock;
1009 ASSERT(W32Thread);
1010
1011 if(!W32Thread->Desktop || ((W32Thread->TIF_flags & TIF_INCLEANUP) && BlockIt))
1012 {
1013 /*
1014 * fail blocking if exiting the thread
1015 */
1016
1017 return FALSE;
1018 }
1019
1020 /*
1021 * FIXME - check access rights of the window station
1022 * e.g. services running in the service window station cannot block input
1023 */
1024 if(!ThreadHasInputAccess(W32Thread) ||
1025 !IntIsActiveDesktop(W32Thread->Desktop))
1026 {
1027 SetLastWin32Error(ERROR_ACCESS_DENIED);
1028 return FALSE;
1029 }
1030
1031 ASSERT(W32Thread->Desktop);
1032 OldBlock = W32Thread->Desktop->BlockInputThread;
1033 if(OldBlock)
1034 {
1035 if(OldBlock != W32Thread)
1036 {
1037 SetLastWin32Error(ERROR_ACCESS_DENIED);
1038 return FALSE;
1039 }
1040 W32Thread->Desktop->BlockInputThread = (BlockIt ? W32Thread : NULL);
1041 return OldBlock == NULL;
1042 }
1043
1044 W32Thread->Desktop->BlockInputThread = (BlockIt ? W32Thread : NULL);
1045 return OldBlock == NULL;
1046 }
1047
1048 BOOL
1049 APIENTRY
1050 NtUserBlockInput(
1051 BOOL BlockIt)
1052 {
1053 DECLARE_RETURN(BOOLEAN);
1054
1055 DPRINT("Enter NtUserBlockInput\n");
1056 UserEnterExclusive();
1057
1058 RETURN( IntBlockInput(PsGetCurrentThreadWin32Thread(), BlockIt));
1059
1060 CLEANUP:
1061 DPRINT("Leave NtUserBlockInput, ret=%i\n",_ret_);
1062 UserLeave();
1063 END_CLEANUP;
1064 }
1065
1066 BOOL FASTCALL
1067 IntMouseInput(MOUSEINPUT *mi)
1068 {
1069 const UINT SwapBtnMsg[2][2] =
1070 {
1071 {
1072 WM_LBUTTONDOWN, WM_RBUTTONDOWN
1073 },
1074 {WM_LBUTTONUP, WM_RBUTTONUP}
1075 };
1076 const WPARAM SwapBtn[2] =
1077 {
1078 MK_LBUTTON, MK_RBUTTON
1079 };
1080 POINT MousePos = {0}, OrgPos;
1081 PSYSTEM_CURSORINFO CurInfo;
1082 PWINSTATION_OBJECT WinSta;
1083 BOOL DoMove, SwapButtons;
1084 MSG Msg;
1085 SURFACE *psurf;
1086 SURFOBJ *pso;
1087 PDC dc;
1088 PWINDOW_OBJECT DesktopWindow;
1089
1090 #if 1
1091
1092 HDC hDC;
1093
1094 /* FIXME - get the screen dc from the window station or desktop */
1095 if(!(hDC = IntGetScreenDC()))
1096 {
1097 return FALSE;
1098 }
1099 #endif
1100
1101 ASSERT(mi);
1102 #if 0
1103
1104 WinSta = PsGetCurrentProcessWin32Process()->WindowStation;
1105 #else
1106 /* FIXME - ugly hack but as long as we're using this dumb callback from the
1107 mouse class driver, we can't access the window station from the calling
1108 process */
1109 WinSta = InputWindowStation;
1110 #endif
1111
1112 ASSERT(WinSta);
1113
1114 CurInfo = IntGetSysCursorInfo(WinSta);
1115
1116 if(!mi->time)
1117 {
1118 LARGE_INTEGER LargeTickCount;
1119 KeQueryTickCount(&LargeTickCount);
1120 mi->time = MsqCalculateMessageTime(&LargeTickCount);
1121 }
1122
1123 SwapButtons = gspv.bMouseBtnSwap;
1124 DoMove = FALSE;
1125
1126 IntGetCursorLocation(WinSta, &MousePos);
1127 OrgPos.x = MousePos.x;
1128 OrgPos.y = MousePos.y;
1129
1130 if(mi->dwFlags & MOUSEEVENTF_MOVE)
1131 {
1132 if(mi->dwFlags & MOUSEEVENTF_ABSOLUTE)
1133 {
1134 MousePos.x = mi->dx;
1135 MousePos.y = mi->dy;
1136 }
1137 else
1138 {
1139 MousePos.x += mi->dx;
1140 MousePos.y += mi->dy;
1141 }
1142
1143 DesktopWindow = IntGetWindowObject(WinSta->ActiveDesktop->DesktopWindow);
1144
1145 if (DesktopWindow)
1146 {
1147 if(MousePos.x >= DesktopWindow->Wnd->rcClient.right)
1148 MousePos.x = DesktopWindow->Wnd->rcClient.right - 1;
1149 if(MousePos.y >= DesktopWindow->Wnd->rcClient.bottom)
1150 MousePos.y = DesktopWindow->Wnd->rcClient.bottom - 1;
1151 UserDereferenceObject(DesktopWindow);
1152 }
1153
1154 if(MousePos.x < 0)
1155 MousePos.x = 0;
1156 if(MousePos.y < 0)
1157 MousePos.y = 0;
1158
1159 if(CurInfo->CursorClipInfo.IsClipped)
1160 {
1161 /* The mouse cursor needs to be clipped */
1162
1163 if(MousePos.x >= (LONG)CurInfo->CursorClipInfo.Right)
1164 MousePos.x = (LONG)CurInfo->CursorClipInfo.Right;
1165 if(MousePos.x < (LONG)CurInfo->CursorClipInfo.Left)
1166 MousePos.x = (LONG)CurInfo->CursorClipInfo.Left;
1167 if(MousePos.y >= (LONG)CurInfo->CursorClipInfo.Bottom)
1168 MousePos.y = (LONG)CurInfo->CursorClipInfo.Bottom;
1169 if(MousePos.y < (LONG)CurInfo->CursorClipInfo.Top)
1170 MousePos.y = (LONG)CurInfo->CursorClipInfo.Top;
1171 }
1172
1173 DoMove = (MousePos.x != OrgPos.x || MousePos.y != OrgPos.y);
1174 }
1175
1176 if (DoMove)
1177 {
1178 dc = DC_LockDc(hDC);
1179 if (dc)
1180 {
1181 psurf = dc->dclevel.pSurface;
1182 if (psurf)
1183 {
1184 pso = &psurf->SurfObj;
1185
1186 if (CurInfo->ShowingCursor)
1187 {
1188 IntEngMovePointer(pso, MousePos.x, MousePos.y, &(GDIDEV(pso)->Pointer.Exclude));
1189 }
1190 /* Only now, update the info in the PDEVOBJ, so EngMovePointer can
1191 * use the old values to move the pointer image */
1192 gpsi->ptCursor.x = MousePos.x;
1193 gpsi->ptCursor.y = MousePos.y;
1194 }
1195
1196 DC_UnlockDc(dc);
1197 }
1198 }
1199
1200 /*
1201 * Insert the messages into the system queue
1202 */
1203
1204 Msg.wParam = CurInfo->ButtonsDown;
1205 Msg.lParam = MAKELPARAM(MousePos.x, MousePos.y);
1206 Msg.pt = MousePos;
1207
1208 if (gQueueKeyStateTable[VK_SHIFT] & 0xc0)
1209 {
1210 Msg.wParam |= MK_SHIFT;
1211 }
1212
1213 if (gQueueKeyStateTable[VK_CONTROL] & 0xc0)
1214 {
1215 Msg.wParam |= MK_CONTROL;
1216 }
1217
1218 if(DoMove)
1219 {
1220 Msg.message = WM_MOUSEMOVE;
1221 MsqInsertSystemMessage(&Msg);
1222 }
1223
1224 Msg.message = 0;
1225 if(mi->dwFlags & MOUSEEVENTF_LEFTDOWN)
1226 {
1227 gQueueKeyStateTable[VK_LBUTTON] |= 0xc0;
1228 Msg.message = SwapBtnMsg[0][SwapButtons];
1229 CurInfo->ButtonsDown |= SwapBtn[SwapButtons];
1230 MsqInsertSystemMessage(&Msg);
1231 }
1232 else if(mi->dwFlags & MOUSEEVENTF_LEFTUP)
1233 {
1234 gQueueKeyStateTable[VK_LBUTTON] &= ~0x80;
1235 Msg.message = SwapBtnMsg[1][SwapButtons];
1236 CurInfo->ButtonsDown &= ~SwapBtn[SwapButtons];
1237 MsqInsertSystemMessage(&Msg);
1238 }
1239 if(mi->dwFlags & MOUSEEVENTF_MIDDLEDOWN)
1240 {
1241 gQueueKeyStateTable[VK_MBUTTON] |= 0xc0;
1242 Msg.message = WM_MBUTTONDOWN;
1243 CurInfo->ButtonsDown |= MK_MBUTTON;
1244 MsqInsertSystemMessage(&Msg);
1245 }
1246 else if(mi->dwFlags & MOUSEEVENTF_MIDDLEUP)
1247 {
1248 gQueueKeyStateTable[VK_MBUTTON] &= ~0x80;
1249 Msg.message = WM_MBUTTONUP;
1250 CurInfo->ButtonsDown &= ~MK_MBUTTON;
1251 MsqInsertSystemMessage(&Msg);
1252 }
1253 if(mi->dwFlags & MOUSEEVENTF_RIGHTDOWN)
1254 {
1255 gQueueKeyStateTable[VK_RBUTTON] |= 0xc0;
1256 Msg.message = SwapBtnMsg[0][!SwapButtons];
1257 CurInfo->ButtonsDown |= SwapBtn[!SwapButtons];
1258 MsqInsertSystemMessage(&Msg);
1259 }
1260 else if(mi->dwFlags & MOUSEEVENTF_RIGHTUP)
1261 {
1262 gQueueKeyStateTable[VK_RBUTTON] &= ~0x80;
1263 Msg.message = SwapBtnMsg[1][!SwapButtons];
1264 CurInfo->ButtonsDown &= ~SwapBtn[!SwapButtons];
1265 MsqInsertSystemMessage(&Msg);
1266 }
1267
1268 if((mi->dwFlags & (MOUSEEVENTF_XDOWN | MOUSEEVENTF_XUP)) &&
1269 (mi->dwFlags & MOUSEEVENTF_WHEEL))
1270 {
1271 /* fail because both types of events use the mouseData field */
1272 return FALSE;
1273 }
1274
1275 if(mi->dwFlags & MOUSEEVENTF_XDOWN)
1276 {
1277 Msg.message = WM_XBUTTONDOWN;
1278 if(mi->mouseData & XBUTTON1)
1279 {
1280 gQueueKeyStateTable[VK_XBUTTON1] |= 0xc0;
1281 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
1282 CurInfo->ButtonsDown |= XBUTTON1;
1283 MsqInsertSystemMessage(&Msg);
1284 }
1285 if(mi->mouseData & XBUTTON2)
1286 {
1287 gQueueKeyStateTable[VK_XBUTTON2] |= 0xc0;
1288 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
1289 CurInfo->ButtonsDown |= XBUTTON2;
1290 MsqInsertSystemMessage(&Msg);
1291 }
1292 }
1293 else if(mi->dwFlags & MOUSEEVENTF_XUP)
1294 {
1295 Msg.message = WM_XBUTTONUP;
1296 if(mi->mouseData & XBUTTON1)
1297 {
1298 gQueueKeyStateTable[VK_XBUTTON1] &= ~0x80;
1299 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
1300 CurInfo->ButtonsDown &= ~XBUTTON1;
1301 MsqInsertSystemMessage(&Msg);
1302 }
1303 if(mi->mouseData & XBUTTON2)
1304 {
1305 gQueueKeyStateTable[VK_XBUTTON2] &= ~0x80;
1306 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
1307 CurInfo->ButtonsDown &= ~XBUTTON2;
1308 MsqInsertSystemMessage(&Msg);
1309 }
1310 }
1311 if(mi->dwFlags & MOUSEEVENTF_WHEEL)
1312 {
1313 Msg.message = WM_MOUSEWHEEL;
1314 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, mi->mouseData);
1315 MsqInsertSystemMessage(&Msg);
1316 }
1317
1318 return TRUE;
1319 }
1320
1321 BOOL FASTCALL
1322 IntKeyboardInput(KEYBDINPUT *ki)
1323 {
1324 return FALSE;
1325 }
1326
1327 UINT
1328 APIENTRY
1329 NtUserSendInput(
1330 UINT nInputs,
1331 LPINPUT pInput,
1332 INT cbSize)
1333 {
1334 PTHREADINFO W32Thread;
1335 UINT cnt;
1336 DECLARE_RETURN(UINT);
1337
1338 DPRINT("Enter NtUserSendInput\n");
1339 UserEnterExclusive();
1340
1341 W32Thread = PsGetCurrentThreadWin32Thread();
1342 ASSERT(W32Thread);
1343
1344 if(!W32Thread->Desktop)
1345 {
1346 RETURN( 0);
1347 }
1348
1349 if(!nInputs || !pInput || (cbSize != sizeof(INPUT)))
1350 {
1351 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1352 RETURN( 0);
1353 }
1354
1355 /*
1356 * FIXME - check access rights of the window station
1357 * e.g. services running in the service window station cannot block input
1358 */
1359 if(!ThreadHasInputAccess(W32Thread) ||
1360 !IntIsActiveDesktop(W32Thread->Desktop))
1361 {
1362 SetLastWin32Error(ERROR_ACCESS_DENIED);
1363 RETURN( 0);
1364 }
1365
1366 cnt = 0;
1367 while(nInputs--)
1368 {
1369 INPUT SafeInput;
1370 NTSTATUS Status;
1371
1372 Status = MmCopyFromCaller(&SafeInput, pInput++, sizeof(INPUT));
1373 if(!NT_SUCCESS(Status))
1374 {
1375 SetLastNtError(Status);
1376 RETURN( cnt);
1377 }
1378
1379 switch(SafeInput.type)
1380 {
1381 case INPUT_MOUSE:
1382 if(IntMouseInput(&SafeInput.mi))
1383 {
1384 cnt++;
1385 }
1386 break;
1387 case INPUT_KEYBOARD:
1388 if(IntKeyboardInput(&SafeInput.ki))
1389 {
1390 cnt++;
1391 }
1392 break;
1393 case INPUT_HARDWARE:
1394 break;
1395 #ifndef NDEBUG
1396
1397 default:
1398 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput.type);
1399 break;
1400 #endif
1401
1402 }
1403 }
1404
1405 RETURN( cnt);
1406
1407 CLEANUP:
1408 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_);
1409 UserLeave();
1410 END_CLEANUP;
1411 }
1412
1413 /* EOF */