Fixed skipped events from keyboard:
[reactos.git] / reactos / subsys / 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 <ddk/ntddkbd.h>
34
35 #define NDEBUG
36 #include <debug.h>
37
38 extern BYTE gQueueKeyStateTable[];
39
40 /* GLOBALS *******************************************************************/
41
42 static HANDLE MouseDeviceHandle;
43 static HANDLE MouseThreadHandle;
44 static CLIENT_ID MouseThreadId;
45 static HANDLE KeyboardThreadHandle;
46 static CLIENT_ID KeyboardThreadId;
47 static HANDLE KeyboardDeviceHandle;
48 static KEVENT InputThreadsStart;
49 static BOOLEAN InputThreadsRunning = FALSE;
50 PUSER_MESSAGE_QUEUE pmPrimitiveMessageQueue = 0;
51
52 /* FUNCTIONS *****************************************************************/
53
54 #define ClearMouseInput(mi) \
55 mi.dx = 0; \
56 mi.dy = 0; \
57 mi.mouseData = 0; \
58 mi.dwFlags = 0;
59
60 #define SendMouseEvent(mi) \
61 if(mi.dx != 0 || mi.dy != 0) \
62 mi.dwFlags |= MOUSEEVENTF_MOVE; \
63 if(mi.dwFlags) \
64 IntMouseInput(&mi); \
65 ClearMouseInput(mi);
66
67 VOID FASTCALL
68 ProcessMouseInputData(PMOUSE_INPUT_DATA Data, ULONG InputCount)
69 {
70 PMOUSE_INPUT_DATA mid;
71 MOUSEINPUT mi;
72 ULONG i;
73
74 ClearMouseInput(mi);
75 mi.time = 0;
76 mi.dwExtraInfo = 0;
77 for(i = 0; i < InputCount; i++)
78 {
79 mid = (Data + i);
80 mi.dx += mid->LastX;
81 mi.dy += mid->LastY;
82
83 if(mid->ButtonFlags)
84 {
85 if(mid->ButtonFlags & MOUSE_LEFT_BUTTON_DOWN)
86 {
87 mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
88 SendMouseEvent(mi);
89 }
90 if(mid->ButtonFlags & MOUSE_LEFT_BUTTON_UP)
91 {
92 mi.dwFlags |= MOUSEEVENTF_LEFTUP;
93 SendMouseEvent(mi);
94 }
95 if(mid->ButtonFlags & MOUSE_MIDDLE_BUTTON_DOWN)
96 {
97 mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
98 SendMouseEvent(mi);
99 }
100 if(mid->ButtonFlags & MOUSE_MIDDLE_BUTTON_UP)
101 {
102 mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
103 SendMouseEvent(mi);
104 }
105 if(mid->ButtonFlags & MOUSE_RIGHT_BUTTON_DOWN)
106 {
107 mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
108 SendMouseEvent(mi);
109 }
110 if(mid->ButtonFlags & MOUSE_RIGHT_BUTTON_UP)
111 {
112 mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
113 SendMouseEvent(mi);
114 }
115 if(mid->ButtonFlags & MOUSE_BUTTON_4_DOWN)
116 {
117 mi.mouseData |= XBUTTON1;
118 mi.dwFlags |= MOUSEEVENTF_XDOWN;
119 SendMouseEvent(mi);
120 }
121 if(mid->ButtonFlags & MOUSE_BUTTON_4_UP)
122 {
123 mi.mouseData |= XBUTTON1;
124 mi.dwFlags |= MOUSEEVENTF_XUP;
125 SendMouseEvent(mi);
126 }
127 if(mid->ButtonFlags & MOUSE_BUTTON_5_DOWN)
128 {
129 mi.mouseData |= XBUTTON2;
130 mi.dwFlags |= MOUSEEVENTF_XDOWN;
131 SendMouseEvent(mi);
132 }
133 if(mid->ButtonFlags & MOUSE_BUTTON_5_UP)
134 {
135 mi.mouseData |= XBUTTON2;
136 mi.dwFlags |= MOUSEEVENTF_XUP;
137 SendMouseEvent(mi);
138 }
139 if(mid->ButtonFlags & MOUSE_WHEEL)
140 {
141 mi.mouseData = mid->ButtonData;
142 mi.dwFlags |= MOUSEEVENTF_WHEEL;
143 SendMouseEvent(mi);
144 }
145 }
146 }
147
148 SendMouseEvent(mi);
149 }
150
151 VOID STDCALL
152 MouseThreadMain(PVOID StartContext)
153 {
154 UNICODE_STRING MouseDeviceName = RTL_CONSTANT_STRING(L"\\Device\\PointerClass0");
155 OBJECT_ATTRIBUTES MouseObjectAttributes;
156 IO_STATUS_BLOCK Iosb;
157 NTSTATUS Status;
158
159 InitializeObjectAttributes(&MouseObjectAttributes,
160 &MouseDeviceName,
161 0,
162 NULL,
163 NULL);
164 do
165 {
166 LARGE_INTEGER DueTime;
167 KEVENT Event;
168 DueTime.QuadPart = (LONGLONG)(-10000000);
169 KeInitializeEvent(&Event, NotificationEvent, FALSE);
170 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime);
171 Status = NtOpenFile(&MouseDeviceHandle,
172 FILE_ALL_ACCESS,
173 &MouseObjectAttributes,
174 &Iosb,
175 0,
176 FILE_SYNCHRONOUS_IO_ALERT);
177 } while (!NT_SUCCESS(Status));
178
179 for(;;)
180 {
181 /*
182 * Wait to start input.
183 */
184 DPRINT("Mouse Input Thread Waiting for start event\n");
185 Status = KeWaitForSingleObject(&InputThreadsStart,
186 0,
187 KernelMode,
188 TRUE,
189 NULL);
190 DPRINT("Mouse Input Thread Starting...\n");
191
192 /*
193 * Receive and process mouse input.
194 */
195 while(InputThreadsRunning)
196 {
197 MOUSE_INPUT_DATA MouseInput;
198 Status = NtReadFile(MouseDeviceHandle,
199 NULL,
200 NULL,
201 NULL,
202 &Iosb,
203 &MouseInput,
204 sizeof(MOUSE_INPUT_DATA),
205 NULL,
206 NULL);
207 if(Status == STATUS_ALERTED && !InputThreadsRunning)
208 {
209 break;
210 }
211 if(Status == STATUS_PENDING)
212 {
213 NtWaitForSingleObject(MouseDeviceHandle, FALSE, NULL);
214 Status = Iosb.Status;
215 }
216 if(!NT_SUCCESS(Status))
217 {
218 DPRINT1("Win32K: Failed to read from mouse.\n");
219 return; //(Status);
220 }
221 DPRINT("MouseEvent\n");
222
223 UserEnterExclusive();
224
225 ProcessMouseInputData(&MouseInput, Iosb.Information / sizeof(MOUSE_INPUT_DATA));
226
227 UserLeave();
228 }
229 DPRINT("Mouse Input Thread Stopped...\n");
230 }
231 }
232
233 /* Returns a value that indicates if the key is a modifier key, and
234 * which one.
235 */
236 STATIC UINT STDCALL
237 IntKeyboardGetModifiers(KEYBOARD_INPUT_DATA *InputData)
238 {
239 if (InputData->Flags & KEY_E1)
240 return 0;
241
242 if (!(InputData->Flags & KEY_E0))
243 {
244 switch (InputData->MakeCode)
245 {
246 case 0x2a: /* left shift */
247 case 0x36: /* right shift */
248 return MOD_SHIFT;
249
250 case 0x1d: /* left control */
251 return MOD_CONTROL;
252
253 case 0x38: /* left alt */
254 return MOD_ALT;
255
256 default:
257 return 0;
258 }
259 }
260 else
261 {
262 switch (InputData->MakeCode)
263 {
264 case 0x1d: /* right control */
265 return MOD_CONTROL;
266
267 case 0x38: /* right alt */
268 return MOD_ALT;
269
270 case 0x5b: /* left gui (windows) */
271 case 0x5c: /* right gui (windows) */
272 return MOD_WIN;
273
274 default:
275 return 0;
276 }
277 }
278 }
279
280 /* Asks the keyboard driver to send a small table that shows which
281 * lights should connect with which scancodes
282 */
283 STATIC NTSTATUS STDCALL
284 IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle,
285 PKEYBOARD_INDICATOR_TRANSLATION *IndicatorTrans)
286 {
287 NTSTATUS Status;
288 DWORD Size = 0;
289 IO_STATUS_BLOCK Block;
290 PKEYBOARD_INDICATOR_TRANSLATION Ret;
291
292 Size = sizeof(KEYBOARD_INDICATOR_TRANSLATION);
293
294 Ret = ExAllocatePoolWithTag(PagedPool,
295 Size,
296 TAG_KEYBOARD);
297
298 while (Ret)
299 {
300 Status = NtDeviceIoControlFile(KeyboardDeviceHandle,
301 NULL,
302 NULL,
303 NULL,
304 &Block,
305 IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION,
306 NULL, 0,
307 Ret, Size);
308
309 if (Status != STATUS_BUFFER_TOO_SMALL)
310 break;
311
312 ExFreePool(Ret);
313
314 Size += sizeof(KEYBOARD_INDICATOR_TRANSLATION);
315
316 Ret = ExAllocatePoolWithTag(PagedPool,
317 Size,
318 TAG_KEYBOARD);
319 }
320
321 if (!Ret)
322 return STATUS_INSUFFICIENT_RESOURCES;
323
324 if (Status != STATUS_SUCCESS)
325 {
326 ExFreePool(Ret);
327 return Status;
328 }
329
330 *IndicatorTrans = Ret;
331 return Status;
332 }
333
334 /* Sends the keyboard commands to turn on/off the lights.
335 */
336 STATIC NTSTATUS STDCALL
337 IntKeyboardUpdateLeds(HANDLE KeyboardDeviceHandle,
338 PKEYBOARD_INPUT_DATA KeyInput,
339 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans)
340 {
341 NTSTATUS Status;
342 UINT Count;
343 static KEYBOARD_INDICATOR_PARAMETERS Indicators;
344 IO_STATUS_BLOCK Block;
345
346 if (!IndicatorTrans)
347 return STATUS_NOT_SUPPORTED;
348
349 if (KeyInput->Flags & (KEY_E0 | KEY_E1 | KEY_BREAK))
350 return STATUS_SUCCESS;
351
352 for (Count = 0; Count < IndicatorTrans->NumberOfIndicatorKeys; Count++)
353 {
354 if (KeyInput->MakeCode == IndicatorTrans->IndicatorList[Count].MakeCode)
355 {
356 Indicators.LedFlags ^=
357 IndicatorTrans->IndicatorList[Count].IndicatorFlags;
358
359 /* Update the lights on the hardware */
360
361 Status = NtDeviceIoControlFile(KeyboardDeviceHandle,
362 NULL,
363 NULL,
364 NULL,
365 &Block,
366 IOCTL_KEYBOARD_SET_INDICATORS,
367 &Indicators, sizeof(Indicators),
368 NULL, 0);
369
370 return Status;
371 }
372 }
373
374 return STATUS_SUCCESS;
375 }
376
377 STATIC VOID STDCALL
378 IntKeyboardSendWinKeyMsg()
379 {
380 PWINDOW_OBJECT Window;
381 MSG Mesg;
382
383 if (!(Window = UserGetWindowObject(InputWindowStation->ShellWindow)))
384 {
385 DPRINT1("Couldn't find window to send Windows key message!\n");
386 return;
387 }
388
389 Mesg.hwnd = InputWindowStation->ShellWindow;
390 Mesg.message = WM_SYSCOMMAND;
391 Mesg.wParam = SC_TASKLIST;
392 Mesg.lParam = 0;
393
394 /* The QS_HOTKEY is just a guess */
395 MsqPostMessage(Window->MessageQueue, &Mesg, FALSE, QS_HOTKEY);
396 }
397
398 STATIC VOID STDCALL
399 co_IntKeyboardSendAltKeyMsg()
400 {
401 co_MsqPostKeyboardMessage(WM_SYSCOMMAND,SC_KEYMENU,0);
402 }
403
404 STATIC VOID STDCALL
405 KeyboardThreadMain(PVOID StartContext)
406 {
407 UNICODE_STRING KeyboardDeviceName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardClass0");
408 OBJECT_ATTRIBUTES KeyboardObjectAttributes;
409 IO_STATUS_BLOCK Iosb;
410 NTSTATUS Status;
411 MSG msg;
412 PUSER_MESSAGE_QUEUE FocusQueue;
413 struct _ETHREAD *FocusThread;
414 extern NTSTATUS Win32kInitWin32Thread(PETHREAD Thread);
415
416 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans = NULL;
417 UINT ModifierState = 0;
418 USHORT LastMakeCode = 0;
419 USHORT LastFlags = 0;
420 UINT RepeatCount = 0;
421
422 InitializeObjectAttributes(&KeyboardObjectAttributes,
423 &KeyboardDeviceName,
424 0,
425 NULL,
426 NULL);
427 do
428 {
429 LARGE_INTEGER DueTime;
430 KEVENT Event;
431 DueTime.QuadPart = (LONGLONG)(-10000000);
432 KeInitializeEvent(&Event, NotificationEvent, FALSE);
433 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime);
434 Status = NtOpenFile(&KeyboardDeviceHandle,
435 FILE_ALL_ACCESS,
436 &KeyboardObjectAttributes,
437 &Iosb,
438 0,
439 FILE_SYNCHRONOUS_IO_ALERT);
440 } while (!NT_SUCCESS(Status));
441
442 /* Not sure if converting this thread to a win32 thread is such
443 a great idea. Since we're posting keyboard messages to the focus
444 window message queue, we'll be (indirectly) doing sendmessage
445 stuff from this thread (for WH_KEYBOARD_LL processing), which
446 means we need our own message queue. If keyboard messages were
447 instead queued to the system message queue, the thread removing
448 the message from the system message queue would be responsible
449 for WH_KEYBOARD_LL processing and we wouldn't need this thread
450 to be a win32 thread. */
451 Status = Win32kInitWin32Thread(PsGetCurrentThread());
452 if (!NT_SUCCESS(Status))
453 {
454 DPRINT1("Win32K: Failed making keyboard thread a win32 thread.\n");
455 return; //(Status);
456 }
457
458 IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle,
459 &IndicatorTrans);
460
461 for (;;)
462 {
463 /*
464 * Wait to start input.
465 */
466 DPRINT( "Keyboard Input Thread Waiting for start event\n" );
467 Status = KeWaitForSingleObject(&InputThreadsStart,
468 0,
469 KernelMode,
470 TRUE,
471 NULL);
472 DPRINT( "Keyboard Input Thread Starting...\n" );
473
474 /*
475 * Receive and process keyboard input.
476 */
477 while (InputThreadsRunning)
478 {
479 BOOLEAN NumKeys = 1;
480 KEYBOARD_INPUT_DATA KeyInput;
481 KEYBOARD_INPUT_DATA NextKeyInput;
482 LPARAM lParam = 0;
483 UINT fsModifiers, fsNextModifiers;
484 struct _ETHREAD *Thread;
485 HWND hWnd;
486 int id;
487
488 DPRINT("KeyInput @ %08x\n", &KeyInput);
489
490 Status = NtReadFile (KeyboardDeviceHandle,
491 NULL,
492 NULL,
493 NULL,
494 &Iosb,
495 &KeyInput,
496 sizeof(KEYBOARD_INPUT_DATA),
497 NULL,
498 NULL);
499
500 if(Status == STATUS_ALERTED && !InputThreadsRunning)
501 {
502 break;
503 }
504 if(Status == STATUS_PENDING)
505 {
506 NtWaitForSingleObject(KeyboardDeviceHandle, FALSE, NULL);
507 Status = Iosb.Status;
508 }
509 if(!NT_SUCCESS(Status))
510 {
511 DPRINT1("Win32K: Failed to read from mouse.\n");
512 return; //(Status);
513 }
514
515 DPRINT("KeyRaw: %s %04x\n",
516 (KeyInput.Flags & KEY_BREAK) ? "up" : "down",
517 KeyInput.MakeCode );
518
519 if (Status == STATUS_ALERTED && !InputThreadsRunning)
520 break;
521
522 if (!NT_SUCCESS(Status))
523 {
524 DPRINT1("Win32K: Failed to read from keyboard.\n");
525 return; //(Status);
526 }
527
528 /* Update modifier state */
529 fsModifiers = IntKeyboardGetModifiers(&KeyInput);
530
531 if (fsModifiers)
532 {
533 if (KeyInput.Flags & KEY_BREAK)
534 {
535 ModifierState &= ~fsModifiers;
536 }
537 else
538 {
539 ModifierState |= fsModifiers;
540
541 if (ModifierState == fsModifiers &&
542 (fsModifiers == MOD_ALT || fsModifiers == MOD_WIN))
543 {
544 /* First send out special notifications
545 * (For alt, the message that turns on accelerator
546 * display, not sure what for win. Both TODO though.)
547 */
548
549 /* Read the next key before sending this one */
550 do
551 {
552 Status = NtReadFile (KeyboardDeviceHandle,
553 NULL,
554 NULL,
555 NULL,
556 &Iosb,
557 &NextKeyInput,
558 sizeof(KEYBOARD_INPUT_DATA),
559 NULL,
560 NULL);
561 DPRINT("KeyRaw: %s %04x\n",
562 (NextKeyInput.Flags & KEY_BREAK) ? "up":"down",
563 NextKeyInput.MakeCode );
564
565 if (Status == STATUS_ALERTED && !InputThreadsRunning)
566 goto KeyboardEscape;
567
568 }
569 while ((!(NextKeyInput.Flags & KEY_BREAK)) &&
570 NextKeyInput.MakeCode == KeyInput.MakeCode);
571 /* ^ Ignore repeats, they'll be KEY_MAKE and the same
572 * code. I'm not caring about the counting, not sure
573 * if that matters. I think not.
574 */
575
576 /* If the ModifierState is now empty again, send a
577 * special notification and eat both keypresses
578 */
579
580 fsNextModifiers = IntKeyboardGetModifiers(&NextKeyInput);
581
582 if (fsNextModifiers)
583 ModifierState ^= fsNextModifiers;
584
585 if (ModifierState == 0)
586 {
587 if (fsModifiers == MOD_WIN)
588 IntKeyboardSendWinKeyMsg();
589 else if (fsModifiers == MOD_ALT)
590 co_IntKeyboardSendAltKeyMsg();
591 continue;
592 }
593
594 NumKeys = 2;
595 }
596 }
597 }
598
599 for (;NumKeys;memcpy(&KeyInput, &NextKeyInput, sizeof(KeyInput)),
600 NumKeys--)
601 {
602 lParam = 0;
603
604 IntKeyboardUpdateLeds(KeyboardDeviceHandle,
605 &KeyInput,
606 IndicatorTrans);
607
608 /* While we are working, we set up lParam. The format is:
609 * 0-15: The number of times this key has autorepeated
610 * 16-23: The keyboard scancode
611 * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
612 * Note that E1 is only used for PAUSE (E1-1D-45) and
613 * E0-45 happens not to be anything.
614 * 29: Alt is pressed ('Context code')
615 * 30: Previous state, if the key was down before this message
616 * This is a cheap way to ignore autorepeat keys
617 * 31: 1 if the key is being pressed
618 */
619
620 /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
621 * and it's the same key as the last one, increase the repeat
622 * count.
623 */
624
625 if (!(KeyInput.Flags & KEY_BREAK))
626 {
627 if (((KeyInput.Flags & (KEY_E0 | KEY_E1)) == LastFlags) &&
628 (KeyInput.MakeCode == LastMakeCode))
629 {
630 RepeatCount++;
631 lParam |= (1 << 30);
632 }
633 else
634 {
635 RepeatCount = 0;
636 LastFlags = KeyInput.Flags & (KEY_E0 | KEY_E1);
637 LastMakeCode = KeyInput.MakeCode;
638 }
639 }
640 else
641 {
642 LastFlags = 0;
643 LastMakeCode = 0; /* Should never match */
644 lParam |= (1 << 30) | (1 << 31);
645 }
646
647 lParam |= RepeatCount;
648
649 lParam |= (KeyInput.MakeCode & 0xff) << 16;
650
651 if (KeyInput.Flags & KEY_E0)
652 lParam |= (1 << 24);
653
654 if (ModifierState & MOD_ALT)
655 {
656 lParam |= (1 << 29);
657
658 if (!(KeyInput.Flags & KEY_BREAK))
659 msg.message = WM_SYSKEYDOWN;
660 else
661 msg.message = WM_SYSKEYUP;
662 }
663 else
664 {
665 if (!(KeyInput.Flags & KEY_BREAK))
666 msg.message = WM_KEYDOWN;
667 else
668 msg.message = WM_KEYUP;
669 }
670
671 /* Find the target thread whose locale is in effect */
672 if (!IntGetScreenDC())
673 FocusQueue = W32kGetPrimitiveMessageQueue();
674 else
675 FocusQueue = IntGetFocusMessageQueue();
676
677 /* This might cause us to lose hot keys, which are important
678 * (ctrl-alt-del secure attention sequence). Not sure if it
679 * can happen though.
680 */
681 if (!FocusQueue)
682 continue;
683
684 msg.lParam = lParam;
685 msg.hwnd = FocusQueue->FocusWindow;
686
687 FocusThread = FocusQueue->Thread;
688
689 if (!(FocusThread && FocusThread->Tcb.Win32Thread &&
690 ((PW32THREAD)FocusThread->Tcb.Win32Thread)->KeyboardLayout))
691 continue;
692
693 /* This function uses lParam to fill wParam according to the
694 * keyboard layout in use.
695 */
696 W32kKeyProcessMessage(&msg,
697 ((PW32THREAD)FocusThread->Tcb.Win32Thread)->KeyboardLayout,
698 KeyInput.Flags & KEY_E0 ? 0xE0 :
699 (KeyInput.Flags & KEY_E1 ? 0xE1 : 0));
700
701 if (GetHotKey(ModifierState,
702 msg.wParam,
703 &Thread,
704 &hWnd,
705 &id))
706 {
707 if (!(KeyInput.Flags & KEY_BREAK))
708 {
709 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd, id);
710 MsqPostHotKeyMessage (Thread,
711 hWnd,
712 (WPARAM)id,
713 MAKELPARAM((WORD)ModifierState,
714 (WORD)msg.wParam));
715 }
716 continue; /* Eat key up motion too */
717 }
718
719 /*
720 * Post a keyboard message.
721 */
722 co_MsqPostKeyboardMessage(msg.message,msg.wParam,msg.lParam);
723 }
724 }
725
726 KeyboardEscape:
727 DPRINT( "KeyboardInput Thread Stopped...\n" );
728 }
729 }
730
731
732 NTSTATUS FASTCALL
733 UserAcquireOrReleaseInputOwnership(BOOLEAN Release)
734 {
735 if (Release && InputThreadsRunning && !pmPrimitiveMessageQueue)
736 {
737 DPRINT( "Releasing input: PM = %08x\n", pmPrimitiveMessageQueue );
738 KeClearEvent(&InputThreadsStart);
739 InputThreadsRunning = FALSE;
740
741 NtAlertThread(KeyboardThreadHandle);
742 NtAlertThread(MouseThreadHandle);
743 }
744 else if (!Release && !InputThreadsRunning)
745 {
746 InputThreadsRunning = TRUE;
747 KeSetEvent(&InputThreadsStart, IO_NO_INCREMENT, FALSE);
748 }
749
750 return(STATUS_SUCCESS);
751 }
752
753
754 NTSTATUS STDCALL
755 NtUserAcquireOrReleaseInputOwnership(BOOLEAN Release)
756 {
757 DECLARE_RETURN(NTSTATUS);
758
759 DPRINT("Enter NtUserAcquireOrReleaseInputOwnership\n");
760 UserEnterExclusive();
761
762 RETURN(UserAcquireOrReleaseInputOwnership(Release));
763
764 CLEANUP:
765 DPRINT("Leave NtUserAcquireOrReleaseInputOwnership, ret=%i\n",_ret_);
766 UserLeave();
767 END_CLEANUP;
768 }
769
770
771 NTSTATUS FASTCALL
772 InitInputImpl(VOID)
773 {
774 NTSTATUS Status;
775
776 KeInitializeEvent(&InputThreadsStart, NotificationEvent, FALSE);
777
778 Status = PsCreateSystemThread(&KeyboardThreadHandle,
779 THREAD_ALL_ACCESS,
780 NULL,
781 NULL,
782 &KeyboardThreadId,
783 KeyboardThreadMain,
784 NULL);
785 if (!NT_SUCCESS(Status))
786 {
787 DPRINT1("Win32K: Failed to create keyboard thread.\n");
788 }
789
790 /* Initialize the default keyboard layout */
791 (VOID)W32kGetDefaultKeyLayout();
792
793
794 Status = PsCreateSystemThread(&MouseThreadHandle,
795 THREAD_ALL_ACCESS,
796 NULL,
797 NULL,
798 &MouseThreadId,
799 MouseThreadMain,
800 NULL);
801 if (!NT_SUCCESS(Status))
802 {
803 DPRINT1("Win32K: Failed to create mouse thread.\n");
804 }
805
806 return STATUS_SUCCESS;
807 }
808
809 NTSTATUS FASTCALL
810 CleanupInputImp(VOID)
811 {
812 return(STATUS_SUCCESS);
813 }
814
815 BOOL
816 STDCALL
817 NtUserDragDetect(
818 HWND hWnd,
819 LONG x,
820 LONG y)
821 {
822 UNIMPLEMENTED
823 return 0;
824 }
825
826 BOOL FASTCALL
827 IntBlockInput(PW32THREAD W32Thread, BOOL BlockIt)
828 {
829 PW32THREAD OldBlock;
830 ASSERT(W32Thread);
831
832 if(!W32Thread->Desktop || (W32Thread->IsExiting && BlockIt))
833 {
834 /*
835 * fail blocking if exiting the thread
836 */
837
838 return FALSE;
839 }
840
841 /*
842 * FIXME - check access rights of the window station
843 * e.g. services running in the service window station cannot block input
844 */
845 if(!ThreadHasInputAccess(W32Thread) ||
846 !IntIsActiveDesktop(W32Thread->Desktop))
847 {
848 SetLastWin32Error(ERROR_ACCESS_DENIED);
849 return FALSE;
850 }
851
852 ASSERT(W32Thread->Desktop);
853 OldBlock = W32Thread->Desktop->BlockInputThread;
854 if(OldBlock)
855 {
856 if(OldBlock != W32Thread)
857 {
858 SetLastWin32Error(ERROR_ACCESS_DENIED);
859 return FALSE;
860 }
861 W32Thread->Desktop->BlockInputThread = (BlockIt ? W32Thread : NULL);
862 return OldBlock == NULL;
863 }
864
865 W32Thread->Desktop->BlockInputThread = (BlockIt ? W32Thread : NULL);
866 return OldBlock == NULL;
867 }
868
869 BOOL
870 STDCALL
871 NtUserBlockInput(
872 BOOL BlockIt)
873 {
874 DECLARE_RETURN(BOOLEAN);
875
876 DPRINT("Enter NtUserBlockInput\n");
877 UserEnterExclusive();
878
879 RETURN( IntBlockInput(PsGetWin32Thread(), BlockIt));
880
881 CLEANUP:
882 DPRINT("Leave NtUserBlockInput, ret=%i\n",_ret_);
883 UserLeave();
884 END_CLEANUP;
885 }
886
887 BOOL FASTCALL
888 IntSwapMouseButton(PWINSTATION_OBJECT WinStaObject, BOOL Swap)
889 {
890 PSYSTEM_CURSORINFO CurInfo;
891 BOOL res;
892
893 CurInfo = IntGetSysCursorInfo(WinStaObject);
894 res = CurInfo->SwapButtons;
895 CurInfo->SwapButtons = Swap;
896 return res;
897 }
898
899 BOOL FASTCALL
900 IntMouseInput(MOUSEINPUT *mi)
901 {
902 const UINT SwapBtnMsg[2][2] =
903 {
904 {
905 WM_LBUTTONDOWN, WM_RBUTTONDOWN
906 },
907 {WM_LBUTTONUP, WM_RBUTTONUP}
908 };
909 const WPARAM SwapBtn[2] =
910 {
911 MK_LBUTTON, MK_RBUTTON
912 };
913 POINT MousePos, OrgPos;
914 PSYSTEM_CURSORINFO CurInfo;
915 PWINSTATION_OBJECT WinSta;
916 BOOL DoMove, SwapButtons;
917 MSG Msg;
918 HBITMAP hBitmap;
919 BITMAPOBJ *BitmapObj;
920 SURFOBJ *SurfObj;
921 PDC dc;
922 PWINDOW_OBJECT DesktopWindow;
923
924 #if 1
925
926 HDC hDC;
927
928 /* FIXME - get the screen dc from the window station or desktop */
929 if(!(hDC = IntGetScreenDC()))
930 {
931 return FALSE;
932 }
933 #endif
934
935 ASSERT(mi);
936 #if 0
937
938 WinSta = PsGetWin32Process()->WindowStation;
939 #else
940 /* FIXME - ugly hack but as long as we're using this dumb callback from the
941 mouse class driver, we can't access the window station from the calling
942 process */
943 WinSta = InputWindowStation;
944 #endif
945
946 ASSERT(WinSta);
947
948 CurInfo = IntGetSysCursorInfo(WinSta);
949
950 if(!mi->time)
951 {
952 LARGE_INTEGER LargeTickCount;
953 KeQueryTickCount(&LargeTickCount);
954 mi->time = LargeTickCount.u.LowPart;
955 }
956
957 SwapButtons = CurInfo->SwapButtons;
958 DoMove = FALSE;
959
960 IntGetCursorLocation(WinSta, &MousePos);
961 OrgPos.x = MousePos.x;
962 OrgPos.y = MousePos.y;
963
964 if(mi->dwFlags & MOUSEEVENTF_MOVE)
965 {
966 if(mi->dwFlags & MOUSEEVENTF_ABSOLUTE)
967 {
968 MousePos.x = mi->dx;
969 MousePos.y = mi->dy;
970 }
971 else
972 {
973 MousePos.x += mi->dx;
974 MousePos.y += mi->dy;
975 }
976
977 DesktopWindow = IntGetWindowObject(WinSta->ActiveDesktop->DesktopWindow);
978
979 if (DesktopWindow)
980 {
981 if(MousePos.x >= DesktopWindow->ClientRect.right)
982 MousePos.x = DesktopWindow->ClientRect.right - 1;
983 if(MousePos.y >= DesktopWindow->ClientRect.bottom)
984 MousePos.y = DesktopWindow->ClientRect.bottom - 1;
985 ObmDereferenceObject(DesktopWindow);
986 }
987
988 if(MousePos.x < 0)
989 MousePos.x = 0;
990 if(MousePos.y < 0)
991 MousePos.y = 0;
992
993 if(CurInfo->CursorClipInfo.IsClipped)
994 {
995 /* The mouse cursor needs to be clipped */
996
997 if(MousePos.x >= (LONG)CurInfo->CursorClipInfo.Right)
998 MousePos.x = (LONG)CurInfo->CursorClipInfo.Right;
999 if(MousePos.x < (LONG)CurInfo->CursorClipInfo.Left)
1000 MousePos.x = (LONG)CurInfo->CursorClipInfo.Left;
1001 if(MousePos.y >= (LONG)CurInfo->CursorClipInfo.Bottom)
1002 MousePos.y = (LONG)CurInfo->CursorClipInfo.Bottom;
1003 if(MousePos.y < (LONG)CurInfo->CursorClipInfo.Top)
1004 MousePos.y = (LONG)CurInfo->CursorClipInfo.Top;
1005 }
1006
1007 DoMove = (MousePos.x != OrgPos.x || MousePos.y != OrgPos.y);
1008 }
1009
1010 if (DoMove)
1011 {
1012 dc = DC_LockDc(hDC);
1013 if (dc)
1014 {
1015 hBitmap = dc->w.hBitmap;
1016 DC_UnlockDc(dc);
1017
1018 BitmapObj = BITMAPOBJ_LockBitmap(hBitmap);
1019 if (BitmapObj)
1020 {
1021 SurfObj = &BitmapObj->SurfObj;
1022
1023 IntEngMovePointer(SurfObj, MousePos.x, MousePos.y, &(GDIDEV(SurfObj)->Pointer.Exclude));
1024 /* Only now, update the info in the GDIDEVICE, so EngMovePointer can
1025 * use the old values to move the pointer image */
1026 GDIDEV(SurfObj)->Pointer.Pos.x = MousePos.x;
1027 GDIDEV(SurfObj)->Pointer.Pos.y = MousePos.y;
1028
1029 BITMAPOBJ_UnlockBitmap(BitmapObj);
1030 }
1031 }
1032 }
1033
1034 /*
1035 * Insert the messages into the system queue
1036 */
1037
1038 Msg.wParam = CurInfo->ButtonsDown;
1039 Msg.lParam = MAKELPARAM(MousePos.x, MousePos.y);
1040 Msg.pt = MousePos;
1041 if(DoMove)
1042 {
1043 Msg.message = WM_MOUSEMOVE;
1044 MsqInsertSystemMessage(&Msg);
1045 }
1046
1047 Msg.message = 0;
1048 if(mi->dwFlags & MOUSEEVENTF_LEFTDOWN)
1049 {
1050 gQueueKeyStateTable[VK_LBUTTON] |= 0xc0;
1051 Msg.message = SwapBtnMsg[0][SwapButtons];
1052 CurInfo->ButtonsDown |= SwapBtn[SwapButtons];
1053 MsqInsertSystemMessage(&Msg);
1054 }
1055 else if(mi->dwFlags & MOUSEEVENTF_LEFTUP)
1056 {
1057 gQueueKeyStateTable[VK_LBUTTON] &= ~0x80;
1058 Msg.message = SwapBtnMsg[1][SwapButtons];
1059 CurInfo->ButtonsDown &= ~SwapBtn[SwapButtons];
1060 MsqInsertSystemMessage(&Msg);
1061 }
1062 if(mi->dwFlags & MOUSEEVENTF_MIDDLEDOWN)
1063 {
1064 gQueueKeyStateTable[VK_MBUTTON] |= 0xc0;
1065 Msg.message = WM_MBUTTONDOWN;
1066 CurInfo->ButtonsDown |= MK_MBUTTON;
1067 MsqInsertSystemMessage(&Msg);
1068 }
1069 else if(mi->dwFlags & MOUSEEVENTF_MIDDLEUP)
1070 {
1071 gQueueKeyStateTable[VK_MBUTTON] &= ~0x80;
1072 Msg.message = WM_MBUTTONUP;
1073 CurInfo->ButtonsDown &= ~MK_MBUTTON;
1074 MsqInsertSystemMessage(&Msg);
1075 }
1076 if(mi->dwFlags & MOUSEEVENTF_RIGHTDOWN)
1077 {
1078 gQueueKeyStateTable[VK_RBUTTON] |= 0xc0;
1079 Msg.message = SwapBtnMsg[0][!SwapButtons];
1080 CurInfo->ButtonsDown |= SwapBtn[!SwapButtons];
1081 MsqInsertSystemMessage(&Msg);
1082 }
1083 else if(mi->dwFlags & MOUSEEVENTF_RIGHTUP)
1084 {
1085 gQueueKeyStateTable[VK_RBUTTON] &= ~0x80;
1086 Msg.message = SwapBtnMsg[1][!SwapButtons];
1087 CurInfo->ButtonsDown &= ~SwapBtn[!SwapButtons];
1088 MsqInsertSystemMessage(&Msg);
1089 }
1090
1091 if((mi->dwFlags & (MOUSEEVENTF_XDOWN | MOUSEEVENTF_XUP)) &&
1092 (mi->dwFlags & MOUSEEVENTF_WHEEL))
1093 {
1094 /* fail because both types of events use the mouseData field */
1095 return FALSE;
1096 }
1097
1098 if(mi->dwFlags & MOUSEEVENTF_XDOWN)
1099 {
1100 Msg.message = WM_XBUTTONDOWN;
1101 if(mi->mouseData & XBUTTON1)
1102 {
1103 gQueueKeyStateTable[VK_XBUTTON1] |= 0xc0;
1104 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
1105 CurInfo->ButtonsDown |= XBUTTON1;
1106 MsqInsertSystemMessage(&Msg);
1107 }
1108 if(mi->mouseData & XBUTTON2)
1109 {
1110 gQueueKeyStateTable[VK_XBUTTON2] |= 0xc0;
1111 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
1112 CurInfo->ButtonsDown |= XBUTTON2;
1113 MsqInsertSystemMessage(&Msg);
1114 }
1115 }
1116 else if(mi->dwFlags & MOUSEEVENTF_XUP)
1117 {
1118 Msg.message = WM_XBUTTONUP;
1119 if(mi->mouseData & XBUTTON1)
1120 {
1121 gQueueKeyStateTable[VK_XBUTTON1] &= ~0x80;
1122 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
1123 CurInfo->ButtonsDown &= ~XBUTTON1;
1124 MsqInsertSystemMessage(&Msg);
1125 }
1126 if(mi->mouseData & XBUTTON2)
1127 {
1128 gQueueKeyStateTable[VK_XBUTTON2] &= ~0x80;
1129 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
1130 CurInfo->ButtonsDown &= ~XBUTTON2;
1131 MsqInsertSystemMessage(&Msg);
1132 }
1133 }
1134 if(mi->dwFlags & MOUSEEVENTF_WHEEL)
1135 {
1136 Msg.message = WM_MOUSEWHEEL;
1137 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, mi->mouseData);
1138 MsqInsertSystemMessage(&Msg);
1139 }
1140
1141 return TRUE;
1142 }
1143
1144 BOOL FASTCALL
1145 IntKeyboardInput(KEYBDINPUT *ki)
1146 {
1147 return FALSE;
1148 }
1149
1150 UINT
1151 STDCALL
1152 NtUserSendInput(
1153 UINT nInputs,
1154 LPINPUT pInput,
1155 INT cbSize)
1156 {
1157 PW32THREAD W32Thread;
1158 UINT cnt;
1159 DECLARE_RETURN(UINT);
1160
1161 DPRINT("Enter NtUserSendInput\n");
1162 UserEnterExclusive();
1163
1164 W32Thread = PsGetWin32Thread();
1165 ASSERT(W32Thread);
1166
1167 if(!W32Thread->Desktop)
1168 {
1169 RETURN( 0);
1170 }
1171
1172 if(!nInputs || !pInput || (cbSize != sizeof(INPUT)))
1173 {
1174 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1175 RETURN( 0);
1176 }
1177
1178 /*
1179 * FIXME - check access rights of the window station
1180 * e.g. services running in the service window station cannot block input
1181 */
1182 if(!ThreadHasInputAccess(W32Thread) ||
1183 !IntIsActiveDesktop(W32Thread->Desktop))
1184 {
1185 SetLastWin32Error(ERROR_ACCESS_DENIED);
1186 RETURN( 0);
1187 }
1188
1189 cnt = 0;
1190 while(nInputs--)
1191 {
1192 INPUT SafeInput;
1193 NTSTATUS Status;
1194
1195 Status = MmCopyFromCaller(&SafeInput, pInput++, sizeof(INPUT));
1196 if(!NT_SUCCESS(Status))
1197 {
1198 SetLastNtError(Status);
1199 RETURN( cnt);
1200 }
1201
1202 switch(SafeInput.type)
1203 {
1204 case INPUT_MOUSE:
1205 if(IntMouseInput(&SafeInput.mi))
1206 {
1207 cnt++;
1208 }
1209 break;
1210 case INPUT_KEYBOARD:
1211 if(IntKeyboardInput(&SafeInput.ki))
1212 {
1213 cnt++;
1214 }
1215 break;
1216 case INPUT_HARDWARE:
1217 break;
1218 #ifndef NDEBUG
1219
1220 default:
1221 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput.type);
1222 break;
1223 #endif
1224
1225 }
1226 }
1227
1228 RETURN( cnt);
1229
1230 CLEANUP:
1231 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_);
1232 UserLeave();
1233 END_CLEANUP;
1234 }
1235
1236 /* EOF */