Merge 13159:13510 from trunk
[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 <rosrtl/string.h>
34
35 /* GLOBALS *******************************************************************/
36
37 static HANDLE MouseDeviceHandle;
38 static HANDLE MouseThreadHandle;
39 static CLIENT_ID MouseThreadId;
40 static HANDLE KeyboardThreadHandle;
41 static CLIENT_ID KeyboardThreadId;
42 static HANDLE KeyboardDeviceHandle;
43 static KEVENT InputThreadsStart;
44 static BOOLEAN InputThreadsRunning = FALSE;
45 PUSER_MESSAGE_QUEUE pmPrimitiveMessageQueue = 0;
46
47 /* FUNCTIONS *****************************************************************/
48
49 #define ClearMouseInput(mi) \
50 mi.dx = 0; \
51 mi.dy = 0; \
52 mi.mouseData = 0; \
53 mi.dwFlags = 0;
54
55 #define SendMouseEvent(mi) \
56 if(mi.dx != 0 || mi.dy != 0) \
57 mi.dwFlags |= MOUSEEVENTF_MOVE; \
58 if(mi.dwFlags) \
59 IntMouseInput(&mi); \
60 ClearMouseInput(mi);
61
62 VOID FASTCALL
63 ProcessMouseInputData(PMOUSE_INPUT_DATA Data, ULONG InputCount)
64 {
65 PMOUSE_INPUT_DATA mid;
66 MOUSEINPUT mi;
67 ULONG i;
68
69 ClearMouseInput(mi);
70 mi.time = 0;
71 mi.dwExtraInfo = 0;
72 for(i = 0; i < InputCount; i++)
73 {
74 mid = (Data + i);
75 mi.dx += mid->LastX;
76 mi.dy += mid->LastY;
77
78 if(mid->ButtonFlags)
79 {
80 if(mid->ButtonFlags & MOUSE_LEFT_BUTTON_DOWN)
81 {
82 mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
83 SendMouseEvent(mi);
84 }
85 if(mid->ButtonFlags & MOUSE_LEFT_BUTTON_UP)
86 {
87 mi.dwFlags |= MOUSEEVENTF_LEFTUP;
88 SendMouseEvent(mi);
89 }
90 if(mid->ButtonFlags & MOUSE_MIDDLE_BUTTON_DOWN)
91 {
92 mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
93 SendMouseEvent(mi);
94 }
95 if(mid->ButtonFlags & MOUSE_MIDDLE_BUTTON_UP)
96 {
97 mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
98 SendMouseEvent(mi);
99 }
100 if(mid->ButtonFlags & MOUSE_RIGHT_BUTTON_DOWN)
101 {
102 mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
103 SendMouseEvent(mi);
104 }
105 if(mid->ButtonFlags & MOUSE_RIGHT_BUTTON_UP)
106 {
107 mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
108 SendMouseEvent(mi);
109 }
110 if(mid->ButtonFlags & MOUSE_BUTTON_4_DOWN)
111 {
112 mi.mouseData |= XBUTTON1;
113 mi.dwFlags |= MOUSEEVENTF_XDOWN;
114 SendMouseEvent(mi);
115 }
116 if(mid->ButtonFlags & MOUSE_BUTTON_4_UP)
117 {
118 mi.mouseData |= XBUTTON1;
119 mi.dwFlags |= MOUSEEVENTF_XUP;
120 SendMouseEvent(mi);
121 }
122 if(mid->ButtonFlags & MOUSE_BUTTON_5_DOWN)
123 {
124 mi.mouseData |= XBUTTON2;
125 mi.dwFlags |= MOUSEEVENTF_XDOWN;
126 SendMouseEvent(mi);
127 }
128 if(mid->ButtonFlags & MOUSE_BUTTON_5_UP)
129 {
130 mi.mouseData |= XBUTTON2;
131 mi.dwFlags |= MOUSEEVENTF_XUP;
132 SendMouseEvent(mi);
133 }
134 if(mid->ButtonFlags & MOUSE_WHEEL)
135 {
136 mi.mouseData = mid->ButtonData;
137 mi.dwFlags |= MOUSEEVENTF_WHEEL;
138 SendMouseEvent(mi);
139 }
140 }
141 }
142
143 SendMouseEvent(mi);
144 }
145
146 VOID STDCALL
147 MouseThreadMain(PVOID StartContext)
148 {
149 UNICODE_STRING MouseDeviceName;
150 OBJECT_ATTRIBUTES MouseObjectAttributes;
151 IO_STATUS_BLOCK Iosb;
152 NTSTATUS Status;
153
154 RtlRosInitUnicodeStringFromLiteral(&MouseDeviceName, L"\\??\\Mouse"); /* FIXME - does win use the same? */
155 InitializeObjectAttributes(&MouseObjectAttributes,
156 &MouseDeviceName,
157 0,
158 NULL,
159 NULL);
160 Status = NtOpenFile(&MouseDeviceHandle,
161 FILE_ALL_ACCESS,
162 &MouseObjectAttributes,
163 &Iosb,
164 0,
165 FILE_SYNCHRONOUS_IO_ALERT);
166 if(!NT_SUCCESS(Status))
167 {
168 DPRINT1("Win32K: Failed to open mouse.\n");
169 return; //(Status);
170 }
171
172 for(;;)
173 {
174 /*
175 * Wait to start input.
176 */
177 DPRINT("Mouse Input Thread Waiting for start event\n");
178 Status = KeWaitForSingleObject(&InputThreadsStart,
179 0,
180 KernelMode,
181 TRUE,
182 NULL);
183 DPRINT("Mouse Input Thread Starting...\n");
184
185 /*
186 * Receive and process keyboard input.
187 */
188 while(InputThreadsRunning)
189 {
190 MOUSE_INPUT_DATA MouseInput;
191 Status = NtReadFile(MouseDeviceHandle,
192 NULL,
193 NULL,
194 NULL,
195 &Iosb,
196 &MouseInput,
197 sizeof(MOUSE_INPUT_DATA),
198 NULL,
199 NULL);
200 if(Status == STATUS_ALERTED && !InputThreadsRunning)
201 {
202 break;
203 }
204 if(Status == STATUS_PENDING)
205 {
206 NtWaitForSingleObject(MouseDeviceHandle, FALSE, NULL);
207 Status = Iosb.Status;
208 }
209 if(!NT_SUCCESS(Status))
210 {
211 DPRINT1("Win32K: Failed to read from mouse.\n");
212 return; //(Status);
213 }
214 DPRINT("MouseEvent\n");
215
216 ProcessMouseInputData(&MouseInput, Iosb.Information / sizeof(MOUSE_INPUT_DATA));
217 }
218 DPRINT("Mouse Input Thread Stopped...\n");
219 }
220 }
221
222 STATIC VOID STDCALL
223 KeyboardThreadMain(PVOID StartContext)
224 {
225 UNICODE_STRING KeyboardDeviceName;
226 OBJECT_ATTRIBUTES KeyboardObjectAttributes;
227 IO_STATUS_BLOCK Iosb;
228 NTSTATUS Status;
229 MSG msg;
230 PUSER_MESSAGE_QUEUE FocusQueue;
231 struct _ETHREAD *FocusThread;
232
233 RtlRosInitUnicodeStringFromLiteral(&KeyboardDeviceName, L"\\??\\Keyboard");
234 InitializeObjectAttributes(&KeyboardObjectAttributes,
235 &KeyboardDeviceName,
236 0,
237 NULL,
238 NULL);
239 Status = NtOpenFile(&KeyboardDeviceHandle,
240 FILE_ALL_ACCESS,
241 &KeyboardObjectAttributes,
242 &Iosb,
243 0,
244 FILE_SYNCHRONOUS_IO_ALERT);
245 if (!NT_SUCCESS(Status))
246 {
247 DPRINT1("Win32K: Failed to open keyboard.\n");
248 return; //(Status);
249 }
250
251 for (;;)
252 {
253 /*
254 * Wait to start input.
255 */
256 DPRINT( "Keyboard Input Thread Waiting for start event\n" );
257 Status = KeWaitForSingleObject(&InputThreadsStart,
258 0,
259 KernelMode,
260 TRUE,
261 NULL);
262 DPRINT( "Keyboard Input Thread Starting...\n" );
263
264 /*
265 * Receive and process keyboard input.
266 */
267 while (InputThreadsRunning)
268 {
269 KEY_EVENT_RECORD KeyEvent;
270 LPARAM lParam = 0;
271 UINT fsModifiers;
272 struct _ETHREAD *Thread;
273 HWND hWnd;
274 int id;
275
276 Status = NtReadFile (KeyboardDeviceHandle,
277 NULL,
278 NULL,
279 NULL,
280 &Iosb,
281 &KeyEvent,
282 sizeof(KEY_EVENT_RECORD),
283 NULL,
284 NULL);
285 DPRINT( "KeyRaw: %s %04x\n",
286 KeyEvent.bKeyDown ? "down" : "up",
287 KeyEvent.wVirtualScanCode );
288
289 if (Status == STATUS_ALERTED && !InputThreadsRunning)
290 {
291 break;
292 }
293 if (!NT_SUCCESS(Status))
294 {
295 DPRINT1("Win32K: Failed to read from keyboard.\n");
296 return; //(Status);
297 }
298
299 DPRINT( "Key: %s\n", KeyEvent.bKeyDown ? "down" : "up" );
300
301 fsModifiers = 0;
302 if (KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
303 fsModifiers |= MOD_ALT;
304
305 if (KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
306 fsModifiers |= MOD_CONTROL;
307
308 if (KeyEvent.dwControlKeyState & SHIFT_PRESSED)
309 fsModifiers |= MOD_SHIFT;
310
311 /* FIXME: Support MOD_WIN */
312
313 lParam = KeyEvent.wRepeatCount |
314 ((KeyEvent.wVirtualScanCode << 16) & 0x00FF0000) | 0x40000000;
315
316 /* Bit 24 indicates if this is an extended key */
317 if (KeyEvent.dwControlKeyState & ENHANCED_KEY)
318 {
319 lParam |= (1 << 24);
320 }
321
322 if (fsModifiers & MOD_ALT)
323 {
324 /* Context mode. 1 if ALT if pressed while the key is pressed */
325 lParam |= (1 << 29);
326 }
327
328 if (! KeyEvent.bKeyDown)
329 {
330 /* Transition state. 1 for KEY_UP etc, 0 for KEY_DOWN */
331 lParam |= (1 << 31);
332 }
333
334 if (GetHotKey(InputWindowStation,
335 fsModifiers,
336 KeyEvent.wVirtualKeyCode,
337 &Thread,
338 &hWnd,
339 &id))
340 {
341 if (KeyEvent.bKeyDown)
342 {
343 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd, id);
344 MsqPostHotKeyMessage (Thread,
345 hWnd,
346 (WPARAM)id,
347 MAKELPARAM((WORD)fsModifiers,
348 (WORD)msg.wParam));
349 }
350 continue;
351 }
352
353 /* Find the target thread whose locale is in effect */
354 if (!IntGetScreenDC())
355 {
356 FocusQueue = W32kGetPrimitiveMessageQueue();
357 }
358 else
359 {
360 FocusQueue = IntGetFocusMessageQueue();
361 }
362
363 if (!FocusQueue) continue;
364
365 if(KeyEvent.bKeyDown && (fsModifiers & MOD_ALT))
366 msg.message = WM_SYSKEYDOWN;
367 else if(KeyEvent.bKeyDown)
368 msg.message = WM_KEYDOWN;
369 else if(fsModifiers & MOD_ALT)
370 msg.message = WM_SYSKEYUP;
371 else
372 msg.message = WM_KEYUP;
373
374 msg.wParam = KeyEvent.wVirtualKeyCode;
375 msg.lParam = lParam;
376 msg.hwnd = FocusQueue->FocusWindow;
377
378 FocusThread = FocusQueue->Thread;
379
380 if (FocusThread && FocusThread->Tcb.Win32Thread &&
381 FocusThread->Tcb.Win32Thread->KeyboardLayout)
382 {
383 W32kKeyProcessMessage(&msg,
384 FocusThread->Tcb.Win32Thread->KeyboardLayout);
385 }
386 else
387 continue;
388
389 /*
390 * Post a keyboard message.
391 */
392 MsqPostKeyboardMessage(msg.message,msg.wParam,msg.lParam);
393 }
394 DPRINT( "KeyboardInput Thread Stopped...\n" );
395 }
396 }
397
398
399 NTSTATUS STDCALL
400 NtUserAcquireOrReleaseInputOwnership(BOOLEAN Release)
401 {
402 if (Release && InputThreadsRunning && !pmPrimitiveMessageQueue)
403 {
404 DPRINT( "Releasing input: PM = %08x\n", pmPrimitiveMessageQueue );
405 KeClearEvent(&InputThreadsStart);
406 InputThreadsRunning = FALSE;
407
408 NtAlertThread(KeyboardThreadHandle);
409 }
410 else if (!Release && !InputThreadsRunning)
411 {
412 InputThreadsRunning = TRUE;
413 KeSetEvent(&InputThreadsStart, IO_NO_INCREMENT, FALSE);
414 }
415
416 return(STATUS_SUCCESS);
417 }
418
419 NTSTATUS FASTCALL
420 InitInputImpl(VOID)
421 {
422 NTSTATUS Status;
423
424 KeInitializeEvent(&InputThreadsStart, NotificationEvent, FALSE);
425
426 Status = PsCreateSystemThread(&KeyboardThreadHandle,
427 THREAD_ALL_ACCESS,
428 NULL,
429 NULL,
430 &KeyboardThreadId,
431 KeyboardThreadMain,
432 NULL);
433 if (!NT_SUCCESS(Status))
434 {
435 DPRINT1("Win32K: Failed to create keyboard thread.\n");
436 }
437
438 /* Initialize the default keyboard layout */
439 (VOID)W32kGetDefaultKeyLayout();
440
441
442 Status = PsCreateSystemThread(&MouseThreadHandle,
443 THREAD_ALL_ACCESS,
444 NULL,
445 NULL,
446 &MouseThreadId,
447 MouseThreadMain,
448 NULL);
449 if (!NT_SUCCESS(Status))
450 {
451 DPRINT1("Win32K: Failed to create mouse thread.\n");
452 }
453
454 return STATUS_SUCCESS;
455 }
456
457 NTSTATUS FASTCALL
458 CleanupInputImp(VOID)
459 {
460 return(STATUS_SUCCESS);
461 }
462
463 BOOL
464 STDCALL
465 NtUserDragDetect(
466 HWND hWnd,
467 LONG x,
468 LONG y)
469 {
470 UNIMPLEMENTED
471 return 0;
472 }
473
474 BOOL FASTCALL
475 IntBlockInput(PW32THREAD W32Thread, BOOL BlockIt)
476 {
477 PW32THREAD OldBlock;
478 ASSERT(W32Thread);
479
480 if(!W32Thread->Desktop || (W32Thread->IsExiting && BlockIt))
481 {
482 /*
483 * fail blocking if exiting the thread
484 */
485
486 return FALSE;
487 }
488
489 /*
490 * FIXME - check access rights of the window station
491 * e.g. services running in the service window station cannot block input
492 */
493 if(!ThreadHasInputAccess(W32Thread) ||
494 !IntIsActiveDesktop(W32Thread->Desktop))
495 {
496 SetLastWin32Error(ERROR_ACCESS_DENIED);
497 return FALSE;
498 }
499
500 ASSERT(W32Thread->Desktop);
501 OldBlock = W32Thread->Desktop->BlockInputThread;
502 if(OldBlock)
503 {
504 if(OldBlock != W32Thread)
505 {
506 SetLastWin32Error(ERROR_ACCESS_DENIED);
507 return FALSE;
508 }
509 W32Thread->Desktop->BlockInputThread = (BlockIt ? W32Thread : NULL);
510 return OldBlock == NULL;
511 }
512
513 W32Thread->Desktop->BlockInputThread = (BlockIt ? W32Thread : NULL);
514 return OldBlock == NULL;
515 }
516
517 BOOL
518 STDCALL
519 NtUserBlockInput(
520 BOOL BlockIt)
521 {
522 return IntBlockInput(PsGetWin32Thread(), BlockIt);
523 }
524
525 BOOL FASTCALL
526 IntSwapMouseButton(PWINSTATION_OBJECT WinStaObject, BOOL Swap)
527 {
528 PSYSTEM_CURSORINFO CurInfo;
529 BOOL res;
530
531 CurInfo = IntGetSysCursorInfo(WinStaObject);
532 res = CurInfo->SwapButtons;
533 CurInfo->SwapButtons = Swap;
534 return res;
535 }
536
537 BOOL FASTCALL
538 IntMouseInput(MOUSEINPUT *mi)
539 {
540 const UINT SwapBtnMsg[2][2] = {{WM_LBUTTONDOWN, WM_RBUTTONDOWN},
541 {WM_LBUTTONUP, WM_RBUTTONUP}};
542 const WPARAM SwapBtn[2] = {MK_LBUTTON, MK_RBUTTON};
543 POINT MousePos, OrgPos;
544 PSYSTEM_CURSORINFO CurInfo;
545 PWINSTATION_OBJECT WinSta;
546 BOOL DoMove, SwapButtons;
547 MSG Msg;
548 HBITMAP hBitmap;
549 BITMAPOBJ *BitmapObj;
550 SURFOBJ *SurfObj;
551 PDC dc;
552 PWINDOW_OBJECT DesktopWindow;
553 NTSTATUS Status;
554
555 #if 1
556 HDC hDC;
557
558 /* FIXME - get the screen dc from the window station or desktop */
559 if(!(hDC = IntGetScreenDC()))
560 {
561 return FALSE;
562 }
563 #endif
564
565 ASSERT(mi);
566 #if 0
567 WinSta = PsGetWin32Process()->WindowStation;
568 #else
569 /* FIXME - ugly hack but as long as we're using this dumb callback from the
570 mouse class driver, we can't access the window station from the calling
571 process */
572 WinSta = InputWindowStation;
573 #endif
574 ASSERT(WinSta);
575
576 CurInfo = IntGetSysCursorInfo(WinSta);
577
578 if(!mi->time)
579 {
580 LARGE_INTEGER LargeTickCount;
581 KeQueryTickCount(&LargeTickCount);
582 mi->time = LargeTickCount.u.LowPart;
583 }
584
585 SwapButtons = CurInfo->SwapButtons;
586 DoMove = FALSE;
587
588 ExAcquireFastMutex(&CurInfo->CursorMutex);
589 IntGetCursorLocation(WinSta, &MousePos);
590 OrgPos.x = MousePos.x;
591 OrgPos.y = MousePos.y;
592
593 if(mi->dwFlags & MOUSEEVENTF_MOVE)
594 {
595 if(mi->dwFlags & MOUSEEVENTF_ABSOLUTE)
596 {
597 MousePos.x = mi->dx;
598 MousePos.y = mi->dy;
599 }
600 else
601 {
602 MousePos.x += mi->dx;
603 MousePos.y += mi->dy;
604 }
605
606 Status = ObmReferenceObjectByHandle(WinSta->HandleTable,
607 WinSta->ActiveDesktop->DesktopWindow, otWindow, (PVOID*)&DesktopWindow);
608 if (NT_SUCCESS(Status))
609 {
610 if(MousePos.x >= DesktopWindow->ClientRect.right)
611 MousePos.x = DesktopWindow->ClientRect.right - 1;
612 if(MousePos.y >= DesktopWindow->ClientRect.bottom)
613 MousePos.y = DesktopWindow->ClientRect.bottom - 1;
614 }
615 ObmDereferenceObject(DesktopWindow);
616
617 if(MousePos.x < 0)
618 MousePos.x = 0;
619 if(MousePos.y < 0)
620 MousePos.y = 0;
621
622 if(CurInfo->CursorClipInfo.IsClipped)
623 {
624 /* The mouse cursor needs to be clipped */
625
626 if(MousePos.x >= (LONG)CurInfo->CursorClipInfo.Right)
627 MousePos.x = (LONG)CurInfo->CursorClipInfo.Right;
628 if(MousePos.x < (LONG)CurInfo->CursorClipInfo.Left)
629 MousePos.x = (LONG)CurInfo->CursorClipInfo.Left;
630 if(MousePos.y >= (LONG)CurInfo->CursorClipInfo.Bottom)
631 MousePos.y = (LONG)CurInfo->CursorClipInfo.Bottom;
632 if(MousePos.y < (LONG)CurInfo->CursorClipInfo.Top)
633 MousePos.y = (LONG)CurInfo->CursorClipInfo.Top;
634 }
635
636 DoMove = (MousePos.x != OrgPos.x || MousePos.y != OrgPos.y);
637 }
638
639 ExReleaseFastMutex(&CurInfo->CursorMutex);
640
641 if (DoMove)
642 {
643 dc = DC_LockDc(hDC);
644 if (dc)
645 {
646 hBitmap = dc->w.hBitmap;
647 DC_UnlockDc(hDC);
648
649 BitmapObj = BITMAPOBJ_LockBitmap(hBitmap);
650 if (BitmapObj)
651 {
652 SurfObj = &BitmapObj->SurfObj;
653
654 if (GDIDEV(SurfObj)->Pointer.MovePointer)
655 {
656 GDIDEV(SurfObj)->Pointer.MovePointer(SurfObj, MousePos.x, MousePos.y, &(GDIDEV(SurfObj)->Pointer.Exclude));
657 } else {
658 EngMovePointer(SurfObj, MousePos.x, MousePos.y, &(GDIDEV(SurfObj)->Pointer.Exclude));
659 }
660 /* Only now, update the info in the GDIDEVICE, so EngMovePointer can
661 * use the old values to move the pointer image */
662 GDIDEV(SurfObj)->Pointer.Pos.x = MousePos.x;
663 GDIDEV(SurfObj)->Pointer.Pos.y = MousePos.y;
664
665 BITMAPOBJ_UnlockBitmap(hBitmap);
666 }
667 }
668 }
669
670 /*
671 * Insert the messages into the system queue
672 */
673
674 Msg.wParam = CurInfo->ButtonsDown;
675 Msg.lParam = MAKELPARAM(MousePos.x, MousePos.y);
676 Msg.pt = MousePos;
677 if(DoMove)
678 {
679 Msg.message = WM_MOUSEMOVE;
680 MsqInsertSystemMessage(&Msg);
681 }
682
683 Msg.message = 0;
684 if(mi->dwFlags & MOUSEEVENTF_LEFTDOWN)
685 {
686 Msg.message = SwapBtnMsg[0][SwapButtons];
687 CurInfo->ButtonsDown |= SwapBtn[SwapButtons];
688 MsqInsertSystemMessage(&Msg);
689 }
690 else if(mi->dwFlags & MOUSEEVENTF_LEFTUP)
691 {
692 Msg.message = SwapBtnMsg[1][SwapButtons];
693 CurInfo->ButtonsDown &= ~SwapBtn[SwapButtons];
694 MsqInsertSystemMessage(&Msg);
695 }
696 if(mi->dwFlags & MOUSEEVENTF_MIDDLEDOWN)
697 {
698 Msg.message = WM_MBUTTONDOWN;
699 CurInfo->ButtonsDown |= MK_MBUTTON;
700 MsqInsertSystemMessage(&Msg);
701 }
702 else if(mi->dwFlags & MOUSEEVENTF_MIDDLEUP)
703 {
704 Msg.message = WM_MBUTTONUP;
705 CurInfo->ButtonsDown &= ~MK_MBUTTON;
706 MsqInsertSystemMessage(&Msg);
707 }
708 if(mi->dwFlags & MOUSEEVENTF_RIGHTDOWN)
709 {
710 Msg.message = SwapBtnMsg[0][!SwapButtons];
711 CurInfo->ButtonsDown |= SwapBtn[!SwapButtons];
712 MsqInsertSystemMessage(&Msg);
713 }
714 else if(mi->dwFlags & MOUSEEVENTF_RIGHTUP)
715 {
716 Msg.message = SwapBtnMsg[1][!SwapButtons];
717 CurInfo->ButtonsDown &= ~SwapBtn[!SwapButtons];
718 MsqInsertSystemMessage(&Msg);
719 }
720
721 if((mi->dwFlags & (MOUSEEVENTF_XDOWN | MOUSEEVENTF_XUP)) &&
722 (mi->dwFlags & MOUSEEVENTF_WHEEL))
723 {
724 /* fail because both types of events use the mouseData field */
725 return FALSE;
726 }
727
728 if(mi->dwFlags & MOUSEEVENTF_XDOWN)
729 {
730 Msg.message = WM_XBUTTONDOWN;
731 if(mi->mouseData & XBUTTON1)
732 {
733 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
734 CurInfo->ButtonsDown |= XBUTTON1;
735 MsqInsertSystemMessage(&Msg);
736 }
737 if(mi->mouseData & XBUTTON2)
738 {
739 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
740 CurInfo->ButtonsDown |= XBUTTON2;
741 MsqInsertSystemMessage(&Msg);
742 }
743 }
744 else if(mi->dwFlags & MOUSEEVENTF_XUP)
745 {
746 Msg.message = WM_XBUTTONUP;
747 if(mi->mouseData & XBUTTON1)
748 {
749 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
750 CurInfo->ButtonsDown &= ~XBUTTON1;
751 MsqInsertSystemMessage(&Msg);
752 }
753 if(mi->mouseData & XBUTTON2)
754 {
755 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
756 CurInfo->ButtonsDown &= ~XBUTTON2;
757 MsqInsertSystemMessage(&Msg);
758 }
759 }
760 if(mi->dwFlags & MOUSEEVENTF_WHEEL)
761 {
762 Msg.message = WM_MOUSEWHEEL;
763 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, mi->mouseData);
764 MsqInsertSystemMessage(&Msg);
765 }
766
767 return TRUE;
768 }
769
770 BOOL FASTCALL
771 IntKeyboardInput(KEYBDINPUT *ki)
772 {
773 return FALSE;
774 }
775
776 UINT
777 STDCALL
778 NtUserSendInput(
779 UINT nInputs,
780 LPINPUT pInput,
781 INT cbSize)
782 {
783 PW32THREAD W32Thread;
784 UINT cnt;
785
786 W32Thread = PsGetWin32Thread();
787 ASSERT(W32Thread);
788
789 if(!W32Thread->Desktop)
790 {
791 return 0;
792 }
793
794 if(!nInputs || !pInput || (cbSize != sizeof(INPUT)))
795 {
796 SetLastWin32Error(ERROR_INVALID_PARAMETER);
797 return 0;
798 }
799
800 /*
801 * FIXME - check access rights of the window station
802 * e.g. services running in the service window station cannot block input
803 */
804 if(!ThreadHasInputAccess(W32Thread) ||
805 !IntIsActiveDesktop(W32Thread->Desktop))
806 {
807 SetLastWin32Error(ERROR_ACCESS_DENIED);
808 return 0;
809 }
810
811 cnt = 0;
812 while(nInputs--)
813 {
814 INPUT SafeInput;
815 NTSTATUS Status;
816
817 Status = MmCopyFromCaller(&SafeInput, pInput++, sizeof(INPUT));
818 if(!NT_SUCCESS(Status))
819 {
820 SetLastNtError(Status);
821 return cnt;
822 }
823
824 switch(SafeInput.type)
825 {
826 case INPUT_MOUSE:
827 if(IntMouseInput(&SafeInput.mi))
828 {
829 cnt++;
830 }
831 break;
832 case INPUT_KEYBOARD:
833 if(IntKeyboardInput(&SafeInput.ki))
834 {
835 cnt++;
836 }
837 break;
838 case INPUT_HARDWARE:
839 break;
840 #ifndef NDEBUG
841 default:
842 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput.type);
843 break;
844 #endif
845 }
846 }
847
848 return cnt;
849 }
850
851 /* EOF */