Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

ntinput.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: ntinput.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * This module contains low-level input code specific to the NT 00007 * implementation of Win32 USER, which is mostly the interfaces to the 00008 * keyboard and mouse device drivers. 00009 * 00010 * History: 00011 * 11-26-90 DavidPe Created 00012 \***************************************************************************/ 00013 #include "precomp.h" 00014 #pragma hdrstop 00015 #include <ntddmou.h> 00016 00017 00018 PKWAIT_BLOCK gWaitBlockArray; 00019 00020 KEYBOARD_UNIT_ID_PARAMETER kuid; 00021 MOUSE_UNIT_ID_PARAMETER muid; 00022 00023 #define UPDATE_KBD_TYPEMATIC 1 00024 #define UPDATE_KBD_LEDS 2 00025 00026 void ProcessQueuedMouseEvents(void); 00027 VOID RawInputThread(PVOID pVoid); 00028 LONG DoMouseAccel(LONG delta); 00029 VOID GetMouseCoord(LONG dx, LONG dy, DWORD dwFlags, LONG time, ULONG_PTR ExtraInfo, PPOINT ppt); 00030 VOID xxxMoveEventAbsolute(LONG x, LONG y, ULONG_PTR dwExtraInfo, DWORD time, 00031 BOOL bInjected); 00032 INT idxRemainder, idyRemainder ; 00033 00034 /* 00035 * Mouse/Kbd diagnostics for #136483 etc. Remove when PNP is stable (IanJa) 00036 */ 00037 #ifdef DIAGNOSE_IO 00038 ULONG gMouseProcessMiceInputTime = 0; // tick at start of ProcessMiceInput 00039 ULONG gMouseQueueMouseEventTime = 0; // tick at start of QueueMouseEvent 00040 ULONG gMouseUnqueueMouseEventTime = 0; // tick at start of UnqueueMouseEvent 00041 00042 // Return a value as close as possible to the system's tick count, 00043 // yet guaranteed to be larger than the value returned last time. 00044 // (useful for sequencing events) 00045 // BUG: when NtGetTickCount overflows, the value returned by MonotonicTick 00046 // will not track system tick count well: instead it will increase by one 00047 // each time until it too overflows. (considerd harmless for IO DIAGNOSTICS) 00048 ULONG MonotonicTick() 00049 { 00050 static ULONG lasttick = 0; 00051 ULONG newtick; 00052 00053 newtick = NtGetTickCount(); 00054 if (newtick > lasttick) { 00055 lasttick = newtick; // use the new tick since it is larger 00056 } else { 00057 lasttick++; // artificially bump the tick up one. 00058 } 00059 return lasttick; 00060 } 00061 00062 #endif 00063 00064 /* 00065 * Parameter Constants for xxxButtonEvent() 00066 */ 00067 #define MOUSE_BUTTON_LEFT 0x0001 00068 #define MOUSE_BUTTON_RIGHT 0x0002 00069 #define MOUSE_BUTTON_MIDDLE 0x0004 00070 #define MOUSE_BUTTON_X1 0x0008 00071 #define MOUSE_BUTTON_X2 0x0010 00072 00073 #define ID_INPUT 0 00074 #define ID_MOUSE 1 00075 00076 #define ID_TIMER 2 00077 #define ID_HIDCHANGE 3 00078 #define ID_NUMBER_NON_HYDRA_HANDLES 4 00079 00080 #define ID_SHUTDOWN 4 00081 #define ID_WDTIMER 5 00082 PKTIMER gptmrWD; 00083 00084 PVOID *apObjects; 00085 00086 typedef struct _RIT_INIT { 00087 PTERMINAL pTerm; 00088 PKEVENT pRitReadyEvent; 00089 } RIT_INIT, *PRIT_INIT; 00090 00091 /***************************************************************************\ 00092 * fAbsoluteMouse 00093 * 00094 * Returns TRUE if the mouse event has absolute coordinates (as apposed to the 00095 * standard delta values we get from MS and PS2 mice) 00096 * 00097 * History: 00098 * 23-Jul-1992 JonPa Created. 00099 \***************************************************************************/ 00100 #define fAbsoluteMouse( pmei ) \ 00101 (((pmei)->Flags & MOUSE_MOVE_ABSOLUTE) != 0) 00102 00103 /***************************************************************************\ 00104 * ConvertToMouseDriverFlags 00105 * 00106 * Converts SendInput kind of flags to mouse driver flags as GetMouseCoord 00107 * needs them. 00108 * As mouse inputs are more frequent than send inputs, we penalize the later. 00109 * 00110 * History: 00111 * 17-dec-1997 MCostea Created. 00112 \***************************************************************************/ 00113 #if ((MOUSEEVENTF_ABSOLUTE >> 15) ^ MOUSE_MOVE_ABSOLUTE) || \ 00114 ((MOUSEEVENTF_VIRTUALDESK >> 13) ^ MOUSE_VIRTUAL_DESKTOP) 00115 # error("Bit mapping broken: fix ConvertToMouseDriverFlags") 00116 #endif 00117 00118 #define ConvertToMouseDriverFlags( Flags ) \ 00119 (((Flags) & MOUSEEVENTF_ABSOLUTE) >> 15 | \ 00120 ((Flags) & MOUSEEVENTF_VIRTUALDESK) >> 13) 00121 00122 #define VKTOMODIFIERS(Vk) ((((Vk) >= VK_SHIFT) && ((Vk) <= VK_MENU)) ? \ 00123 (MOD_SHIFT >> ((Vk) - VK_SHIFT)) : \ 00124 0) 00125 #if (VKTOMODIFIERS(VK_SHIFT) != MOD_SHIFT) || \ 00126 (VKTOMODIFIERS(VK_CONTROL) != MOD_CONTROL) || \ 00127 (VKTOMODIFIERS(VK_MENU) != MOD_ALT) 00128 # error("VKTOMODIFIERS broken") 00129 #endif 00130 00131 00132 /***************************************************************************\ 00133 * xxxInitInput 00134 * 00135 * This function is called from CreateTerminalInput() and gets USER setup to 00136 * process keyboard and mouse input. It starts the RIT for that terminal. 00137 * History: 00138 * 11-26-90 DavidPe Created. 00139 \***************************************************************************/ 00140 BOOL xxxInitInput( 00141 PTERMINAL pTerm) 00142 { 00143 NTSTATUS Status; 00144 HANDLE hThreadRawInput; 00145 RIT_INIT initData; 00146 UserAssert(pTerm != NULL); 00147 00148 #ifdef MOUSE_LOCK_CODE 00149 /* 00150 * Lock RIT pages into memory 00151 */ 00152 LockMouseInputCodePages(); 00153 #endif 00154 00155 initData.pTerm = pTerm; 00156 initData.pRitReadyEvent = CreateKernelEvent(SynchronizationEvent, FALSE); 00157 if (initData.pRitReadyEvent == NULL) { 00158 return FALSE; 00159 } 00160 /* 00161 * Create the RIT and let it run. 00162 */ 00163 LeaveCrit(); 00164 Status = CreateSystemThread((PKSTART_ROUTINE)RawInputThread, &initData, 00165 &hThreadRawInput); 00166 if (!NT_SUCCESS(Status)) { 00167 goto Exit; 00168 } 00169 ZwClose(hThreadRawInput); 00170 00171 KeWaitForSingleObject(initData.pRitReadyEvent, WrUserRequest, 00172 KernelMode, FALSE, NULL); 00173 Exit: 00174 FreeKernelEvent(&initData.pRitReadyEvent); 00175 EnterCrit(); 00176 00177 return (gptiRit != NULL); 00178 } 00179 00180 00181 /***************************************************************************\ 00182 * InitScancodeMap 00183 * 00184 * Fetches the scancode map from the registry, allocating space as required. 00185 * 00186 * A scancode map is used to convert unusual OEM scancodes into standard 00187 * "Scan Code Set 1" values. This is to support KB3270 keyboards, but can 00188 * be used for other types too. 00189 * 00190 * History: 00191 * 96-04-18 IanJa Created. 00192 \***************************************************************************/ 00193 PSCANCODEMAP 00194 InitScancodeMap() 00195 { 00196 LPBYTE pb = NULL; 00197 DWORD dwBytes; 00198 00199 /* 00200 * Find the size of the scancode map 00201 */ 00202 dwBytes = FastGetProfileValue(NULL, PMAP_KBDLAYOUT, L"Scancode Map", NULL, NULL, 0); 00203 00204 /* 00205 * Allocate space for the scancode map, and fetch it from the registry 00206 */ 00207 if (dwBytes > sizeof(SCANCODEMAP)) { 00208 if ((pb = UserAllocPoolZInit(dwBytes, TAG_SCANCODEMAP)) != 0) { 00209 dwBytes = FastGetProfileValue(NULL, PMAP_KBDLAYOUT, L"Scancode Map", 00210 NULL, pb, dwBytes); 00211 } 00212 } 00213 00214 #ifdef LATER 00215 /* 00216 * For shadow the WD has it's own keyboard scan code interpreter. 00217 * It needs to know the keyboard type. 00218 * 00219 * The keyboard comments say these are asynchronous commands so only 00220 * use globals. 00221 */ 00222 if (gbRemoteSession && dwBytes) { 00223 00224 ZwDeviceIoControlFile(ghRemoteKeyboardChannel, NULL, NULL, NULL, 00225 &giosbKbdControl, IOCTL_KEYBOARD_ICA_SCANMAP, pb, dwBytes, 00226 NULL, 0); 00227 00228 } 00229 #endif // LATER 00230 00231 return (PSCANCODEMAP)pb; 00232 } 00233 00234 /***************************************************************************\ 00235 * MapScancode 00236 * 00237 * Converts a scancode (and it's prefix, if any) to a different scancode 00238 * and prefix. 00239 * 00240 * Parameters: 00241 * pbScanCode = address of Scancode byte, the scancode may be changed 00242 * pbPrefix = address of Prefix byte, The prefix may be changed 00243 * 00244 * Return value: 00245 * TRUE - mapping was found, scancode was altered. 00246 * FALSE - no mapping found, scancode was not altered. 00247 * 00248 * Note on scancode map table format: 00249 * A table entry DWORD of 0xE0450075 means scancode 0x45, prefix 0xE0 00250 * gets mapped to scancode 0x75, no prefix 00251 * 00252 * History: 00253 * 96-04-18 IanJa Created. 00254 \***************************************************************************/ 00255 BOOL 00256 MapScancode( 00257 PBYTE pbScanCode, 00258 PBYTE pbPrefix 00259 ) 00260 { 00261 DWORD *pdw; 00262 WORD wT = MAKEWORD(*pbScanCode, *pbPrefix); 00263 00264 CheckCritIn(); 00265 UserAssert(gpScancodeMap != NULL); 00266 00267 for (pdw = &(gpScancodeMap->dwMap[0]); *pdw; pdw++) { 00268 if (HIWORD(*pdw) == wT) { 00269 wT = LOWORD(*pdw); 00270 *pbScanCode = LOBYTE(wT); 00271 *pbPrefix = HIBYTE(wT); 00272 return TRUE; 00273 } 00274 } 00275 return FALSE; 00276 } 00277 00278 00279 /***************************************************************************\ 00280 * InitMice 00281 * 00282 * This function initializes the data and settings before we start enumerating 00283 * the mice. 00284 * 00285 * History: 00286 * 11-18-97 IanJa Created. 00287 \***************************************************************************/ 00288 00289 VOID InitMice() 00290 { 00291 CLEAR_ACCF(ACCF_MKVIRTUALMOUSE); 00292 CLEAR_GTERMF(GTERMF_MOUSE); 00293 SYSMET(MOUSEPRESENT) = FALSE; 00294 SYSMET(CMOUSEBUTTONS) = 0; 00295 SYSMET(MOUSEWHEELPRESENT) = FALSE; 00296 } 00297 00298 /***************************************************************************\ 00299 * FreeDeviceInfo 00300 * 00301 * Unlinks a DEVICEINFO struct from the gpDeviceInfoList list and frees the 00302 * allocated memory UNLESS the device is actively being read (GDIF_READING) or 00303 * has a PnP thread waiting for it in RequestDeviceChange() (GDIAF_PNPWAITING) 00304 * If the latter, then wake the PnP thread via pkeHidChangeCompleted so that it 00305 * can free the structure itself. 00306 * 00307 * Returns a pointer to the next DEVICEINFO struct, or NULL if the device was 00308 * not found in the gpDeviceInfoList. 00309 * 00310 * History: 00311 * 11-18-97 IanJa Created. 00312 \***************************************************************************/ 00313 PDEVICEINFO FreeDeviceInfo(PDEVICEINFO pDeviceInfo) 00314 { 00315 PDEVICEINFO *ppDeviceInfo; 00316 00317 CheckDeviceInfoListCritIn(); 00318 00319 TAGMSG1(DBGTAG_PNP, "FreeDeviceInfo(%#p)", pDeviceInfo); 00320 00321 /* 00322 * We cannot free the device since we still have a read pending. 00323 * Mark it GDIAF_FREEME so that it will be freed when the APC is made 00324 * (see InputApc), or when the next read request is about to be issued 00325 * (see StartDeviceRead). 00326 */ 00327 if (pDeviceInfo->bFlags & GDIF_READING) { 00328 #if DIAGNOSE_IO 00329 pDeviceInfo->bFlags |= GDIF_READERMUSTFREE; 00330 #endif 00331 TAGMSG1(DBGTAG_PNP, "** FreeDeviceInfo(%#p) DEFERRED : reader must free", pDeviceInfo); 00332 pDeviceInfo->usActions |= GDIAF_FREEME; 00333 return pDeviceInfo->pNext; 00334 } 00335 00336 /* 00337 * If a PnP thread is waiting in RequestDeviceChange for some action to be 00338 * performed on this device, just mark it for freeing and signal that PnP 00339 * thread with the pkeHidChangeCompleted so that it will free it 00340 */ 00341 if (pDeviceInfo->usActions & GDIAF_PNPWAITING) { 00342 #if DIAGNOSE_IO 00343 pDeviceInfo->bFlags |= GDIF_PNPMUSTFREE; 00344 #endif 00345 TAGMSG1(DBGTAG_PNP, "** FreeDeviceInfo(%#p) DEFERRED : PnP must free", pDeviceInfo); 00346 pDeviceInfo->usActions |= GDIAF_FREEME; 00347 KeSetEvent(pDeviceInfo->pkeHidChangeCompleted, EVENT_INCREMENT, FALSE); 00348 return pDeviceInfo->pNext; 00349 } 00350 00351 ppDeviceInfo = &gpDeviceInfoList; 00352 00353 while (*ppDeviceInfo) { 00354 if (*ppDeviceInfo == pDeviceInfo) { 00355 /* 00356 * Found the DEVICEINFO struct, so free it and its members. 00357 */ 00358 if (pDeviceInfo->pkeHidChangeCompleted != NULL) { 00359 FreeKernelEvent(&pDeviceInfo->pkeHidChangeCompleted); // BUG BUG 00360 } 00361 if (pDeviceInfo->ustrName.Buffer != NULL) { 00362 UserFreePool(pDeviceInfo->ustrName.Buffer); 00363 } 00364 *ppDeviceInfo = pDeviceInfo->pNext; 00365 UserFreePool(pDeviceInfo); 00366 00367 return *ppDeviceInfo; 00368 } 00369 ppDeviceInfo = &(*ppDeviceInfo)->pNext; 00370 } 00371 RIPMSG1(RIP_ERROR, "pDeviceInfo %#p not found in gpDeviceInfoList", pDeviceInfo); 00372 00373 return NULL; 00374 } 00375 00376 /***************************************************************************\ 00377 * UpdateMouseInfo 00378 * 00379 * This function updates mouse information for a remote session. 00380 * 00381 * History: 00382 * 05-22-98 clupu Created. 00383 \***************************************************************************/ 00384 00385 void UpdateMouseInfo(void) 00386 { 00387 DEVICEINFO *pDeviceInfo; 00388 CheckCritIn(); // expect no surprises 00389 00390 UserAssert(gbRemoteSession); 00391 00392 if (ghRemoteMouseChannel == NULL) { 00393 return; 00394 } 00395 00396 UserAssert(gnMice == 1); 00397 00398 /* 00399 * Mark the mice and signal the RIT to do the work asynchronously 00400 */ 00401 EnterDeviceInfoListCrit(); 00402 for (pDeviceInfo = gpDeviceInfoList; pDeviceInfo; pDeviceInfo = pDeviceInfo->pNext) { 00403 if (pDeviceInfo->type == DEVICE_TYPE_MOUSE) { 00404 TAGMSG1(DBGTAG_PNP, "UpdateMouseInfo(): pDeviceInfo %#p ARRIVED", pDeviceInfo); 00405 RequestDeviceChange(pDeviceInfo, GDIAF_ARRIVED | GDIAF_RECONNECT, TRUE); 00406 } 00407 } 00408 LeaveDeviceInfoListCrit(); 00409 } 00410 00411 00412 NTSTATUS DeviceNotify(IN PPLUGPLAY_NOTIFY_HDR, IN PDEVICEINFO); 00413 00414 00415 /***************************************************************************\ 00416 * InitKeyboard 00417 * 00418 * This function opens the keyboard driver for USER. It does this by opening 00419 * the keyboard driver 'file'. It also gets information about the keyboard 00420 * driver such as the minimum and maximum repeat rate/delay. This is necessary 00421 * because the keyboard driver will return an error if you give it values 00422 * outside those ranges. 00423 * 00424 * History: 00425 * 11-26-90 DavidPe Created. 00426 \***************************************************************************/ 00427 00428 VOID InitKeyboard(VOID) 00429 { 00430 if (!gbRemoteSession) { 00431 /* 00432 * Get the Scancode Mapping, if any. 00433 */ 00434 gpScancodeMap = InitScancodeMap(); 00435 } 00436 } 00437 00438 00439 HKL GetActiveHKL() 00440 { 00441 CheckCritIn(); 00442 if (gpqForeground && gpqForeground->spwndActive) { 00443 PTHREADINFO ptiForeground = GETPTI(gpqForeground->spwndActive); 00444 if (ptiForeground && ptiForeground->spklActive) { 00445 return ptiForeground->spklActive->hkl; 00446 } 00447 } 00448 return _GetKeyboardLayout(0L); 00449 } 00450 00451 00452 /***************************************************************************\ 00453 * xxxButtonEvent (RIT) 00454 * 00455 * Button events from the mouse driver go here. Based on the location of 00456 * the cursor the event is directed to specific window. When a button down 00457 * occurs, a mouse owner window is established. All mouse events up to and 00458 * including the corresponding button up go to the mouse owner window. This 00459 * is done to best simulate what applications want when doing mouse capturing. 00460 * Since we're processing these events asynchronously, but the application 00461 * calls SetCapture() in response to it's synchronized processing of input 00462 * we have no other way to get this functionality. 00463 * 00464 * The async keystate table for VK_*BUTTON is updated here. 00465 * 00466 * History: 00467 * 10-18-90 DavidPe Created. 00468 * 01-25-91 IanJa xxxWindowHitTest change 00469 * 03-12-92 JonPa Make caller enter crit instead of this function 00470 \***************************************************************************/ 00471 00472 VOID xxxButtonEvent( 00473 DWORD ButtonNumber, 00474 POINT ptPointer, 00475 BOOL fBreak, 00476 DWORD time, 00477 ULONG_PTR ExtraInfo, 00478 BOOL bInjected, 00479 BOOL fDblClk) 00480 { 00481 UINT message, usVK, usOtherVK, wHardwareButton; 00482 PWND pwnd; 00483 LPARAM lParam; 00484 WPARAM wParam; 00485 int xbutton; 00486 TL tlpwnd; 00487 PHOOK pHook; 00488 00489 #ifdef REDIRECTION 00490 PWND pwndStart; 00491 #endif // REDIRECTION 00492 00493 CheckCritIn(); 00494 00495 00496 /* 00497 * Cancel Alt-Tab if the user presses a mouse button 00498 */ 00499 if (gspwndAltTab != NULL) { 00500 xxxCancelCoolSwitch(); 00501 } 00502 00503 /* 00504 * Grab the mouse button before we process any button swapping. 00505 * This is so we won't get confused if someone calls 00506 * SwapMouseButtons() inside a down-click/up-click. 00507 */ 00508 wHardwareButton = (UINT)ButtonNumber; 00509 00510 /* 00511 * If this is the left or right mouse button, we have to handle mouse 00512 * button swapping. 00513 */ 00514 if (ButtonNumber & (MOUSE_BUTTON_LEFT | MOUSE_BUTTON_RIGHT)) { 00515 /* 00516 * If button swapping is on, swap the mouse buttons 00517 */ 00518 if (SYSMET(SWAPBUTTON)) { 00519 ButtonNumber ^= (MOUSE_BUTTON_LEFT | MOUSE_BUTTON_RIGHT); 00520 } 00521 00522 /* 00523 * Figure out VK 00524 */ 00525 if (ButtonNumber == MOUSE_BUTTON_RIGHT) { 00526 usVK = VK_RBUTTON; 00527 usOtherVK = VK_LBUTTON; 00528 } else if (ButtonNumber == MOUSE_BUTTON_LEFT) { 00529 usVK = VK_LBUTTON; 00530 usOtherVK = VK_RBUTTON; 00531 } else { 00532 RIPMSG1(RIP_ERROR, "Unexpected Button number %d", ButtonNumber); 00533 } 00534 00535 /* 00536 * If the mouse buttons have recently been swapped AND the button 00537 * transition doesn't match what we have in our keystate, then swap the 00538 * button to match. 00539 * This is to fix the ruler (tabs and margins) in Word 97 SR1, which 00540 * calls SwapMouseButtons(0) to determine if button swapping is on, and 00541 * if so then calls SwapMouseButtons(1) to restore it: if we receive a 00542 * button event between these two calls, we may swap incorrectly, and 00543 * be left with a mouse button stuck down or see the wrong button going 00544 * down. This really messed up single/double button tab/margin setting! 00545 * The same bug shows up under Windows '95, although very infrequently: 00546 * Word 9 will use GetSystemMetrics(SM_SWAPBUTTON) instead according to 00547 * to Mark Walker (MarkWal). (IanJa) #165157 00548 */ 00549 if (gbMouseButtonsRecentlySwapped) { 00550 if ((!fBreak == !!TestAsyncKeyStateDown(usVK)) && 00551 (fBreak == !!TestAsyncKeyStateDown(usOtherVK))) { 00552 RIPMSG4(RIP_WARNING, "Correct %s %s to %s %s", 00553 ButtonNumber == MOUSE_BUTTON_LEFT ? "Left" : "Right", 00554 fBreak ? "Up" : "Down", 00555 ButtonNumber == MOUSE_BUTTON_LEFT ? "Right" : "Left", 00556 fBreak ? "Up" : "Down"); 00557 ButtonNumber ^= (MOUSE_BUTTON_LEFT | MOUSE_BUTTON_RIGHT); 00558 usVK = usOtherVK; 00559 } 00560 gbMouseButtonsRecentlySwapped = FALSE; 00561 } 00562 } 00563 00564 xbutton = 0; 00565 switch (ButtonNumber) { 00566 case MOUSE_BUTTON_RIGHT: 00567 if (fBreak) { 00568 message = WM_RBUTTONUP; 00569 } else { 00570 if (ISTS() && fDblClk) 00571 message = WM_RBUTTONDBLCLK; 00572 else 00573 message = WM_RBUTTONDOWN; 00574 } 00575 break; 00576 00577 case MOUSE_BUTTON_LEFT: 00578 if (fBreak) { 00579 message = WM_LBUTTONUP; 00580 } else { 00581 if (ISTS() && fDblClk) 00582 message = WM_LBUTTONDBLCLK; 00583 else 00584 message = WM_LBUTTONDOWN; 00585 } 00586 break; 00587 00588 case MOUSE_BUTTON_MIDDLE: 00589 if (fBreak) { 00590 message = WM_MBUTTONUP; 00591 } else { 00592 if (ISTS() && fDblClk) 00593 message = WM_MBUTTONDBLCLK; 00594 else 00595 message = WM_MBUTTONDOWN; 00596 } 00597 usVK = VK_MBUTTON; 00598 break; 00599 00600 case MOUSE_BUTTON_X1: 00601 case MOUSE_BUTTON_X2: 00602 if (fBreak) { 00603 message = WM_XBUTTONUP; 00604 } else { 00605 if (ISTS() && fDblClk) 00606 message = WM_XBUTTONDBLCLK; 00607 else 00608 message = WM_XBUTTONDOWN; 00609 } 00610 00611 if (ButtonNumber == MOUSE_BUTTON_X1) { 00612 usVK = VK_XBUTTON1; 00613 xbutton = XBUTTON1; 00614 } else { 00615 usVK = VK_XBUTTON2; 00616 xbutton = XBUTTON2; 00617 } 00618 break; 00619 00620 default: 00621 /* 00622 * Unknown button. Since we don't 00623 * have messages for these buttons, ignore them. 00624 */ 00625 return; 00626 } 00627 UserAssert(usVK != 0); 00628 00629 wParam = MAKEWPARAM(0, xbutton); 00630 00631 /* 00632 * Call low level mouse hooks to see if they allow this message 00633 * to pass through USER 00634 */ 00635 if ((pHook = PhkFirstValid(PtiCurrent(), WH_MOUSE_LL)) != NULL) { 00636 MSLLHOOKSTRUCT mslls; 00637 BOOL bAnsiHook; 00638 00639 mslls.pt = ptPointer; 00640 mslls.mouseData = (LONG)wParam; 00641 mslls.flags = bInjected; 00642 mslls.time = time; 00643 mslls.dwExtraInfo = ExtraInfo; 00644 00645 if (xxxCallHook2(pHook, HC_ACTION, (DWORD)message, (LPARAM)&mslls, &bAnsiHook)) { 00646 return; 00647 } 00648 } 00649 00650 /* 00651 * This is from HYDRA 00652 */ 00653 UserAssert(grpdeskRitInput != NULL); 00654 00655 #ifdef REDIRECTION 00656 /* 00657 * Call the speed hit test hook 00658 */ 00659 pwndStart = xxxCallSpeedHitTestHook(&ptPointer); 00660 if (pwndStart == NULL) { 00661 pwndStart = grpdeskRitInput->pDeskInfo->spwnd; 00662 } 00663 00664 pwnd = SpeedHitTest(pwndStart, ptPointer); 00665 #else 00666 pwnd = SpeedHitTest(grpdeskRitInput->pDeskInfo->spwnd, ptPointer); 00667 #endif // REDIRECTION 00668 00669 /* 00670 * Only post the message if we actually hit a window. 00671 */ 00672 if (pwnd == NULL) 00673 return; 00674 00675 /* 00676 * Assign the message to a window. 00677 */ 00678 lParam = MAKELONG((SHORT)ptPointer.x, (SHORT)ptPointer.y); 00679 00680 /* 00681 * KOREAN: 00682 * Send VK_PROCESSKEY to finalize current composition string (NT4 behavior) 00683 * Post private message to let IMM finalize the composition string (NT5) 00684 */ 00685 if (IS_IME_ENABLED() && 00686 !fBreak && 00687 KOREAN_KBD_LAYOUT(GetActiveHKL()) && 00688 !TestCF(pwnd, CFIME) && 00689 gpqForeground != NULL) { 00690 00691 PTHREADINFO ptiWnd = GETPTI(pwnd); 00692 00693 /* 00694 * 274007: MFC flushes mouse related messages if keyup is posted 00695 * while it's in context help mode. 00696 */ 00697 if (gpqForeground->spwndCapture == NULL && 00698 /* 00699 * Hack for OnScreen Keyboard: no finalization on button event. 00700 */ 00701 (GetAppImeCompatFlags(ptiWnd) & IMECOMPAT_NOFINALIZECOMPSTR) == 0) { 00702 00703 if (ptiWnd->dwExpWinVer > VER40) { 00704 PWND pwndIme = ptiWnd->spwndDefaultIme; 00705 00706 if (pwndIme && !TestWF(pwndIme, WFINDESTROY)) { 00707 /* 00708 * For new applications, we no longer post hacky WM_KEYUP. 00709 * Instead, we use private IME_SYSTEM message. 00710 */ 00711 _PostMessage(pwndIme, WM_IME_SYSTEM, IMS_FINALIZE_COMPSTR, 0); 00712 } 00713 } else { 00714 /* 00715 * For the backward compatibility w/NT4, we post WM_KEYUP to finalize 00716 * the composition string. 00717 */ 00718 PostInputMessage(gpqForeground, NULL, WM_KEYUP, VK_PROCESSKEY, 0, 0, 0); 00719 } 00720 } 00721 } 00722 00723 /* 00724 * If screen capture is active do it 00725 */ 00726 if (gspwndScreenCapture != NULL) 00727 pwnd = gspwndScreenCapture; 00728 00729 /* 00730 * If this is a button down event and there isn't already 00731 * a mouse owner, setup the mouse ownership globals. 00732 */ 00733 if (gspwndMouseOwner == NULL) { 00734 if (!fBreak) { 00735 PWND pwndCapture; 00736 00737 /* 00738 * BIG HACK: If the foreground window has the capture 00739 * and the mouse is outside the foreground queue then 00740 * send a buttondown/up pair to that queue so it'll 00741 * cancel it's modal loop. 00742 */ 00743 if (pwndCapture = PwndForegroundCapture()) { 00744 00745 if (GETPTI(pwnd)->pq != GETPTI(pwndCapture)->pq) { 00746 PQ pqCapture; 00747 00748 pqCapture = GETPTI(pwndCapture)->pq; 00749 PostInputMessage(pqCapture, pwndCapture, message, 00750 0, lParam, 0, 0); 00751 PostInputMessage(pqCapture, pwndCapture, message + 1, 00752 0, lParam, 0, 0); 00753 00754 /* 00755 * EVEN BIGGER HACK: To maintain compatibility 00756 * with how tracking deals with this, we don't 00757 * pass this event along. This prevents mouse 00758 * clicks in other windows from causing them to 00759 * become foreground while tracking. The exception 00760 * to this is when we have the sysmenu up on 00761 * an iconic window. 00762 */ 00763 if ((GETPTI(pwndCapture)->pmsd != NULL) && 00764 !IsMenuStarted(GETPTI(pwndCapture))) { 00765 return; 00766 } 00767 } 00768 } 00769 00770 Lock(&(gspwndMouseOwner), pwnd); 00771 gwMouseOwnerButton |= wHardwareButton; 00772 glinp.ptLastClick = gpsi->ptCursor; 00773 } else { 00774 00775 /* 00776 * The mouse owner must have been destroyed or unlocked 00777 * by a fullscreen switch. Keep the button state in sync. 00778 */ 00779 gwMouseOwnerButton &= ~wHardwareButton; 00780 } 00781 00782 } else { 00783 00784 /* 00785 * Give any other button events to the mouse-owner window 00786 * to be consistent with old capture semantics. 00787 */ 00788 if (gspwndScreenCapture == NULL) { 00789 /* 00790 * NT5 Foreground and Drag Drop. 00791 * If the mouse goes up on a different thread 00792 * make the mouse up thread the owner of this click 00793 */ 00794 if (fBreak && (GETPTI(pwnd) != GETPTI(gspwndMouseOwner))) { 00795 glinp.ptiLastWoken = GETPTI(pwnd); 00796 TAGMSG1(DBGTAG_FOREGROUND, "xxxButtonEvent. ptiLastWoken %#p", glinp.ptiLastWoken); 00797 } 00798 pwnd = gspwndMouseOwner; 00799 } 00800 00801 /* 00802 * If this is the button-up event for the mouse-owner 00803 * clear gspwndMouseOwner. 00804 */ 00805 if (fBreak) { 00806 gwMouseOwnerButton &= ~wHardwareButton; 00807 if (!gwMouseOwnerButton) 00808 Unlock(&gspwndMouseOwner); 00809 } else { 00810 gwMouseOwnerButton |= wHardwareButton; 00811 } 00812 } 00813 00814 /* 00815 * Only update the async keystate when we know which window this 00816 * event goes to (or else we can't keep the thread specific key 00817 * state in sync). 00818 */ 00819 UserAssert(usVK != 0); 00820 UpdateAsyncKeyState(GETPTI(pwnd)->pq, usVK, fBreak); 00821 00822 /* 00823 * Put pwnd into the foreground if this is a button down event 00824 * and it isn't already the foreground window. 00825 */ 00826 if (!fBreak && GETPTI(pwnd)->pq != gpqForeground) { 00827 /* 00828 * If this is an WM_*BUTTONDOWN on a desktop window just do 00829 * cancel-mode processing. Check to make sure that there 00830 * wasn't already a mouse owner window. See comments below. 00831 */ 00832 if ((gpqForeground != NULL) && (pwnd == grpdeskRitInput->pDeskInfo->spwnd) && 00833 ((gwMouseOwnerButton & wHardwareButton) || 00834 (gwMouseOwnerButton == 0))) { 00835 PostEventMessage(gpqForeground->ptiMouse, 00836 gpqForeground, QEVENT_CANCELMODE, NULL, 0, 0, 0); 00837 00838 } else if ((gwMouseOwnerButton & wHardwareButton) || 00839 (gwMouseOwnerButton == 0)) { 00840 00841 /* 00842 * Don't bother setting the foreground window if there's 00843 * already mouse owner window from a button-down different 00844 * than this event. This prevents weird things from happening 00845 * when the user starts a tracking operation with the left 00846 * button and clicks the right button during the tracking 00847 * operation. 00848 */ 00849 /* 00850 * If pwnd is a descendent of a WS_EX_NOACTIVATE window, then we 00851 * won't set it to the foreground 00852 */ 00853 PWND pwndTopLevel = GetTopLevelWindow(pwnd); 00854 if (!TestWF(pwndTopLevel, WEFNOACTIVATE)) { 00855 ThreadLockAlways(pwnd, &tlpwnd); 00856 xxxSetForegroundWindow2(pwnd, NULL, 0); 00857 /* 00858 * Ok to unlock right away: the above didn't really leave the crit sec. 00859 * We lock here for consistency so the debug macros work ok. 00860 */ 00861 ThreadUnlock(&tlpwnd); 00862 00863 } 00864 } 00865 } 00866 00867 if (GETPTI(pwnd)->pq->QF_flags & QF_MOUSEMOVED) { 00868 PostMove(GETPTI(pwnd)->pq); 00869 } 00870 00871 PostInputMessage(GETPTI(pwnd)->pq, pwnd, message, wParam, lParam, time, ExtraInfo); 00872 00873 /* 00874 * If this is a mouse up event and stickykeys is enabled all latched 00875 * keys will be released. 00876 */ 00877 if (fBreak && (TEST_ACCESSFLAG(StickyKeys, SKF_STICKYKEYSON) || 00878 TEST_ACCESSFLAG(MouseKeys, MKF_MOUSEKEYSON))) { 00879 xxxHardwareMouseKeyUp(ButtonNumber); 00880 } 00881 00882 if (message == WM_LBUTTONDOWN) { 00883 PDESKTOP pdesk = GETPTI(pwnd)->rpdesk; 00884 if (pdesk != NULL && pdesk->rpwinstaParent != NULL) { 00885 00886 UserAssert(!(pdesk->rpwinstaParent->dwWSF_Flags & WSF_NOIO)); 00887 00888 #ifdef HUNGAPP_GHOSTING 00889 if (FHungApp(GETPTI(pwnd), CMSHUNGAPPTIMEOUT)) { 00890 SignalGhost(pwnd); 00891 } 00892 #else // HUNGAPP_GHOSTING 00893 KeSetEvent(gpEventHungThread, EVENT_INCREMENT, FALSE); 00894 #endif // HUNGAPP_GHOSTING 00895 } 00896 } 00897 } 00898 00899 /***************************************************************************\ 00900 * 00901 * The Button-Click Queue is protected by the semaphore gcsMouseEventQueue 00902 * 00903 \***************************************************************************/ 00904 #ifdef LOCK_MOUSE_CODE 00905 #pragma alloc_text(MOUSE, QueueMouseEvent) 00906 #endif 00907 00908 /***************************************************************************\ 00909 * QueueMouseEvent 00910 * 00911 * Params: 00912 * ButtonFlags - button flags from the driver in MOUSE_INPUT_DATA.ButtonFlags 00913 * 00914 * ButtonData - data from the driver in MOUSE_INPUT_DATA.ButtonData 00915 * Stores the wheel delta 00916 * 00917 * ExtraInfo - extra information from the driver in MOUSE_INPUT_DATA.ExtraInfo 00918 * ptMouse - mouse delta 00919 * time - tick count at time of event 00920 * bInjected - injected by SendInput? 00921 * bWakeRIT - wake the RIT? 00922 * 00923 \***************************************************************************/ 00924 00925 VOID QueueMouseEvent( 00926 USHORT ButtonFlags, 00927 USHORT ButtonData, 00928 ULONG_PTR ExtraInfo, 00929 POINT ptMouse, 00930 LONG time, 00931 BOOL bInjected, 00932 BOOL bWakeRIT 00933 ) 00934 { 00935 CheckCritOut(); 00936 00937 EnterMouseCrit(); 00938 00939 LOGTIME(gMouseQueueMouseEventTime); 00940 00941 /* 00942 * Button data must always be accompanied by a flag to interpret it. 00943 */ 00944 UserAssert(ButtonData == 0 || ButtonFlags != 0); 00945 00946 /* 00947 * We can coalesce this mouse event with the previous event if there is a 00948 * previous event, and if the previous event and this event involve no 00949 * key transitions. 00950 */ 00951 if ((gdwMouseEvents == 0) || 00952 (ButtonFlags != 0) || 00953 (gMouseEventQueue[gdwMouseQueueHead].ButtonFlags != 0)) { 00954 /* 00955 * Can't coalesce: must add a new mouse event 00956 */ 00957 if (gdwMouseEvents >= NELEM_BUTTONQUEUE) { 00958 /* 00959 * But no more room! 00960 */ 00961 LeaveMouseCrit(); 00962 UserBeep(440, 125); 00963 return; 00964 } 00965 00966 gdwMouseQueueHead = (gdwMouseQueueHead + 1) % NELEM_BUTTONQUEUE; 00967 gMouseEventQueue[gdwMouseQueueHead].ButtonFlags = ButtonFlags; 00968 gMouseEventQueue[gdwMouseQueueHead].ButtonData = ButtonData; 00969 gdwMouseEvents++; 00970 } 00971 00972 gMouseEventQueue[gdwMouseQueueHead].ExtraInfo = ExtraInfo; 00973 gMouseEventQueue[gdwMouseQueueHead].ptPointer = ptMouse; 00974 gMouseEventQueue[gdwMouseQueueHead].time = time; 00975 gMouseEventQueue[gdwMouseQueueHead].bInjected = bInjected; 00976 00977 LeaveMouseCrit(); 00978 00979 if (bWakeRIT) { 00980 /* 00981 * Signal RIT to complete the mouse input processing 00982 */ 00983 KeSetEvent(gpkeMouseData, EVENT_INCREMENT, FALSE); 00984 } 00985 } 00986 00987 /*****************************************************************************\ 00988 * 00989 * Gets mouse events out of the queue 00990 * 00991 * Returns: 00992 * TRUE - a mouse event is obtained in *pme 00993 * FALSE - no mouse event available 00994 * 00995 \*****************************************************************************/ 00996 00997 BOOL UnqueueMouseEvent( 00998 PMOUSEEVENT pme 00999 ) 01000 { 01001 DWORD dwTail; 01002 01003 EnterMouseCrit(); 01004 01005 LOGTIME(gMouseUnqueueMouseEventTime); 01006 01007 if (gdwMouseEvents == 0) { 01008 LeaveMouseCrit(); 01009 return FALSE; 01010 } else { 01011 dwTail = (gdwMouseQueueHead - gdwMouseEvents + 1) % NELEM_BUTTONQUEUE; 01012 *pme = gMouseEventQueue[dwTail]; 01013 gdwMouseEvents--; 01014 } 01015 01016 LeaveMouseCrit(); 01017 return TRUE; 01018 } 01019 01020 VOID xxxDoButtonEvent(PMOUSEEVENT pme) 01021 { 01022 ULONG dwButtonMask; 01023 ULONG dwButtonState; 01024 LPARAM lParam; 01025 BOOL fWheel; 01026 PHOOK pHook; 01027 ULONG dwButtonData = (ULONG) pme->ButtonData; 01028 01029 CheckCritIn(); 01030 01031 dwButtonState = (ULONG) pme->ButtonFlags; 01032 fWheel = dwButtonState & MOUSE_WHEEL; 01033 dwButtonState &= ~MOUSE_WHEEL; 01034 01035 for( dwButtonMask = 1; 01036 dwButtonState != 0; 01037 dwButtonData >>= 2, dwButtonState >>= 2, dwButtonMask <<= 1) { 01038 01039 if (dwButtonState & 1) { 01040 xxxButtonEvent(dwButtonMask, pme->ptPointer, FALSE, 01041 pme->time, pme->ExtraInfo, pme->bInjected, 01042 gbClientDoubleClickSupport && (dwButtonData & 1)); 01043 } 01044 01045 if (dwButtonState & 2) { 01046 xxxButtonEvent(dwButtonMask, pme->ptPointer, TRUE, 01047 pme->time, pme->ExtraInfo, pme->bInjected ,FALSE); 01048 } 01049 } 01050 01051 /* 01052 * Handle the wheel msg. 01053 */ 01054 if (fWheel && pme->ButtonData != 0 && gpqForeground) { 01055 01056 lParam = MAKELONG((SHORT)pme->ptPointer.x, (SHORT)pme->ptPointer.y); 01057 01058 /* 01059 * Call low level mouse hooks to see if they allow this message 01060 * to pass through USER 01061 */ 01062 if ((pHook = PhkFirstValid(PtiCurrent(), WH_MOUSE_LL)) != NULL) { 01063 MSLLHOOKSTRUCT mslls; 01064 BOOL bAnsiHook; 01065 01066 mslls.pt = pme->ptPointer; 01067 mslls.mouseData = MAKELONG(0, pme->ButtonData); 01068 mslls.flags = pme->bInjected; 01069 mslls.time = pme->time; 01070 mslls.dwExtraInfo = pme->ExtraInfo; 01071 01072 if (xxxCallHook2(pHook, HC_ACTION, (DWORD)WM_MOUSEWHEEL, 01073 (LPARAM)&mslls, &bAnsiHook)) { 01074 return; 01075 } 01076 } 01077 01078 PostInputMessage( 01079 gpqForeground, 01080 NULL, 01081 WM_MOUSEWHEEL, 01082 MAKELONG(0, pme->ButtonData), 01083 lParam, pme->time, 01084 pme->ExtraInfo); 01085 01086 return; 01087 } 01088 } 01089 01090 VOID NTAPI InputApc( 01091 IN PVOID ApcContext, 01092 IN PIO_STATUS_BLOCK IoStatusBlock, 01093 IN ULONG Reserved 01094 ) 01095 { 01096 PDEVICEINFO pDeviceInfo = (PDEVICEINFO)ApcContext; 01097 UNREFERENCED_PARAMETER(Reserved); 01098 01099 #ifdef DIAGNOSE_IO 01100 pDeviceInfo->nReadsOutstanding--; 01101 #endif 01102 01103 /* 01104 * If this device needs freeing, abandon reading now and request the free. 01105 * (Don't even process the input that we received in this APC) 01106 */ 01107 if (pDeviceInfo->usActions & GDIAF_FREEME) { 01108 EnterDeviceInfoListCrit(); 01109 pDeviceInfo->bFlags &= ~GDIF_READING; 01110 FreeDeviceInfo(pDeviceInfo); 01111 LeaveDeviceInfoListCrit(); 01112 return; 01113 } 01114 01115 if (NT_SUCCESS(IoStatusBlock->Status)) { 01116 PDEVICE_TEMPLATE pDevTpl = &aDeviceTemplate[pDeviceInfo->type]; 01117 pDevTpl->DeviceRead(pDeviceInfo); 01118 } 01119 StartDeviceRead(pDeviceInfo); 01120 } 01121 01122 /***************************************************************************\ 01123 * ProcessMouseInput 01124 * 01125 * This function is called whenever a mouse event occurs. Once the event 01126 * has been processed by USER, StartDeviceRead() is called again to request 01127 * the next mouse event. 01128 * 01129 * When this routin returns, InputApc will start another read. 01130 * 01131 * History: 01132 * 11-26-90 DavidPe Created. 01133 * 07-23-92 Mikehar Moved most of the processing to _InternalMouseEvent() 01134 * 11-08-92 JonPa Rewrote button code to work with new mouse drivers 01135 * 11-18-97 IanJa Renamed from MouseApcProcedure etc, for multiple mice 01136 \***************************************************************************/ 01137 VOID ProcessMouseInput( 01138 PDEVICEINFO pMouseInfo) 01139 { 01140 PMOUSE_INPUT_DATA pmei, pmeiNext; 01141 LONG time; 01142 POINT ptLastMove; 01143 01144 /* 01145 * This is an APC, so we don't need the DeviceInfoList Critical Section 01146 * In fact, we don't want it either. We will not remove the device until 01147 * ProcessMouseInput has signalled that it is OK to do so. (TBD) 01148 */ 01149 CheckCritOut(); 01150 CheckDeviceInfoListCritOut(); 01151 01152 UserAssert(pMouseInfo); 01153 UserAssert((PtiCurrentShared() == gTermIO.ptiDesktop) || 01154 (PtiCurrentShared() == gTermNOIO.ptiDesktop)); 01155 01156 LOGTIME(gMouseProcessMiceInputTime); 01157 01158 if (gptiBlockInput != NULL) { 01159 return; 01160 } 01161 01162 if (TEST_ACCF(ACCF_ACCESSENABLED)) { 01163 /* 01164 * Any mouse movement resets the count of consecutive shift key 01165 * presses. The shift key is used to enable & disable the 01166 * stickykeys accessibility functionality. 01167 */ 01168 gStickyKeysLeftShiftCount = 0; 01169 gStickyKeysRightShiftCount = 0; 01170 01171 /* 01172 * Any mouse movement also cancels the FilterKeys activation timer. 01173 * Entering critsect here breaks non-jerky mouse movement 01174 */ 01175 if (gtmridFKActivation != 0) { 01176 EnterCrit(); 01177 KILLRITTIMER(NULL, gtmridFKActivation); 01178 gtmridFKActivation = 0; 01179 gFilterKeysState = FKMOUSEMOVE; 01180 LeaveCrit(); 01181 return; 01182 } 01183 } 01184 01185 if (!NT_SUCCESS(pMouseInfo->iosb.Status)) { 01186 /* 01187 * If we get a bad status, we abandon reading this mouse. 01188 */ 01189 if (!gbRemoteSession) 01190 if (pMouseInfo->iosb.Status != STATUS_DELETE_PENDING) { 01191 RIPMSG3(RIP_ERROR, "iosb.Status %lx for mouse %#p (id %x) tell IanJa x63321", 01192 pMouseInfo->iosb.Status, 01193 pMouseInfo, pMouseInfo->mouse.Attr.MouseIdentifier); 01194 } 01195 return; 01196 } 01197 01198 /* 01199 * get the last move point from ptCursorAsync 01200 */ 01201 ptLastMove = gptCursorAsync; 01202 01203 pmei = pMouseInfo->mouse.Data; 01204 while (pmei != NULL) { 01205 01206 time = NtGetTickCount(); 01207 01208 /* 01209 * Figure out where the next event is. 01210 */ 01211 pmeiNext = pmei + 1; 01212 if ((PUCHAR)pmeiNext >= 01213 (PUCHAR)(((PUCHAR)pMouseInfo->mouse.Data) + pMouseInfo->iosb.Information)) { 01214 01215 /* 01216 * If there isn't another event set pmeiNext to 01217 * NULL so we exit the loop and don't get confused. 01218 */ 01219 pmeiNext = NULL; 01220 } 01221 01222 /* 01223 * If a PS/2 mouse was plugged in, evaluate the (new) mouse and 01224 * the skip the input record. 01225 */ 01226 if (pmei->Flags & MOUSE_ATTRIBUTES_CHANGED) { 01227 RequestDeviceChange(pMouseInfo, GDIAF_REFRESH_MOUSE, FALSE); 01228 goto NextMouseInputRecord; 01229 } 01230 01231 /* 01232 * First process any mouse movement that occured. 01233 * It is important to process movement before button events, otherwise 01234 * absolute coordinate pointing devices like touch-screens and tablets 01235 * will produce button clicks at old coordinates. 01236 */ 01237 if (pmei->LastX || pmei->LastY) { 01238 01239 /* 01240 * Get the actual point that will be injected. 01241 */ 01242 GetMouseCoord(pmei->LastX, 01243 pmei->LastY, 01244 pmei->Flags, 01245 time, 01246 pmei->ExtraInformation, 01247 &ptLastMove); 01248 01249 /* 01250 * If this is a move-only event, and the next one is also a 01251 * move-only event, skip/coalesce it. 01252 */ 01253 if ( (pmeiNext != NULL) && 01254 (pmei->ButtonFlags == 0) && 01255 (pmeiNext->ButtonFlags == 0) && 01256 (fAbsoluteMouse(pmei) == fAbsoluteMouse(pmeiNext))) { 01257 01258 pmei = pmeiNext; 01259 01260 continue; 01261 } 01262 01263 /* 01264 * Moves the cursor on the screen and updates gptCursorAsync 01265 * Call directly xxxMoveEventAbsolute because we already did the 01266 * acceleration sensitivity and clipping. 01267 */ 01268 xxxMoveEventAbsolute( 01269 ptLastMove.x, 01270 ptLastMove.y, 01271 pmei->ExtraInformation, 01272 time, 01273 FALSE 01274 ); 01275 01276 /* 01277 * Now update ptLastMove with ptCursorAsync because ptLastMove 01278 * doesn't reflect the clipping. 01279 */ 01280 ptLastMove = gptCursorAsync; 01281 } 01282 01283 /* 01284 * Queue mouse event for the other thread to pick up when it finishes 01285 * with the USER critical section. 01286 * If pmeiNext == NULL, there is no more mouse input yet, so wake RIT. 01287 */ 01288 QueueMouseEvent( 01289 pmei->ButtonFlags, 01290 pmei->ButtonData, 01291 pmei->ExtraInformation, 01292 gptCursorAsync, 01293 time, 01294 FALSE, 01295 (pmeiNext == NULL)); 01296 01297 NextMouseInputRecord: 01298 pmei = pmeiNext; 01299 } 01300 01301 return; 01302 } 01303 01304 01305 /***************************************************************************\ 01306 * IsHexNumpadKeys (RIT) inline 01307 * 01308 * If you change this code, you may need to change 01309 * xxxInternalToUnicode() as well. 01310 \***************************************************************************/ 01311 __inline IsHexNumpadKeys(BYTE Vk, WORD wScanCode) 01312 { 01313 return (wScanCode >= SCANCODE_NUMPAD_FIRST && wScanCode <= SCANCODE_NUMPAD_LAST && aVkNumpad[wScanCode - SCANCODE_NUMPAD_FIRST] != 0xff) || 01314 (Vk >= L'A' && Vk <= L'F') || 01315 (Vk >= L'0' && Vk <= L'9'); 01316 } 01317 01318 /***************************************************************************\ 01319 * xxxKeyEvent (RIT) 01320 * 01321 * All events from the keyboard driver go here. We receive a scan code 01322 * from the driver and convert it to a virtual scan code and virtual 01323 * key. 01324 * 01325 * The async keystate table and keylights are also updated here. Based 01326 * on the 'focus' window we direct the input to a specific window. If 01327 * the ALT key is down we send the events as WM_SYSKEY* messages. 01328 * 01329 * History: 01330 * 10-18-90 DavidPe Created. 01331 * 11-13-90 DavidPe WM_SYSKEY* support. 01332 * 11-30-90 DavidPe Added keylight updating support. 01333 * 12-05-90 DavidPe Added hotkey support. 01334 * 03-14-91 DavidPe Moved most lParam flag support to xxxCookMessage(). 01335 * 06-07-91 DavidPe Changed to use gpqForeground rather than pwndFocus. 01336 \***************************************************************************/ 01337 01338 VOID xxxKeyEvent( 01339 USHORT usFlaggedVk, 01340 WORD wScanCode, 01341 DWORD time, 01342 ULONG_PTR ExtraInfo, 01343 BOOL bInjected) 01344 { 01345 USHORT message, usExtraStuff; 01346 BOOL fBreak; 01347 BYTE VkHanded; 01348 BYTE Vk; 01349 TL tlpwndActivate; 01350 DWORD fsReserveKeys; 01351 static BOOL fMakeAltUpASysKey; 01352 PHOOK pHook; 01353 PTHREADINFO ptiCurrent = PtiCurrent(); 01354 01355 CheckCritIn(); 01356 01357 fBreak = usFlaggedVk & KBDBREAK; 01358 gpsi->bLastRITWasKeyboard = TRUE; 01359 01360 /* 01361 * Is this a keyup or keydown event? 01362 */ 01363 message = fBreak ? WM_KEYUP : WM_KEYDOWN; 01364 01365 VkHanded = (BYTE)usFlaggedVk; // get rid of state bits - no longer needed 01366 usExtraStuff = usFlaggedVk & KBDEXT; 01367 01368 /* 01369 * Convert Left/Right Ctrl/Shift/Alt key to "unhanded" key. 01370 * ie: if VK_LCONTROL or VK_RCONTROL, convert to VK_CONTROL etc. 01371 * Update this "unhanded" key's state if necessary. 01372 */ 01373 if ((VkHanded >= VK_LSHIFT) && (VkHanded <= VK_RMENU)) { 01374 BYTE VkOtherHand = VkHanded ^ 1; 01375 01376 Vk = (BYTE)((VkHanded - VK_LSHIFT) / 2 + VK_SHIFT); 01377 if (!fBreak || !TestAsyncKeyStateDown(VkOtherHand)) { 01378 if ((gptiBlockInput == NULL) || (gptiBlockInput != ptiCurrent)) { 01379 UpdateAsyncKeyState(gpqForeground, Vk, fBreak); 01380 } 01381 } 01382 } else { 01383 Vk = VkHanded; 01384 } 01385 01386 /* 01387 * Maintain gfsSASModifiersDown to indicate which of Ctrl/Shift/Alt 01388 * are really truly physically down 01389 */ 01390 if (!bInjected && ((wScanCode & SCANCODE_SIMULATED) == 0)) { 01391 if (fBreak) { 01392 gfsSASModifiersDown &= ~VKTOMODIFIERS(Vk); 01393 } else { 01394 gfsSASModifiersDown |= VKTOMODIFIERS(Vk); 01395 } 01396 } 01397 01398 /* 01399 * Call low level keyboard hook to see if it allows this 01400 * message to pass 01401 */ 01402 if ((pHook = PhkFirstValid(ptiCurrent, WH_KEYBOARD_LL)) != NULL) { 01403 KBDLLHOOKSTRUCT kbds; 01404 BOOL bAnsiHook; 01405 USHORT msg = message; 01406 01407 /* 01408 * Check if this is a WM_SYS* message 01409 */ 01410 if (TestRawKeyDown(VK_MENU) && 01411 !TestRawKeyDown(VK_CONTROL)) { 01412 01413 msg += (WM_SYSKEYDOWN - WM_KEYDOWN); 01414 usExtraStuff |= 0x2000; // ALT key down 01415 } 01416 kbds.vkCode = (DWORD)VkHanded; 01417 kbds.scanCode = (DWORD)wScanCode; 01418 kbds.flags = HIBYTE(usExtraStuff | (bInjected ? (LLKHF_INJECTED << 8) : 0)); 01419 kbds.flags |= (fBreak ? (KBDBREAK >> 8) : 0); 01420 kbds.time = time; 01421 kbds.dwExtraInfo = ExtraInfo; 01422 01423 if (xxxCallHook2(pHook, HC_ACTION, (DWORD)msg, (LPARAM)&kbds, &bAnsiHook)) { 01424 01425 UINT fsModifiers; 01426 01427 /* 01428 * We can't let low level hooks or BlockInput() eat SAS 01429 * or someone could write a trojan winlogon look alike. 01430 */ 01431 if (IsSAS(VkHanded, &fsModifiers)) { 01432 RIPMSG0(RIP_WARNING, "xxxKeyEvent: SAS ignore bad response from low level hook"); 01433 } else { 01434 return; 01435 } 01436 } 01437 } 01438 01439 /* 01440 * If someone is blocking input and it's not us, don't allow this input 01441 */ 01442 if (gptiBlockInput && (gptiBlockInput != ptiCurrent)) { 01443 UINT fsModifiers; 01444 if (IsSAS(VkHanded, &fsModifiers)) { 01445 RIPMSG0(RIP_WARNING, "xxxKeyEvent: SAS unblocks BlockInput"); 01446 gptiBlockInput = NULL; 01447 } else { 01448 return; 01449 } 01450 } 01451 01452 UpdateAsyncKeyState(gpqForeground, VkHanded, fBreak); 01453 01454 /* 01455 * Clear gfInNumpadHexInput if Menu key is up. 01456 */ 01457 if (gfEnableHexNumpad) { 01458 if (!TestAsyncKeyStateDown(VK_MENU)) { 01459 if (gfInNumpadHexInput & NUMPAD_HEXMODE_LL) { 01460 gfInNumpadHexInput &= ~NUMPAD_HEXMODE_LL; 01461 } 01462 } else { 01463 if (!fBreak) { // if it's key down 01464 if ((gfInNumpadHexInput & NUMPAD_HEXMODE_LL) || 01465 wScanCode == SCANCODE_NUMPAD_PLUS || wScanCode == SCANCODE_NUMPAD_DOT) { 01466 if ((usExtraStuff & KBDEXT) == 0) { 01467 /* 01468 * We need to check whether the input is escape character 01469 * of hex input mode. 01470 * This should be equivalent code as in xxxInternalToUnicode(). 01471 * If you change this code, you may need to change 01472 * xxxInternalToUnicode() as well. 01473 */ 01474 WORD wModBits = 0; 01475 01476 wModBits |= TestAsyncKeyStateDown(VK_MENU) ? KBDALT : 0; 01477 wModBits |= TestAsyncKeyStateDown(VK_SHIFT) ? KBDSHIFT : 0; 01478 wModBits |= TestAsyncKeyStateDown(VK_KANA) ? KBDKANA : 0; 01479 01480 if (MODIFIER_FOR_ALT_NUMPAD(wModBits)) { 01481 if ((gfInNumpadHexInput & NUMPAD_HEXMODE_LL) == 0) { 01482 /* 01483 * Only if it's not a hotkey, we enter hex Alt+Numpad mode. 01484 */ 01485 UINT wHotKeyMod = 0; 01486 01487 wHotKeyMod |= (wModBits & KBDSHIFT) ? MOD_SHIFT : 0; 01488 wHotKeyMod |= TestAsyncKeyStateDown(VK_CONTROL) ? MOD_CONTROL : 0; 01489 UserAssert(wModBits & KBDALT); 01490 wHotKeyMod |= MOD_ALT; 01491 wHotKeyMod |= TestAsyncKeyStateDown(VK_LWIN) || TestAsyncKeyStateDown(VK_RWIN) ? 01492 MOD_WIN : 0; 01493 01494 if (IsHotKey(wHotKeyMod, Vk) == NULL) { 01495 UserAssert(wScanCode == SCANCODE_NUMPAD_PLUS || wScanCode == SCANCODE_NUMPAD_DOT); 01496 gfInNumpadHexInput |= NUMPAD_HEXMODE_LL; 01497 } 01498 } else if (!IsHexNumpadKeys(Vk, wScanCode)) { 01499 gfInNumpadHexInput &= ~NUMPAD_HEXMODE_LL; 01500 } 01501 } else { 01502 gfInNumpadHexInput &= ~NUMPAD_HEXMODE_LL; 01503 } 01504 } else { 01505 gfInNumpadHexInput &= ~NUMPAD_HEXMODE_LL; 01506 } 01507 } else { 01508 UserAssert((gfInNumpadHexInput & NUMPAD_HEXMODE_LL) == 0); 01509 } 01510 } 01511 } 01512 } 01513 01514 /* 01515 * If this is a make and the key is one linked to the keyboard LEDs, 01516 * update their state. 01517 */ 01518 01519 if (!fBreak && 01520 ((Vk == VK_CAPITAL) || (Vk == VK_NUMLOCK) || (Vk == VK_SCROLL) || 01521 (Vk == VK_KANA && JAPANESE_KBD_LAYOUT(GetActiveHKL())))) { 01522 /* 01523 * Only Japanese keyboard layout could generate VK_KANA. 01524 * 01525 * [Comments for before] 01526 * Since NT 3.x, UpdatesKeyLisghts() had been called for VK_KANA 01527 * at both of 'make' and 'break' to support NEC PC-9800 Series 01528 * keyboard hardware, but for NT 4.0, thier keyboard driver emurate 01529 * PC/AT keyboard hardware, then this is changed to 01530 * "Call UpdateKeyLights() only at 'make' for VK_KANA" 01531 */ 01532 UpdateKeyLights(bInjected); 01533 } 01534 01535 /* 01536 * check for reserved keys 01537 */ 01538 fsReserveKeys = 0; 01539 if (gptiForeground != NULL) 01540 fsReserveKeys = gptiForeground->fsReserveKeys; 01541 01542 /* 01543 * Check the RIT's queue to see if it's doing the cool switch thing. 01544 * Cancel if the user presses any other key. 01545 */ 01546 if (gspwndAltTab != NULL && (!fBreak) && 01547 Vk != VK_TAB && Vk != VK_SHIFT && Vk != VK_MENU) { 01548 01549 /* 01550 * Remove the Alt-tab window 01551 */ 01552 xxxCancelCoolSwitch(); 01553 01554 /* 01555 * eat VK_ESCAPE if the app doesn't want it 01556 */ 01557 if ((Vk == VK_ESCAPE) && !(fsReserveKeys & CONSOLE_ALTESC)) { 01558 return; 01559 } 01560 } 01561 01562 /* 01563 * Check for hotkeys. 01564 */ 01565 if (xxxDoHotKeyStuff(Vk, fBreak, fsReserveKeys)) { 01566 01567 /* 01568 * The hotkey was processed so don't pass on the event. 01569 */ 01570 return; 01571 } 01572 01573 /* 01574 * If the ALT key is down and the CTRL key 01575 * isn't, this is a WM_SYS* message. 01576 */ 01577 if (TestAsyncKeyStateDown(VK_MENU) && !TestAsyncKeyStateDown(VK_CONTROL) && Vk != VK_JUNJA) { 01578 // VK_JUNJA is ALT+'+'. Since all KOR VKs are not converted to IME hotkey IDs and 01579 // should be passed directly to IME, KOR related VKs are not treated as SYSKEYDOWN. 01580 message += (WM_SYSKEYDOWN - WM_KEYDOWN); 01581 usExtraStuff |= 0x2000; 01582 01583 /* 01584 * If this is the ALT-down set this flag, otherwise 01585 * clear it since we got a key inbetween the ALT-down 01586 * and ALT-up. (see comment below) 01587 */ 01588 if (Vk == VK_MENU) { 01589 fMakeAltUpASysKey = TRUE; 01590 /* 01591 * Unlock SetForegroundWindow (if locked) when the ALT key went down. 01592 */ 01593 if (!fBreak) { 01594 gppiLockSFW = NULL; 01595 } 01596 } else { 01597 fMakeAltUpASysKey = FALSE; 01598 } 01599 01600 } else if (Vk == VK_MENU) { 01601 if (fBreak) { 01602 /* 01603 * End our switch if we are in the middle of one. 01604 */ 01605 if (fMakeAltUpASysKey) { 01606 01607 /* 01608 * We don't make the keyup of the ALT key a WM_SYSKEYUP if any 01609 * other key is typed while the ALT key was down. I don't know 01610 * why we do this, but it's been here since version 1 and any 01611 * app that uses SDM relies on it (eg - opus). 01612 * 01613 * The Alt bit is not set for the KEYUP message either. 01614 */ 01615 message += (WM_SYSKEYDOWN - WM_KEYDOWN); 01616 } 01617 01618 if (gspwndAltTab != NULL) { 01619 01620 /* 01621 * Send the alt up message before we change queues 01622 */ 01623 if (gpqForeground != NULL) { 01624 01625 /* 01626 * Set this flag so that we know we're doing a tab-switch. 01627 * This makes sure that both cases where the ALT-KEY is released 01628 * before or after the TAB-KEY is handled. It is checked in 01629 * xxxDefWindowProc(). 01630 */ 01631 gpqForeground->QF_flags |= QF_TABSWITCHING; 01632 01633 PostInputMessage(gpqForeground, NULL, message, (DWORD)Vk, 01634 MAKELONG(1, (wScanCode | usExtraStuff)), 01635 time, ExtraInfo); 01636 } 01637 01638 /* 01639 * Remove the Alt-tab window 01640 */ 01641 xxxCancelCoolSwitch(); 01642 01643 if (gspwndActivate != NULL) { 01644 /* 01645 * Make our selected window active and destroy our 01646 * switch window. If the new window is minmized, 01647 * restore it. If we are switching in the same 01648 * queue, we clear out gpqForeground to make 01649 * xxxSetForegroundWindow2 to change the pwnd 01650 * and make the switch. This case will happen 01651 * with WOW and Console apps. 01652 */ 01653 if (gpqForeground == GETPTI(gspwndActivate)->pq) { 01654 gpqForeground = NULL; 01655 } 01656 01657 /* 01658 * Make the selected window thread the owner of the last input; 01659 * since the user has selected him, he owns the ALT-TAB. 01660 */ 01661 glinp.ptiLastWoken = GETPTI(gspwndActivate); 01662 01663 01664 ThreadLockAlways(gspwndActivate, &tlpwndActivate); 01665 xxxSetForegroundWindow2(gspwndActivate, NULL, 01666 SFW_SWITCH | SFW_ACTIVATERESTORE); 01667 /* 01668 * Win3.1 calls SetWindowPos() with activate, which z-orders 01669 * first regardless, then activates. Our code relies on 01670 * xxxActivateThisWindow() to z-order, and it'll only do 01671 * it if the window does not have the child bit set (regardless 01672 * that the window is a child of the desktop). 01673 * 01674 * To be compatible, we'll just force z-order here if the 01675 * window has the child bit set. This z-order is asynchronous, 01676 * so this'll z-order after the activate event is processed. 01677 * That'll allow it to come on top because it'll be foreground 01678 * then. (Grammatik has a top level window with the child 01679 * bit set that wants to be come the active window). 01680 */ 01681 if (TestWF(gspwndActivate, WFCHILD)) { 01682 xxxSetWindowPos(gspwndActivate, (PWND)HWND_TOP, 0, 0, 0, 0, 01683 SWP_NOSIZE | SWP_NOMOVE | SWP_ASYNCWINDOWPOS); 01684 } 01685 ThreadUnlock(&tlpwndActivate); 01686 01687 Unlock(&gspwndActivate); 01688 } 01689 return; 01690 } 01691 } else { 01692 /* 01693 * The ALT key is down, unlock SetForegroundWindow (if locked) 01694 */ 01695 gppiLockSFW = NULL; 01696 } 01697 } 01698 01699 /* 01700 * Handle switching. Eat the Key if we are doing switching. 01701 */ 01702 if (!FJOURNALPLAYBACK() && !FJOURNALRECORD() && (!fBreak) && 01703 (TestAsyncKeyStateDown(VK_MENU)) && 01704 (!TestAsyncKeyStateDown(VK_CONTROL)) && //gpqForeground && 01705 (((Vk == VK_TAB) && !(fsReserveKeys & CONSOLE_ALTTAB)) || 01706 ((Vk == VK_ESCAPE) && !(fsReserveKeys & CONSOLE_ALTESC)))) { 01707 01708 xxxNextWindow(gpqForeground ? gpqForeground : gptiRit->pq, Vk); 01709 01710 } else if (gpqForeground != NULL) { 01711 PQMSG pqmsgPrev = gpqForeground->mlInput.pqmsgWriteLast; 01712 DWORD wParam = (DWORD)Vk; 01713 LONG lParam; 01714 01715 /* 01716 * We have a packet containing a Unicode character 01717 * This is injected by Pen via SendInput 01718 */ 01719 if ((Vk == VK_PACKET) && (usFlaggedVk & KBDUNICODE)) { 01720 wParam |= (wScanCode << 16); 01721 wScanCode = 0; 01722 } 01723 lParam = MAKELONG(1, (wScanCode | usExtraStuff)); 01724 01725 /* 01726 * WM_*KEYDOWN messages are left unchanged on the queue except the 01727 * repeat count field (LOWORD(lParam)) is incremented. 01728 */ 01729 if (pqmsgPrev != NULL && 01730 pqmsgPrev->msg.message == message && 01731 (message == WM_KEYDOWN || message == WM_SYSKEYDOWN) && 01732 pqmsgPrev->msg.wParam == wParam && 01733 HIWORD(pqmsgPrev->msg.lParam) == HIWORD(lParam)) { 01734 /* 01735 * Increment the queued message's repeat count. This could 01736 * conceivably overflow but Win 3.0 doesn't deal with it 01737 * and anyone who buffers up 65536 keystrokes is a chimp 01738 * and deserves to have it wrap anyway. 01739 */ 01740 pqmsgPrev->msg.lParam = MAKELONG(LOWORD(pqmsgPrev->msg.lParam) + 1, 01741 HIWORD(lParam)); 01742 01743 WakeSomeone(gpqForeground, message, pqmsgPrev); 01744 01745 } else { 01746 /* 01747 * check if these are speedracer keys - bug 339877 01748 * for the speedracer keys we want to post an event message and generate the 01749 * wm_appcommand in xxxprocesseventmessage 01750 * Since SpeedRacer software looks for the hotkeys we want to let those through 01751 * It is going in here since we don't want the ability to eat up tons of pool memory 01752 * so we post the event message here and then post the input message for the wm_keydown 01753 * below - that way if the key is repeated then there is coalescing done above and no more 01754 * qevent_appcommands are posted to the input queue. 01755 */ 01756 if (VK_APPCOMMAND_FIRST <= Vk && Vk <= VK_APPCOMMAND_LAST) { 01757 /* 01758 * Only send wm_appcommands for wm_keydown (& wm_syskeydown) messages - 01759 * essentially we ignore wm_keyup for those vk's defined for wm_appcommand messages 01760 */ 01761 if (!fBreak && gpqForeground) { 01762 /* 01763 * post an event message so we can syncronize with normal types of input 01764 * send through the vk - we will construct the message in xxxProcessEventMessage 01765 */ 01766 PostEventMessage(gpqForeground->ptiKeyboard, gpqForeground, QEVENT_APPCOMMAND, 01767 NULL, 0, (WPARAM)0, Vk); 01768 } 01769 } 01770 /* 01771 * We let the key go through since we want wm_keydowns/ups to get generated for these 01772 * SpeedRacer keys 01773 */ 01774 01775 if (gpqForeground->QF_flags & QF_MOUSEMOVED) { 01776 PostMove(gpqForeground); 01777 } 01778 01779 PostInputMessage(gpqForeground, NULL, message, wParam, 01780 lParam, time, ExtraInfo); 01781 } 01782 } 01783 } 01784 01785 /**************************************************************************\ 01786 * GetMouseCoord 01787 * 01788 * Calculates the coordinates of the point that will be injected. 01789 * 01790 * History: 01791 * 11-01-96 CLupu Created. 01792 * 12-18-97 MCostea MOUSE_VIRTUAL_DESKTOP support 01793 \**************************************************************************/ 01794 VOID GetMouseCoord( 01795 LONG dx, 01796 LONG dy, 01797 DWORD dwFlags, 01798 LONG time, 01799 ULONG_PTR ExtraInfo, 01800 PPOINT ppt) 01801 { 01802 if (dwFlags & MOUSE_MOVE_ABSOLUTE) { 01803 01804 LONG cxMetric, cyMetric; 01805 01806 /* 01807 * If MOUSE_VIRTUAL_DESKTOP was specified, map to entire virtual screen 01808 */ 01809 if (dwFlags & MOUSE_VIRTUAL_DESKTOP) { 01810 cxMetric = SYSMET(CXVIRTUALSCREEN); 01811 cyMetric = SYSMET(CYVIRTUALSCREEN); 01812 } else { 01813 cxMetric = SYSMET(CXSCREEN); 01814 cyMetric = SYSMET(CYSCREEN); 01815 } 01816 01817 /* 01818 * Absolute pointing device used: deltas are actually the current 01819 * position. Update the global mouse position. 01820 * 01821 * Note that the position is always reported in units of 01822 * (0,0)-(0xFFFF,0xFFFF) which corresponds to 01823 * (0,0)-(SYSMET(CXSCREEN), SYSMET(CYSCREEN)) in pixels. 01824 * We must first scale it to fit on the screen using the formula: 01825 * ptScreen = ptMouse * resPrimaryMonitor / 64K 01826 * 01827 * The straightforward algorithm coding of this algorithm is: 01828 * 01829 * ppt->x = (dx * SYSMET(CXSCREEN)) / (long)0x0000FFFF; 01830 * ppt->y = (dy * SYSMET(CYSCREEN)) / (long)0x0000FFFF; 01831 * 01832 * On x86, with 14 more bytes we can avoid the division function with 01833 * the following code. 01834 */ 01835 01836 ppt->x = dx * cxMetric; 01837 if (ppt->x >= 0) { 01838 ppt->x = HIWORD(ppt->x); 01839 } else { 01840 ppt->x = - (long) HIWORD(-ppt->x); 01841 } 01842 01843 ppt->y = dy * cyMetric; 01844 if (ppt->y >= 0) { 01845 ppt->y = HIWORD(ppt->y); 01846 } else { 01847 ppt->y = - (long) HIWORD(-ppt->y); 01848 } 01849 01850 /* 01851 * (0, 0) must map to the leftmost point on the desktop 01852 */ 01853 if (dwFlags & MOUSE_VIRTUAL_DESKTOP) { 01854 ppt->x += SYSMET(XVIRTUALSCREEN); 01855 ppt->y += SYSMET(YVIRTUALSCREEN); 01856 } 01857 01858 /* 01859 * Reset the mouse sensitivity remainder. 01860 */ 01861 idxRemainder = idyRemainder = 0; 01862 01863 /* 01864 * Save the absolute coordinates in the global array 01865 * for GetMouseMovePointsEx. 01866 */ 01867 SAVEPOINT(dx, dy, 0xFFFF, 0xFFFF, time, ExtraInfo); 01868 } else { 01869 /* 01870 * Is there any mouse acceleration to do? 01871 */ 01872 if (gMouseSpeed != 0) { 01873 dx = DoMouseAccel(dx); 01874 dy = DoMouseAccel(dy); 01875 } 01876 01877 /* 01878 * Does the mouse sensitivity need to be adjusted? 01879 */ 01880 if (gMouseSensitivity != MOUSE_SENSITIVITY_DEFAULT) { 01881 int iNumerator; 01882 01883 if (dx) { 01884 iNumerator = dx * gMouseSensitivityFactor + idxRemainder; 01885 dx = iNumerator / 256 ; 01886 idxRemainder = iNumerator % 256 ; 01887 if ((iNumerator < 0) && (idxRemainder > 0)) { 01888 dx++ ; 01889 idxRemainder -= 256 ; 01890 } 01891 } 01892 if (dy) { 01893 iNumerator = dy * gMouseSensitivityFactor + idyRemainder ; 01894 dy = iNumerator / 256 ; 01895 idyRemainder = iNumerator % 256 ; 01896 if ((iNumerator < 0) && (idyRemainder > 0)) { 01897 dy++ ; 01898 idyRemainder -= 256 ; 01899 } 01900 } 01901 } 01902 01903 ppt->x += dx; 01904 ppt->y += dy; 01905 01906 /* 01907 * Save the absolute coordinates in the global array 01908 * for GetMouseMovePointsEx. 01909 */ 01910 SAVEPOINT(ppt->x, ppt->y, 01911 SYSMET(CXVIRTUALSCREEN) - 1, SYSMET(CYVIRTUALSCREEN) - 1, 01912 time, ExtraInfo); 01913 } 01914 } 01915 01916 /***************************************************************************\ 01917 * xxxMoveEventAbsolute (RIT) 01918 * 01919 * Mouse move events from the mouse driver are processed here. If there is a 01920 * mouse owner window setup from xxxButtonEvent() the event is automatically 01921 * sent there, otherwise it's sent to the window the mouse is over. 01922 * 01923 * Mouse acceleration happens here as well as cursor clipping (as a result of 01924 * the ClipCursor() API). 01925 * 01926 * History: 01927 * 10-18-90 DavidPe Created. 01928 * 11-29-90 DavidPe Added mouse acceleration support. 01929 * 01-25-91 IanJa xxxWindowHitTest change 01930 * IanJa non-jerky mouse moves 01931 \***************************************************************************/ 01932 #ifdef LOCK_MOUSE_CODE 01933 #pragma alloc_text(MOUSE, xxxMoveEventAbsolute) 01934 #endif 01935 01936 VOID xxxMoveEventAbsolute( 01937 LONG x, 01938 LONG y, 01939 ULONG_PTR dwExtraInfo, 01940 DWORD time, 01941 BOOL bInjected 01942 ) 01943 { 01944 CheckCritOut(); 01945 01946 if (IsHooked(gptiRit, WHF_FROM_WH(WH_MOUSE_LL))) { 01947 MSLLHOOKSTRUCT mslls; 01948 BOOL bEatEvent = FALSE; 01949 BOOL bAnsiHook; 01950 PHOOK pHook; 01951 01952 mslls.pt.x = x; 01953 mslls.pt.y = y; 01954 mslls.mouseData = 0; 01955 mslls.flags = bInjected; 01956 mslls.time = time; 01957 mslls.dwExtraInfo = dwExtraInfo; 01958 01959 /* 01960 * Call low level mouse hooks to see if they allow this message 01961 * to pass through USER 01962 */ 01963 01964 EnterCrit(); 01965 01966 /* 01967 * Check again to see if we still have the hook installed. Fix for 80477. 01968 */ 01969 if ((pHook = PhkFirstValid(gptiRit, WH_MOUSE_LL)) != NULL) { 01970 bEatEvent = (xxxCallHook2(pHook, HC_ACTION, WM_MOUSEMOVE, (LPARAM)&mslls, &bAnsiHook) != 0); 01971 } 01972 01973 LeaveCrit(); 01974 01975 if (bEatEvent) { 01976 return; 01977 } 01978 } 01979 01980 /* 01981 * Blow off the event if WH_JOURNALPLAYBACK is installed. Do not 01982 * use FJOURNALPLAYBACK() because this routine may be called from 01983 * multiple desktop threads and the hook check must be done 01984 * for the rit thread, not the calling thread. 01985 */ 01986 if (IsGlobalHooked(gptiRit, WHF_FROM_WH(WH_JOURNALPLAYBACK))) { 01987 return; 01988 } 01989 01990 gptCursorAsync.x = x; 01991 gptCursorAsync.y = y; 01992 01993 BoundCursor(&gptCursorAsync); 01994 01995 /* 01996 * Move the screen pointer. 01997 */ 01998 GreMovePointer(gpDispInfo->hDev, gptCursorAsync.x, gptCursorAsync.y); 01999 02000 /* 02001 * Save the time stamp in a global so we can use it in PostMove 02002 */ 02003 gdwMouseMoveTimeStamp = time; 02004 } 02005 02006 /***************************************************************************\ 02007 * xxxMoveEvent (RIT) 02008 * 02009 * The dwFlags can be 02010 * 0 relative move 02011 * MOUSEEVENTF_ABSOLUTE absolute move 02012 * MOUSEEVENTF_VIRTUALDESK the absolute coordinates will be maped 02013 * to the entire virtual desktop. This flag makes sense only with MOUSEEVENTF_ABSOLUTE 02014 * 02015 \***************************************************************************/ 02016 #ifdef LOCK_MOUSE_CODE 02017 #pragma alloc_text(MOUSE, xxxMoveEvent) 02018 #endif 02019 02020 VOID xxxMoveEvent( 02021 LONG dx, 02022 LONG dy, 02023 DWORD dwFlags, 02024 ULONG_PTR dwExtraInfo, 02025 DWORD time, 02026 BOOL bInjected) 02027 { 02028 POINT ptLastMove = gptCursorAsync; 02029 02030 CheckCritOut(); 02031 02032 /* 02033 * Get the actual point that will be injected. 02034 */ 02035 GetMouseCoord(dx, dy, ConvertToMouseDriverFlags(dwFlags), 02036 time, dwExtraInfo, &ptLastMove); 02037 02038 /* 02039 * move the mouse 02040 */ 02041 xxxMoveEventAbsolute( 02042 ptLastMove.x, 02043 ptLastMove.y, 02044 dwExtraInfo, 02045 time, 02046 bInjected); 02047 } 02048 02049 02050 /***************************************************************************\ 02051 * UpdateRawKeyState 02052 * 02053 * A helper routine for ProcessKeyboardInput. 02054 * Based on a VK and a make/break flag, this function will update the physical 02055 * keystate table. 02056 * 02057 * History: 02058 * 10-13-91 IanJa Created. 02059 \***************************************************************************/ 02060 02061 void UpdateRawKeyState( 02062 BYTE Vk, 02063 BOOL fBreak) 02064 { 02065 CheckCritIn(); 02066 02067 if (fBreak) { 02068 ClearRawKeyDown(Vk); 02069 } else { 02070 02071 /* 02072 * This is a key make. If the key was not already down, update the 02073 * physical toggle bit. 02074 */ 02075 if (!TestRawKeyDown(Vk)) { 02076 ToggleRawKeyToggle(Vk); 02077 } 02078 02079 /* 02080 * This is a make, so turn on the physical key down bit. 02081 */ 02082 SetRawKeyDown(Vk); 02083 } 02084 } 02085 02086 02087 VOID CleanupResources( 02088 VOID) 02089 { 02090 PPCLS ppcls; 02091 PTHREADINFO pti; 02092 02093 UserAssert(!gbCleanedUpResources); 02094 02095 gbCleanedUpResources = TRUE; 02096 02097 HYDRA_HINT(HH_CLEANUPRESOURCES); 02098 02099 /* 02100 * Prevent power callouts. 02101 */ 02102 CleanupPowerRequestList(); 02103 02104 /* 02105 * Destroy the system classes also 02106 */ 02107 ppcls = &gpclsList; 02108 while (*ppcls != NULL) { 02109 DestroyClass(ppcls); 02110 } 02111 02112 /* 02113 * Unlock the cursor from all the CSRSS's threads. 02114 * We do this here because RIT might not be the only 02115 * CSRSS process running at this time and we want 02116 * to prevent the change of thread ownership 02117 * after RIT is gone. 02118 */ 02119 pti = PpiCurrent()->ptiList; 02120 02121 while (pti != NULL) { 02122 02123 if (pti->pq != NULL) { 02124 LockQCursor(pti->pq, NULL); 02125 } 02126 pti = pti->ptiSibling; 02127 } 02128 02129 UnloadCursorsAndIcons(); 02130 02131 /* 02132 * Cleanup the GDI globals in USERK 02133 */ 02134 CleanupGDI(); 02135 } 02136 02137 02138 /***************************************************************************\ 02139 * InitiateWin32kCleanup (RIT) 02140 * 02141 * This function starts the cleanup of a win32k 02142 * 02143 * History: 02144 * 04-Dec-97 clupu Created. 02145 \***************************************************************************/ 02146 BOOL InitiateWin32kCleanup( 02147 VOID) 02148 { 02149 PTHREADINFO ptiCurrent; 02150 PWINDOWSTATION pwinsta; 02151 BOOLEAN fWait = TRUE; 02152 PDESKTOP pdesk; 02153 UNICODE_STRING ustrName; 02154 WCHAR szName[MAX_SESSION_PATH]; 02155 HANDLE hevtRitExited; 02156 OBJECT_ATTRIBUTES obja; 02157 NTSTATUS Status; 02158 LARGE_INTEGER timeout; 02159 NTSTATUS Reason; 02160 BOOL fFirstTimeout = TRUE; 02161 02162 if (!gbRemoteSession) { 02163 return FALSE; 02164 } 02165 02166 TRACE_HYDAPI(("InitiateWin32kCleanup\n")); 02167 02168 TRACE_RIT(("Exiting Win32k ...\n")); 02169 02170 /* 02171 * Prevent power callouts. 02172 */ 02173 CleanupPowerRequestList(); 02174 02175 EnterCrit(); 02176 02177 HYDRA_HINT(HH_INITIATEWIN32KCLEANUP); 02178 02179 ptiCurrent = PtiCurrent(); 02180 02181 UserAssert(ptiCurrent != NULL); 02182 02183 pwinsta = ptiCurrent->pwinsta; 02184 02185 /* 02186 * Give DTs 5 minutes to go away 02187 */ 02188 timeout.QuadPart = Int32x32To64(-10000, 300000); 02189 02190 /* 02191 * Wait for all desktops to exit other than the disconnected desktop. 02192 */ 02193 while (fWait) { 02194 02195 /* 02196 * If things are left on the destroy list or the disconnected desktop is 02197 * not the current desktop (at the end we should always switch to the 02198 * disconnected desktop), then wait. 02199 */ 02200 pdesk = pwinsta->rpdeskList; 02201 02202 if (pdesk == NULL) { 02203 break; 02204 } 02205 02206 fWait = pdesk != gspdeskDisconnect 02207 || pdesk->rpdeskNext != NULL 02208 || pwinsta->pTerm->rpdeskDestroy != NULL; 02209 02210 if (fWait) { 02211 02212 LeaveCrit(); 02213 02214 Reason = KeWaitForSingleObject(gpevtDesktopDestroyed, WrUserRequest, 02215 KernelMode, FALSE, &timeout); 02216 02217 if (Reason == STATUS_TIMEOUT) { 02218 02219 /* 02220 * The first time we timeout might be because winlogon died 02221 * before calling ExitWindowsEx. In that case there may be processes 02222 * w/ GUI threads running and those threads will have an hdesk 02223 * in the THREADINFO structure. Thus the desktop threads will not exit. 02224 * In this situation we signal the event 'EventRitStuck' so that 02225 * csrss can tell termsrv to start killing the remaining processes 02226 * calling NtTerminateProcess on them. csrss signals that to termsrv 02227 * by closing the LPC port in ntuser\server\api.c (W32WinStationTerminate) 02228 */ 02229 02230 if (fFirstTimeout) { 02231 02232 HANDLE hevtRitStuck; 02233 02234 RIPMSG0(RIP_WARNING, 02235 "Timeout in RIT waiting for gpevtDesktopDestroyed. Signal EventRitStuck..."); 02236 02237 swprintf(szName, L"\\Sessions\\%ld\\BaseNamedObjects\\EventRitStuck", 02238 gSessionId); 02239 02240 RtlInitUnicodeString(&ustrName, szName); 02241 02242 InitializeObjectAttributes(&obja, 02243 &ustrName, 02244 OBJ_CASE_INSENSITIVE | OBJ_OPENIF, 02245 NULL, 02246 NULL); 02247 02248 Status = ZwCreateEvent(&hevtRitStuck, 02249 EVENT_ALL_ACCESS, 02250 &obja, 02251 SynchronizationEvent, 02252 FALSE); 02253 02254 UserAssert(NT_SUCCESS(Status)); 02255 02256 if (NT_SUCCESS(Status)) { 02257 ZwSetEvent(hevtRitStuck, NULL); 02258 ZwClose(hevtRitStuck); 02259 02260 fFirstTimeout = FALSE; 02261 } 02262 02263 } else { 02264 RIPMSG0(RIP_ERROR, 02265 "Timeout in RIT waiting for gpevtDesktopDestroyed.\n" 02266 "There are still GUI threads (assigned to a desktop) running !"); 02267 } 02268 } 02269 02270 EnterCrit(); 02271 } 02272 } 02273 TRACE_RIT(("All other desktops exited...\n")); 02274 02275 Unlock(&gspwndLogonNotify); 02276 02277 gbExitInProgress = TRUE; 02278 02279 TRACE_RIT(("Shutting down ptiCurrent %lx cWindows %d\n", 02280 ptiCurrent, ptiCurrent->cWindows)); 02281 02282 /* 02283 * Clear out some values so some operations won't be possible 02284 */ 02285 UserAssert(gspwndScreenCapture == NULL); 02286 UserAssert(gspwndMouseOwner == NULL); 02287 UserAssert(gspwndInternalCapture == NULL); 02288 02289 /* 02290 * Free any SPB's (Taken from wallpaper change code) 02291 */ 02292 02293 if (gpDispInfo) // If this wasn't allocated, never mind 02294 FreeAllSpbs(); 02295 02296 /* 02297 * Close the disconnected desktop. 02298 */ 02299 if (ghDisconnectWinSta) { 02300 UserVerify(NT_SUCCESS(ZwClose(ghDisconnectWinSta))); 02301 ghDisconnectWinSta = NULL; 02302 } 02303 02304 if (ghDisconnectDesk) { 02305 CloseProtectedHandle(ghDisconnectDesk); 02306 ghDisconnectDesk = NULL; 02307 } 02308 02309 UserAssert(pwinsta->rpdeskList == NULL); 02310 02311 /* 02312 * Unlock the logon desktop from the global variable 02313 */ 02314 UnlockDesktop(&grpdeskLogon, LDU_DESKLOGON, 0); 02315 02316 /* 02317 * Unlock the disconnect logon 02318 * 02319 * This was referenced when we created it, so free it now. 02320 * This is also a flag since the disconnect code checks to see if 02321 * the disconnected desktop is still around. 02322 */ 02323 UnlockDesktop(&gspdeskDisconnect, LDU_DESKDISCONNECT, 0); 02324 02325 /* 02326 * Unlock any windows still locked in the SMS list. We need to do 02327 * this here because if we don't, we end up with zombie windows in the 02328 * desktop thread that we'll try to assign to RIT but RIT will be gone. 02329 */ 02330 { 02331 PSMS psms = gpsmsList; 02332 02333 while (psms != NULL) { 02334 if (psms->spwnd != NULL) { 02335 UserAssert(psms->message == WM_CLIENTSHUTDOWN); 02336 02337 RIPMSG1(RIP_WARNING, "Window %x locked in the SMS list", 02338 psms->spwnd); 02339 02340 Unlock(&psms->spwnd); 02341 } 02342 psms = psms->psmsNext; 02343 } 02344 } 02345 02346 TRACE_RIT(("posting WM_QUIT to the IO DT\n")); 02347 02348 UserAssert(pwinsta->pTerm->ptiDesktop != NULL); 02349 02350 UserVerify(_PostThreadMessage(pwinsta->pTerm->ptiDesktop, WM_QUIT, 0, 0)); 02351 02352 HYDRA_HINT(HH_DTQUITPOSTED); 02353 02354 /* 02355 * Wait for desktop thread(s) to exit. 02356 * This thread (RIT) is used to assign 02357 * objects if the orginal thread leaves. So it should be 02358 * the last one to go. Hopefully, if the desktop thread 02359 * exits, there shouldn't be any objects in use. 02360 */ 02361 { 02362 PVOID aDT[2]; 02363 ULONG objects = 1; 02364 02365 aDT[0] = gTermIO.ptiDesktop->pEThread; 02366 02367 ObReferenceObject(aDT[0]); 02368 02369 if (gTermNOIO.ptiDesktop != NULL) { 02370 aDT[1] = gTermNOIO.ptiDesktop->pEThread; 02371 ObReferenceObject(aDT[1]); 02372 objects++; 02373 } 02374 02375 TRACE_RIT(("waiting on desktop thread(s) destruction ...\n")); 02376 02377 LeaveCrit(); 02378 02379 /* 02380 * Give DTs 5 minutes to go away 02381 */ 02382 timeout.QuadPart = Int32x32To64(-10000, 300000); 02383 WaitAgain: 02384 02385 Reason = 02386 02387 KeWaitForMultipleObjects(objects, 02388 aDT, 02389 WaitAll, 02390 WrUserRequest, 02391 KernelMode, 02392 TRUE, 02393 &timeout, 02394 NULL); 02395 02396 if (Reason == STATUS_TIMEOUT) { 02397 RIPMSG0(RIP_ERROR, 02398 "Timeout in RIT waiting for desktop threads to go away."); 02399 goto WaitAgain; 02400 } 02401 02402 TRACE_RIT(("desktop thread(s) destroyed\n")); 02403 02404 ObDereferenceObject(aDT[0]); 02405 02406 if (objects > 1) { 02407 ObDereferenceObject(aDT[1]); 02408 } 02409 02410 EnterCrit(); 02411 } 02412 02413 HYDRA_HINT(HH_ALLDTGONE); 02414 02415 /* 02416 * If still connected, tell the miniport driver to disconnect 02417 */ 02418 if (gbConnected) { 02419 bDrvDisconnect(gpDispInfo->hDev, ghRemoteThinwireChannel, 02420 gThinwireFileObject); 02421 } 02422 02423 UnlockDesktop(&grpdeskRitInput, LDU_DESKRITINPUT, 0); 02424 UnlockDesktop(&gspdeskShouldBeForeground, LDU_DESKSHOULDBEFOREGROUND, 0); 02425 02426 /* 02427 * Free outstanding timers 02428 */ 02429 while (gptmrFirst != NULL) { 02430 FreeTimer(gptmrFirst); 02431 } 02432 02433 /* 02434 * Kill the csr port so no hard errors are services after this point 02435 */ 02436 if (CsrApiPort != NULL) { 02437 ObDereferenceObject(CsrApiPort); 02438 CsrApiPort = NULL; 02439 } 02440 02441 Unlock(&gspwndCursor); 02442 02443 /* 02444 * set this to NULL 02445 */ 02446 gptiRit = NULL; 02447 02448 TRACE_RIT(("TERMINATING !!!\n")); 02449 02450 #if DBG 02451 { 02452 PPROCESSINFO ppi = gppiList; 02453 02454 KdPrint(("Processes still running:\n")); 02455 KdPrint(("-------------------------\n")); 02456 02457 while (ppi) { 02458 02459 PTHREADINFO pti; 02460 02461 KdPrint(("ppi '%s' 0x%x threads: %d\n", 02462 ppi->Process->ImageFileName, 02463 ppi, 02464 ppi->cThreads)); 02465 02466 KdPrint(("\tGUI threads\n")); 02467 02468 pti = ppi->ptiList; 02469 02470 while (pti) { 02471 KdPrint(("\t%#p\n", pti)); 02472 pti = pti->ptiSibling; 02473 } 02474 02475 ppi = ppi->ppiNextRunning; 02476 } 02477 KdPrint(("-------------------------\n")); 02478 } 02479 #endif // DBG 02480 02481 LeaveCrit(); 02482 02483 swprintf(szName, L"\\Sessions\\%ld\\BaseNamedObjects\\EventRitExited", 02484 gSessionId); 02485 02486 RtlInitUnicodeString(&ustrName, szName); 02487 02488 InitializeObjectAttributes(&obja, 02489 &ustrName, 02490 OBJ_CASE_INSENSITIVE | OBJ_OPENIF, 02491 NULL, 02492 NULL); 02493 02494 Status = ZwCreateEvent(&hevtRitExited, 02495 EVENT_ALL_ACCESS, 02496 &obja, 02497 SynchronizationEvent, 02498 FALSE); 02499 02500 UserAssert(NT_SUCCESS(Status)); 02501 02502 ZwSetEvent(hevtRitExited, NULL); 02503 02504 ZwClose(hevtRitExited); 02505 /* 02506 * Clear TIF_PALETTEAWARE or else we will AV in xxxDestroyThreadInfo 02507 * MCostea #412136 02508 */ 02509 ptiCurrent->TIF_flags &= ~TIF_PALETTEAWARE; 02510 02511 HYDRA_HINT(HH_RITGONE); 02512 02513 return TRUE; 02514 } 02515 02516 02517 /***************************************************************************\ 02518 * RemoteSyncToggleKeys (RIT) 02519 * 02520 * This function is called whenever a remote client needs to synchronize the 02521 * current toggle key state of the server. If the keys are out of sync, it 02522 * injects the correct toggle key sequences. 02523 * 02524 * History: 02525 * 11-12-98 JParsons Created. 02526 \***************************************************************************/ 02527 void RemoteSyncToggleKeys(ULONG toggleKeys) 02528 { 02529 KE ke; 02530 02531 CheckCritIn(); 02532 gSetLedReceived = toggleKeys | KEYBOARD_LED_INJECTED; 02533 02534 // Key injection only works if there is a ready application queue. 02535 if (gpqForeground != NULL) { 02536 02537 if (((gSetLedReceived & KEYBOARD_CAPS_LOCK_ON) && 02538 !TestRawKeyToggle(VK_CAPITAL)) || 02539 (!(gSetLedReceived & KEYBOARD_CAPS_LOCK_ON) && 02540 TestRawKeyToggle(VK_CAPITAL))) { 02541 02542 ke.bScanCode = (BYTE)(0x3a); 02543 ke.usFlaggedVk = VK_CAPITAL; 02544 xxxProcessKeyEvent(&ke, 0, FALSE); 02545 02546 ke.bScanCode = (BYTE)(0xba); 02547 ke.usFlaggedVk = VK_CAPITAL | KBDBREAK; 02548 xxxProcessKeyEvent(&ke, 0, FALSE); 02549 } 02550 02551 if (((gSetLedReceived & KEYBOARD_NUM_LOCK_ON) && 02552 !TestRawKeyToggle(VK_NUMLOCK)) || 02553 (!(gSetLedReceived & KEYBOARD_NUM_LOCK_ON) && 02554 TestRawKeyToggle(VK_NUMLOCK))) { 02555 02556 ke.bScanCode = (BYTE)(0x45); 02557 ke.usFlaggedVk = VK_NUMLOCK; 02558 xxxProcessKeyEvent(&ke, 0, FALSE); 02559 02560 ke.bScanCode = (BYTE)(0xc5); 02561 ke.usFlaggedVk = VK_NUMLOCK | KBDBREAK; 02562 xxxProcessKeyEvent(&ke, 0, FALSE); 02563 } 02564 02565 if (((gSetLedReceived & KEYBOARD_SCROLL_LOCK_ON) && 02566 !TestRawKeyToggle(VK_SCROLL)) || 02567 (!(gSetLedReceived & KEYBOARD_SCROLL_LOCK_ON) && 02568 TestRawKeyToggle(VK_SCROLL))) { 02569 02570 ke.bScanCode = (BYTE)(0x46); 02571 ke.usFlaggedVk = VK_SCROLL; 02572 xxxProcessKeyEvent(&ke, 0, FALSE); 02573 02574 ke.bScanCode = (BYTE)(0xc6); 02575 ke.usFlaggedVk = VK_SCROLL | KBDBREAK; 02576 xxxProcessKeyEvent(&ke, 0, FALSE); 02577 } 02578 02579 if (JAPANESE_KBD_LAYOUT(GetActiveHKL())) { 02580 if (((gSetLedReceived & KEYBOARD_KANA_LOCK_ON) && 02581 !TestRawKeyToggle(VK_KANA)) || 02582 (!(gSetLedReceived & KEYBOARD_KANA_LOCK_ON) && 02583 TestRawKeyToggle(VK_KANA))) { 02584 02585 ke.bScanCode = (BYTE)(0x70); 02586 ke.usFlaggedVk = VK_KANA; 02587 xxxProcessKeyEvent(&ke, 0, FALSE); 02588 02589 ke.bScanCode = (BYTE)(0xf0); 02590 ke.usFlaggedVk = VK_KANA | KBDBREAK; 02591 xxxProcessKeyEvent(&ke, 0, FALSE); 02592 } 02593 } 02594 02595 gSetLedReceived = 0; 02596 } 02597 } 02598 02599 02600 /***************************************************************************\ 02601 * ProcessKeyboardInput (RIT) 02602 * 02603 * This function is called whenever a keyboard input is ready to be consumed. 02604 * It calls xxxProcessKeyEvent() for every input event, and once all the events 02605 * have been consumed, calls StartDeviceRead() to request more keyboard events. 02606 * 02607 * Return value: "OK to continue walking gpDeviceInfoList" 02608 * TRUE - processed input without leaving gpresDeviceInfoList critical section 02609 * FALSE - had to leave the gpresDeviceInfoList critical section 02610 * 02611 * History: 02612 * 11-26-90 DavidPe Created. 02613 \***************************************************************************/ 02614 02615 VOID ProcessKeyboardInput(PDEVICEINFO pDeviceInfo) 02616 { 02617 BYTE Vk; 02618 BYTE bPrefix; 02619 KE ke; 02620 PKEYBOARD_INPUT_DATA pkei; 02621 PKEYBOARD_INPUT_DATA pkeiStart, pkeiEnd; 02622 02623 EnterCrit(); 02624 UserAssert(pDeviceInfo->type == DEVICE_TYPE_KEYBOARD); 02625 02626 pkeiStart = pDeviceInfo->keyboard.Data; 02627 pkeiEnd = (PKEYBOARD_INPUT_DATA)((PBYTE)pkeiStart + pDeviceInfo->iosb.Information); 02628 for (pkei = pkeiStart; pkei < pkeiEnd; pkei++) { 02629 02630 /* 02631 * Remote terminal server clients occationally need to be able to set 02632 * the server's toggle key state to match the client. All other 02633 * standard keyboard inputs are processed below since this is the most 02634 * frequent code path. 02635 */ 02636 if (!(pkei->Flags & KEY_TERMSRV_SET_LED)) { 02637 02638 // Process any deferred remote key sync requests 02639 if (!(gSetLedReceived & KEYBOARD_LED_INJECTED)) 02640 goto ProcessKeys; 02641 else 02642 RemoteSyncToggleKeys(gSetLedReceived); 02643 02644 ProcessKeys: 02645 if (pkei->Flags & KEY_E0) { 02646 bPrefix = 0xE0; 02647 } else if (pkei->Flags & KEY_E1) { 02648 bPrefix = 0xE1; 02649 } else { 02650 bPrefix = 0; 02651 } 02652 02653 if (pkei->MakeCode == 0xFF) { 02654 /* 02655 * Kbd overrun (kbd hardware and/or keyboard driver) : Beep! 02656 * (some DELL keyboards send 0xFF if keys are hit hard enough, 02657 * presumably due to keybounce) 02658 */ 02659 LeaveCrit(); 02660 UserBeep(440, 125); 02661 EnterCrit(); 02662 continue; 02663 } 02664 02665 ke.bScanCode = (BYTE)(pkei->MakeCode & 0x7F); 02666 if (gpScancodeMap) { 02667 MapScancode(&ke.bScanCode, &bPrefix); 02668 } 02669 02670 Vk = VKFromVSC(&ke, bPrefix, gafRawKeyState); 02671 02672 if (Vk == 0) { 02673 continue; 02674 } 02675 02676 if (pkei->Flags & KEY_BREAK) { 02677 ke.usFlaggedVk |= KBDBREAK; 02678 } 02679 02680 02681 /* 02682 * We don't know if the client system or the host should get the 02683 * windows key, so the choice is to not support it on the host. 02684 * (The windows key is a local key.) 02685 * 02686 * The other practical problem is that the local shell intercepts 02687 * the "break" of the windows key and switches to the start menu. 02688 * The client never sees the "break" so the host thinks the 02689 * windows key is always depressed. 02690 * 02691 * Newer clients may indicate they support the windows key. 02692 * If the client has indicated this through the gfEnableWindowsKey, 02693 * then we allow it to be processed here on the host. 02694 */ 02695 if (gbRemoteSession) { 02696 BYTE CheckVk = (BYTE)ke.usFlaggedVk; 02697 02698 if (CheckVk == VK_LWIN || CheckVk == VK_RWIN) 02699 if ( !gfEnableWindowsKey ) 02700 continue; 02701 } 02702 02703 // 02704 // Keep track of real modifier key state. Conveniently, the values for 02705 // VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, VK_RCONTROL, VK_LMENU and 02706 // VK_RMENU are contiguous. We'll construct a bit field to keep track 02707 // of the current modifier key state. If a bit is set, the corresponding 02708 // modifier key is down. The bit field has the following format: 02709 // 02710 // +---------------------------------------------------+ 02711 // | Right | Left | Right | Left | Right | Left | 02712 // | Alt | Alt | Control | Control | Shift | Shift | 02713 // +---------------------------------------------------+ 02714 // 5 4 3 2 1 0 Bit 02715 // 02716 // Add bit 7 -- VK_RWIN 02717 // bit 6 -- VK_LWIN 02718 02719 switch (Vk) { 02720 case VK_LSHIFT: 02721 case VK_RSHIFT: 02722 case VK_LCONTROL: 02723 case VK_RCONTROL: 02724 case VK_LMENU: 02725 case VK_RMENU: 02726 gCurrentModifierBit = 1 << (Vk & 0xf); 02727 break; 02728 case VK_LWIN: 02729 gCurrentModifierBit = 0x40; 02730 break; 02731 case VK_RWIN: 02732 gCurrentModifierBit = 0x80; 02733 break; 02734 default: 02735 gCurrentModifierBit = 0; 02736 } 02737 if (gCurrentModifierBit) { 02738 /* 02739 * If this is a break of a modifier key then clear the bit value. 02740 * Otherwise, set it. 02741 */ 02742 if (pkei->Flags & KEY_BREAK) { 02743 gPhysModifierState &= ~gCurrentModifierBit; 02744 } else { 02745 gPhysModifierState |= gCurrentModifierBit; 02746 } 02747 } 02748 02749 if (!TEST_ACCF(ACCF_ACCESSENABLED)) { 02750 xxxProcessKeyEvent(&ke, (ULONG_PTR)pkei->ExtraInformation, FALSE); 02751 } else { 02752 if ((gtmridAccessTimeOut != 0) && TEST_ACCESSFLAG(AccessTimeOut, ATF_TIMEOUTON)) { 02753 gtmridAccessTimeOut = InternalSetTimer( 02754 NULL, 02755 gtmridAccessTimeOut, 02756 (UINT)gAccessTimeOut.iTimeOutMSec, 02757 xxxAccessTimeOutTimer, 02758 TMRF_RIT | TMRF_ONESHOT 02759 ); 02760 } 02761 if (AccessProceduresStream(&ke, pkei->ExtraInformation, 0)) { 02762 xxxProcessKeyEvent(&ke, (ULONG_PTR)pkei->ExtraInformation, FALSE); 02763 } 02764 } 02765 } 02766 02767 // Special toggle key synchronization for Terminal Server 02768 else { 02769 RemoteSyncToggleKeys(pkei->ExtraInformation); 02770 } 02771 } 02772 02773 LeaveCrit(); 02774 } 02775 02776 02777 /***************************************************************************\ 02778 * xxxProcessKeyEvent (RIT) 02779 * 02780 * This function is called to process an individual keystroke (up or down). 02781 * It performs some OEM, language and layout specific processing which 02782 * discards or modifies the keystroke or introduces additional keystrokes. 02783 * The RawKeyState is updated here, also termination of screen saver and video 02784 * power down is initiated here. 02785 * xxxKeyEvent() is called for each resulting keystroke. 02786 * 02787 * History: 02788 * 11-26-90 DavidPe Created. 02789 \***************************************************************************/ 02790 02791 VOID xxxProcessKeyEvent( 02792 PKE pke, 02793 ULONG_PTR ExtraInformation, 02794 BOOL bInjected) 02795 { 02796 BYTE Vk; 02797 02798 CheckCritIn(); 02799 02800 Vk = (BYTE)pke->usFlaggedVk; 02801 02802 /* 02803 * KOREAN: 02804 * Check this is Korean keyboard layout, or not.. 02805 * 02806 * NOTE: 02807 * It would be better check this by "keyboard hardware" or 02808 * "keyboard layout" ??? 02809 * 02810 * 1. Check by hardware : 02811 * 02812 * if (KOREAN_KEYBOARD(gKeyboardInfo.KeyboardIdentifier)) { 02813 * 02814 * 2. Check by layout : 02815 * 02816 * if (KOREAN_KBD_LAYOUT(_GetKeyboardLayout(0L))) { 02817 */ 02818 if (KOREAN_KBD_LAYOUT(GetActiveHKL())) { 02819 if ((pke->usFlaggedVk & KBDBREAK) && 02820 !(pke->usFlaggedVk & KBDUNICODE) && 02821 (pke->bScanCode == 0xF1 || pke->bScanCode == 0xF2) && 02822 !TestRawKeyDown(Vk)) { 02823 /* 02824 * This is actually a keydown with a scancode of 0xF1 or 0xF2 from a 02825 * Korean keyboard. Korean IMEs and apps want a WM_KEYDOWN with a 02826 * scancode of 0xF1 or 0xF2. They don't mind not getting the WM_KEYUP. 02827 * Don't update physical keystate to allow a real 0x71/0x72 keydown. 02828 */ 02829 pke->usFlaggedVk &= ~KBDBREAK; 02830 } else { 02831 UpdateRawKeyState(Vk, pke->usFlaggedVk & KBDBREAK); 02832 } 02833 } else { 02834 UpdateRawKeyState(Vk, pke->usFlaggedVk & KBDBREAK); 02835 } 02836 02837 /* 02838 * Convert Left/Right Ctrl/Shift/Alt key to "unhanded" key. 02839 * ie: if VK_LCONTROL or VK_RCONTROL, convert to VK_CONTROL etc. 02840 */ 02841 if ((Vk >= VK_LSHIFT) && (Vk <= VK_RMENU)) { 02842 Vk = (BYTE)((Vk - VK_LSHIFT) / 2 + VK_SHIFT); 02843 UpdateRawKeyState(Vk, pke->usFlaggedVk & KBDBREAK); 02844 } 02845 02846 /* 02847 * Setup to shutdown screen saver and exit video power down mode. 02848 */ 02849 if (glinp.dwFlags & LINP_POWERTIMEOUTS) { 02850 /* 02851 * Call video driver here to exit power down mode. 02852 */ 02853 KdPrint(("Exit video power down mode\n")); 02854 DrvSetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD0); 02855 } 02856 glinp.dwFlags = (glinp.dwFlags & ~LINP_INPUTTIMEOUTS) | LINP_KEYBOARD; 02857 glinp.timeLastInputMessage = gpsi->dwLastRITEventTickCount = NtGetTickCount(); 02858 if (!bInjected || (pke->dwTime == 0)) { 02859 pke->dwTime = glinp.timeLastInputMessage; 02860 } 02861 02862 /* 02863 * Now call all the OEM- and Locale- specific KEProcs. 02864 * If KEProcs return FALSE, the keystroke has been discarded, in 02865 * which case don't pass the key event on to xxxKeyEvent(). 02866 */ 02867 if (pke->usFlaggedVk & KBDUNICODE) { 02868 xxxKeyEvent(pke->usFlaggedVk, pke->wchInjected, 02869 pke->dwTime, ExtraInformation, bInjected); 02870 } else { 02871 if (KEOEMProcs(pke) && xxxKELocaleProcs(pke) && xxxKENLSProcs(pke,ExtraInformation)) { 02872 xxxKeyEvent(pke->usFlaggedVk, pke->bScanCode, 02873 pke->dwTime, ExtraInformation, bInjected); 02874 } 02875 } 02876 } 02877 02878 /***************************************************************************\ 02879 * DoMouseAccel (RIT) 02880 * 02881 * History: 02882 * 11-29-90 DavidPe Created. 02883 \***************************************************************************/ 02884 #ifdef LOCK_MOUSE_CODE 02885 #pragma alloc_text(MOUSE, DoMouseAccel) 02886 #endif 02887 02888 LONG DoMouseAccel( 02889 LONG Delta) 02890 { 02891 LONG newDelta = Delta; 02892 02893 if (abs(Delta) > gMouseThresh1) { 02894 newDelta *= 2; 02895 02896 if ((abs(Delta) > gMouseThresh2) && (gMouseSpeed == 2)) { 02897 newDelta *= 2; 02898 } 02899 } 02900 02901 return newDelta; 02902 } 02903 02904 02905 /***************************************************************************\ 02906 * PwndForegroundCapture 02907 * 02908 * History: 02909 * 10-23-91 DavidPe Created. 02910 \***************************************************************************/ 02911 02912 PWND PwndForegroundCapture(VOID) 02913 { 02914 if (gpqForeground != NULL) { 02915 return gpqForeground->spwndCapture; 02916 } 02917 02918 return NULL; 02919 } 02920 02921 02922 /***************************************************************************\ 02923 * SetKeyboardRate 02924 * 02925 * This function calls the keyboard driver to set a new keyboard repeat 02926 * rate and delay. It limits the values to the min and max given by 02927 * the driver so it won't return an error when we call it. 02928 * 02929 * History: 02930 * 11-29-90 DavidPe Created. 02931 \***************************************************************************/ 02932 VOID SetKeyboardRate( 02933 UINT nKeySpeedAndDelay 02934 ) 02935 { 02936 UINT nKeyDelay; 02937 UINT nKeySpeed; 02938 02939 nKeyDelay = (nKeySpeedAndDelay & KDELAY_MASK) >> KDELAY_SHIFT; 02940 02941 nKeySpeed = KSPEED_MASK & nKeySpeedAndDelay; 02942 02943 gktp.Rate = (USHORT)( ( gKeyboardInfo.KeyRepeatMaximum.Rate - 02944 gKeyboardInfo.KeyRepeatMinimum.Rate 02945 ) * nKeySpeed / KSPEED_MASK 02946 ) + 02947 gKeyboardInfo.KeyRepeatMinimum.Rate; 02948 02949 gktp.Delay = (USHORT)( ( gKeyboardInfo.KeyRepeatMaximum.Delay - 02950 gKeyboardInfo.KeyRepeatMinimum.Delay 02951 ) * nKeyDelay / (KDELAY_MASK >> KDELAY_SHIFT) 02952 ) + 02953 gKeyboardInfo.KeyRepeatMinimum.Delay; 02954 02955 /* 02956 * Hand off the IOCTL to the RIT, since only the system process can 02957 * access keyboard handles 02958 */ 02959 gdwUpdateKeyboard |= UPDATE_KBD_TYPEMATIC; 02960 } 02961 02962 02963 /***************************************************************************\ 02964 * UpdateKeyLights 02965 * 02966 * This function calls the keyboard driver to set the keylights into the 02967 * current state specified by the async keystate table. 02968 * 02969 * bInjected: (explanation from John Parsons via email) 02970 * Set this TRUE if you do something on the server to asynchronously change the 02971 * indicators behind the TS client's back, to get this reflected back to the 02972 * client. Examples are toggling num lock or caps lock programatically, or our 02973 * favorite example is the automatic spelling correction on Word: if you type 02974 * "tHE mouse went up the clock", Word will fix it by automagically pressing 02975 * CAPS LOCK, then retyping the T -- if the client is not informed, the keys 02976 * get out of sync. 02977 * Set this to FALSE for indicator changes initiated by the client (let's say by 02978 * pressing CAPS LOCK) in which case we don't loop back the indicator change 02979 * since the client has already changed state locally. 02980 * 02981 * History: 02982 * 11-29-90 DavidPe Created. 02983 \***************************************************************************/ 02984 02985 VOID UpdateKeyLights(BOOL bInjected) 02986 { 02987 /* 02988 * Looking at async keystate. Must be in critical section. 02989 */ 02990 CheckCritIn(); 02991 02992 /* 02993 * Based on the toggle bits in the async keystate table, 02994 * set the key lights. 02995 */ 02996 gklp.LedFlags = 0; 02997 if (TestAsyncKeyStateToggle(VK_CAPITAL)) { 02998 gklp.LedFlags |= KEYBOARD_CAPS_LOCK_ON; 02999 SetRawKeyToggle(VK_CAPITAL); 03000 } else { 03001 ClearRawKeyToggle(VK_CAPITAL); 03002 } 03003 03004 if (TestAsyncKeyStateToggle(VK_NUMLOCK)) { 03005 gklp.LedFlags |= KEYBOARD_NUM_LOCK_ON; 03006 SetRawKeyToggle(VK_NUMLOCK); 03007 } else { 03008 ClearRawKeyToggle(VK_NUMLOCK); 03009 } 03010 03011 if (TestAsyncKeyStateToggle(VK_SCROLL)) { 03012 gklp.LedFlags |= KEYBOARD_SCROLL_LOCK_ON; 03013 SetRawKeyToggle(VK_SCROLL); 03014 } else { 03015 ClearRawKeyToggle(VK_SCROLL); 03016 } 03017 03018 /* 03019 * Only "Japanese keyboard hardware" has "KANA" LEDs, and switch to 03020 * "KANA" state. 03021 */ 03022 if (JAPANESE_KEYBOARD(gKeyboardInfo.KeyboardIdentifier)) { 03023 if (TestAsyncKeyStateToggle(VK_KANA)) { 03024 gklp.LedFlags |= KEYBOARD_KANA_LOCK_ON; 03025 SetRawKeyToggle(VK_KANA); 03026 } else { 03027 ClearRawKeyToggle(VK_KANA); 03028 } 03029 } 03030 03031 /* 03032 * On terminal server, we need to tell the WD about application injected 03033 * toggle keys so it can update the client accordingly. 03034 */ 03035 if (gbRemoteSession) { 03036 if (bInjected) 03037 gklp.LedFlags |= KEYBOARD_LED_INJECTED; 03038 else 03039 gklp.LedFlags &= ~KEYBOARD_LED_INJECTED; 03040 } 03041 03042 03043 if (PtiCurrent() != gptiRit) { 03044 /* 03045 * Hand off the IOCTL to the RIT, since only the system process can 03046 * access the keyboard handles. Happens when applying user's profile. 03047 * IanJa: Should we check PpiCurrent() == gptiRit->ppi instead? 03048 */ 03049 gdwUpdateKeyboard |= UPDATE_KBD_LEDS; 03050 } else { 03051 /* 03052 * Do it immediately (avoids a small delay between keydown and LED 03053 * on when typing) 03054 */ 03055 PDEVICEINFO pDeviceInfo; 03056 03057 EnterDeviceInfoListCrit(); 03058 for (pDeviceInfo = gpDeviceInfoList; pDeviceInfo; pDeviceInfo = pDeviceInfo->pNext) { 03059 if ((pDeviceInfo->type == DEVICE_TYPE_KEYBOARD) && (pDeviceInfo->handle)) { 03060 ZwDeviceIoControlFile(pDeviceInfo->handle, NULL, NULL, NULL, 03061 &giosbKbdControl, IOCTL_KEYBOARD_SET_INDICATORS, 03062 (PVOID)&gklp, sizeof(gklp), NULL, 0); 03063 } 03064 } 03065 LeaveDeviceInfoListCrit(); 03066 } 03067 } 03068 03069 03070 int _GetKeyboardType(int nTypeFlag) 03071 { 03072 03073 switch (nTypeFlag) { 03074 case 0: 03075 return gKeyboardInfo.KeyboardIdentifier.Type; 03076 03077 case 1: 03078 // FE_SB 03079 { 03080 int OEMId = 0; 03081 // 03082 // If this keyboard layout is compatible with 101 or 106 03083 // Japanese keyboard, we just return 101 or 106's keyboard 03084 // id, not this keyboard's one to let application handle 03085 // this keyboard as 101 or 106 Japanese keyboard. 03086 // 03087 if (gpKbdNlsTbl != NULL) { 03088 if (gpKbdNlsTbl->LayoutInformation & NLSKBD_INFO_EMURATE_101_KEYBOARD) { 03089 return (MICROSOFT_KBD_101_TYPE); 03090 } 03091 if (gpKbdNlsTbl->LayoutInformation & NLSKBD_INFO_EMURATE_106_KEYBOARD) { 03092 return (MICROSOFT_KBD_106_TYPE); 03093 } 03094 } 03095 03096 // 03097 // PSS ID Number: Q130054 03098 // Article last modified on 05-16-1995 03099 // 03100 // 3.10 1.20 | 3.50 1.20 03101 // WINDOWS | WINDOWS NT 03102 // 03103 // --------------------------------------------------------------------- 03104 // The information in this article applies to: 03105 // - Microsoft Windows Software Development Kit (SDK) for Windows 03106 // version 3.1 03107 // - Microsoft Win32 Software Development Kit (SDK) version 3.5 03108 // - Microsoft Win32s version 1.2 03109 // --------------------------------------------------------------------- 03110 // SUMMARY 03111 // ======= 03112 // Because of the variety of computer manufacturers (NEC, Fujitsu, IBMJ, and 03113 // so on) in Japan, sometimes Windows-based applications need to know which 03114 // OEM (original equipment manufacturer) manufactured the computer that is 03115 // running the application. This article explains how. 03116 // 03117 // MORE INFORMATION 03118 // ================ 03119 // There is no documented way to detect the manufacturer of the computer that 03120 // is currently running an application. However, a Windows-based application 03121 // can detect the type of OEM Windows by using the return value of the 03122 // GetKeyboardType() function. 03123 // 03124 // If an application uses the GetKeyboardType API, it can get OEM ID by 03125 // specifying "1" (keyboard subtype) as argument of the function. Each OEM ID 03126 // is listed here: 03127 // 03128 // OEM Windows OEM ID 03129 // ------------------------------ 03130 // Microsoft 00H (DOS/V) 03131 // all AX 01H 03132 // EPSON 04H 03133 // Fujitsu 05H 03134 // IBMJ 07H 03135 // Matsushita 0AH 03136 // NEC 0DH 03137 // Toshiba 12H 03138 // 03139 // Application programs can use these OEM IDs to distinguish the type of OEM 03140 // Windows. Note, however, that this method is not documented, so Microsoft 03141 // may not support it in the future version of Windows. 03142 // 03143 // As a rule, application developers should write hardware-independent code, 03144 // especially when making Windows-based applications. If they need to make a 03145 // hardware-dependent application, they must prepare the separated program 03146 // file for each different hardware architecture. 03147 // 03148 // Additional reference words: 3.10 1.20 3.50 1.20 kbinf 03149 // KBCategory: kbhw 03150 // KBSubcategory: wintldev 03151 // ============================================================================= 03152 // Copyright Microsoft Corporation 1995. 03153 03154 if (gpKbdNlsTbl != NULL) { 03155 // 03156 // Get OEM (Windows) ID. 03157 // 03158 OEMId = ((int)gpKbdNlsTbl->OEMIdentifier) << 8; 03159 } 03160 // 03161 // The format of KeyboardIdentifier.Subtype : 03162 // 03163 // 0 - 3 bits = keyboard subtype 03164 // 4 - 7 bits = kernel mode kerboard driver provider id. 03165 // 03166 // Kernel mode keyboard dirver provier | ID 03167 // ------------------------------------+----- 03168 // Microsoft | 00H 03169 // all AX | 01H 03170 // Toshiba | 02H 03171 // EPSON | 04H 03172 // Fujitsu | 05H 03173 // IBMJ | 07H 03174 // Matsushita | 0AH 03175 // NEC | 0DH 03176 // 03177 03178 // 03179 // And here is the format of return value. 03180 // 03181 // 0 - 7 bits = Keyboard Subtype. 03182 // 8 - 15 bits = OEM (Windows) Id. 03183 // 16 - 31 bits = not used. 03184 // 03185 return (int)(OEMId | (gKeyboardInfo.KeyboardIdentifier.Subtype & 0x0F)); 03186 } 03187 03188 case 2: 03189 return gKeyboardInfo.NumberOfFunctionKeys; 03190 } 03191 return 0; 03192 } 03193 03194 /**************************************************************************\ 03195 * xxxMouseEventDirect 03196 * 03197 * Mouse event inserts a mouse event into the input stream. 03198 * 03199 * The parameters are the same as the fields of the MOUSEINPUT structure 03200 * used in SendInput. 03201 * 03202 * dx Delta x 03203 * dy Delta y 03204 * mouseData Mouse wheel movement or xbuttons 03205 * dwMEFlags Mouse event flags 03206 * dwExtraInfo Extra info from driver. 03207 * 03208 * History: 03209 * 07-23-92 Mikehar Created. 03210 * 01-08-93 JonPa Made it work with new mouse drivers 03211 \**************************************************************************/ 03212 03213 VOID xxxMouseEventDirect( 03214 DWORD dx, 03215 DWORD dy, 03216 DWORD mouseData, 03217 DWORD dwMEFlags, 03218 DWORD dwTime, 03219 ULONG_PTR dwExtraInfo) 03220 { 03221 DWORD dwDriverMouseFlags; 03222 DWORD dwDriverMouseData; 03223 03224 PTHREADINFO pti = PtiCurrent(); 03225 if (dwTime == 0) { 03226 dwTime = NtGetTickCount(); 03227 } 03228 03229 /* 03230 * The calling thread must be on the active desktop 03231 * and have journal playback access to that desktop. 03232 */ 03233 if (pti->rpdesk == grpdeskRitInput) { 03234 UserAssert(!(pti->rpdesk->rpwinstaParent->dwWSF_Flags & WSF_NOIO)); 03235 if (!CheckGrantedAccess(pti->amdesk, DESKTOP_JOURNALPLAYBACK)) { 03236 RIPMSG0(RIP_ERROR, "mouse_event(): No DESKTOP_JOURNALPLAYBACK access to input desktop." ); 03237 return; 03238 } 03239 } else { 03240 /* 03241 * 3/22/95 BradG - Only allow below HACK for pre 4.0 applications 03242 */ 03243 if (pti->dwExpWinVer >= VER40) { 03244 RIPMSG0(RIP_VERBOSE,"mouse_event(): Calls not forwarded for 4.0 or greater apps."); 03245 return; 03246 } else { 03247 BOOL fAccessToDesktop; 03248 03249 /* 03250 * 3/22/95 BradG - Bug #9314: Screensavers are not deactivated by mouse_event() 03251 * The main problem is the check above, since screensavers run on their own 03252 * desktop. This causes the above check to fail because the process using 03253 * mouse_event() is running on another desktop. The solution is to determine 03254 * if we have access to the input desktop by calling xxxOpenDesktop for the 03255 * current input desktop, grpdeskRitInput, with a request for DESKTOP_JOURNALPLAYBACK 03256 * access. If this succeeds, we can allow this mouse_event() request to pass 03257 * through, otherwise return. 03258 */ 03259 UserAssert(grpdeskRitInput != NULL); 03260 03261 UserAssert(!(grpdeskRitInput->rpwinstaParent->dwWSF_Flags & WSF_NOIO)); 03262 fAccessToDesktop = AccessCheckObject(grpdeskRitInput, 03263 DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS | DESKTOP_JOURNALPLAYBACK, 03264 KernelMode, 03265 &DesktopMapping); 03266 if (!fAccessToDesktop) { 03267 RIPMSG0(RIP_VERBOSE, "mouse_event(): Call NOT forwarded to input desktop" ); 03268 return; 03269 } 03270 03271 /* 03272 * We do have access to the desktop, so 03273 * let this mouse_event() call go through. 03274 */ 03275 RIPMSG0( RIP_VERBOSE, "mouse_event(): Call forwarded to input desktop" ); 03276 } 03277 } 03278 03279 /* 03280 * This process is providing input so it gets the right to 03281 * call SetForegroundWindow 03282 */ 03283 gppiInputProvider = pti->ppi; 03284 03285 LeaveCrit(); 03286 03287 /* 03288 * Process coordinates first. This is especially useful for absolute 03289 * pointing devices like touch-screens and tablets. 03290 */ 03291 if (dwMEFlags & MOUSEEVENTF_MOVE) { 03292 xxxMoveEvent(dx, dy, dwMEFlags, dwExtraInfo, dwTime, TRUE); 03293 } 03294 03295 /* 03296 * The following code assumes that MOUSEEVENTF_MOVE == 1, 03297 * that MOUSEEVENTF_ABSOLUTE > all button flags, and that the 03298 * mouse_event button flags are defined in the same order as the 03299 * MOUSE_INPUT_DATA button bits. 03300 */ 03301 #if MOUSEEVENTF_MOVE != 1 03302 # error("MOUSEEVENTF_MOVE != 1") 03303 #endif 03304 #if MOUSEEVENTF_LEFTDOWN != MOUSE_LEFT_BUTTON_DOWN * 2 03305 # error("MOUSEEVENTF_LEFTDOWN != MOUSE_LEFT_BUTTON_DOWN * 2") 03306 #endif 03307 #if MOUSEEVENTF_LEFTUP != MOUSE_LEFT_BUTTON_UP * 2 03308 # error("MOUSEEVENTF_LEFTUP != MOUSE_LEFT_BUTTON_UP * 2") 03309 #endif 03310 #if MOUSEEVENTF_RIGHTDOWN != MOUSE_RIGHT_BUTTON_DOWN * 2 03311 # error("MOUSEEVENTF_RIGHTDOWN != MOUSE_RIGHT_BUTTON_DOWN * 2") 03312 #endif 03313 #if MOUSEEVENTF_RIGHTUP != MOUSE_RIGHT_BUTTON_UP * 2 03314 # error("MOUSEEVENTF_RIGHTUP != MOUSE_RIGHT_BUTTON_UP * 2") 03315 #endif 03316 #if MOUSEEVENTF_MIDDLEDOWN != MOUSE_MIDDLE_BUTTON_DOWN * 2 03317 # error("MOUSEEVENTF_MIDDLEDOWN != MOUSE_MIDDLE_BUTTON_DOWN * 2") 03318 #endif 03319 #if MOUSEEVENTF_MIDDLEUP != MOUSE_MIDDLE_BUTTON_UP * 2 03320 # error("MOUSEEVENTF_MIDDLEUP != MOUSE_MIDDLE_BUTTON_UP * 2") 03321 #endif 03322 #if MOUSEEVENTF_WHEEL != MOUSE_WHEEL * 2 03323 # error("MOUSEEVENTF_WHEEL != MOUSE_WHEEL * 2") 03324 #endif 03325 03326 /* set legal values */ 03327 dwDriverMouseFlags = dwMEFlags & MOUSEEVENTF_BUTTONMASK; 03328 03329 /* remove MOUSEEVENTF_XDOWN/UP because we are going to add 03330 MOUSEEVENTF_DRIVER_X1/2DOWN/UP later */ 03331 dwDriverMouseFlags &= ~(MOUSEEVENTF_XDOWN | MOUSEEVENTF_XUP); 03332 03333 dwDriverMouseData = 0; 03334 03335 /* 03336 * Handle mouse wheel and xbutton inputs. 03337 * 03338 * Note that MOUSEEVENTF_XDOWN/UP and MOUSEEVENTF_MOUSEWHEEL cannot both 03339 * be specified since they share the mouseData field 03340 */ 03341 if ( ((dwMEFlags & (MOUSEEVENTF_XDOWN | MOUSEEVENTF_WHEEL)) == (MOUSEEVENTF_XDOWN | MOUSEEVENTF_WHEEL)) || 03342 ((dwMEFlags & (MOUSEEVENTF_XUP | MOUSEEVENTF_WHEEL)) == (MOUSEEVENTF_XUP | MOUSEEVENTF_WHEEL))) { 03343 03344 RIPMSG1(RIP_WARNING, "Can't specify both MOUSEEVENTF_XDOWN/UP and MOUSEEVENTF_WHEEL in call to SendInput, dwFlags=0x%.8X", dwMEFlags); 03345 dwDriverMouseFlags &= ~(MOUSEEVENTF_XDOWN | MOUSEEVENTF_XUP | MOUSEEVENTF_WHEEL); 03346 } else if (dwMEFlags & MOUSEEVENTF_WHEEL) { 03347 /* 03348 * Force the value to a short. We cannot fail if it is out of range 03349 * because we accepted a 32 bit value in NT 4. 03350 */ 03351 dwDriverMouseData = min(max(SHRT_MIN, (LONG)mouseData), SHRT_MAX); 03352 } else { 03353 /* don't process xbuttons if mousedata has invalid buttons */ 03354 if (~XBUTTON_MASK & mouseData) { 03355 RIPMSG1(RIP_WARNING, "Invalid xbutton specified in SendInput, mouseData=0x%.8X", mouseData); 03356 } else { 03357 if (dwMEFlags & MOUSEEVENTF_XDOWN) { 03358 if (mouseData & XBUTTON1) { 03359 dwDriverMouseFlags |= MOUSEEVENTF_DRIVER_X1DOWN; 03360 } 03361 if (mouseData & XBUTTON2) { 03362 dwDriverMouseFlags |= MOUSEEVENTF_DRIVER_X2DOWN; 03363 } 03364 } 03365 if (dwMEFlags & MOUSEEVENTF_XUP) { 03366 if (mouseData & XBUTTON1) { 03367 dwDriverMouseFlags |= MOUSEEVENTF_DRIVER_X1UP; 03368 } 03369 if (mouseData & XBUTTON2) { 03370 dwDriverMouseFlags |= MOUSEEVENTF_DRIVER_X2UP; 03371 } 03372 } 03373 } 03374 } 03375 03376 /* Convert the MOUSEEVENTF_ flags to MOUSE_BUTTON flags sent by the driver */ 03377 dwDriverMouseFlags >>= 1; 03378 03379 QueueMouseEvent( 03380 (USHORT) dwDriverMouseFlags, 03381 (USHORT) dwDriverMouseData, 03382 dwExtraInfo, 03383 gptCursorAsync, 03384 dwTime, 03385 TRUE, 03386 FALSE 03387 ); 03388 03389 ProcessQueuedMouseEvents(); 03390 03391 EnterCrit(); 03392 } 03393 03394 /**************************************************************************\ 03395 * xxxInternalKeyEventDirect 03396 * 03397 * key event inserts a key event into the input stream. 03398 * 03399 * History: 03400 * 07-23-92 Mikehar Created. 03401 \**************************************************************************/ 03402 03403 VOID xxxInternalKeyEventDirect( 03404 BYTE bVk, 03405 WORD wScan, 03406 DWORD dwFlags, 03407 DWORD dwTime, 03408 ULONG_PTR dwExtraInfo) 03409 { 03410 PTHREADINFO pti = PtiCurrent(); 03411 KE KeyEvent; 03412 03413 /* 03414 * The calling thread must be on the active desktop 03415 * and have journal playback access to that desktop. 03416 */ 03417 if (pti->rpdesk != grpdeskRitInput || 03418 !RtlAreAllAccessesGranted(pti->amdesk, DESKTOP_JOURNALPLAYBACK)) { 03419 03420 RIPNTERR0(STATUS_ACCESS_DENIED, RIP_WARNING, 03421 "Injecting key failed: Non active desktop or access denied"); 03422 03423 return; 03424 } 03425 UserAssert(!(pti->rpdesk->rpwinstaParent->dwWSF_Flags & WSF_NOIO)); 03426 03427 KeyEvent.bScanCode = (BYTE)wScan; 03428 if (dwFlags & KEYEVENTF_SCANCODE) { 03429 bVk = VKFromVSC(&KeyEvent, 03430 (BYTE)(dwFlags & KEYEVENTF_EXTENDEDKEY ? 0xE0 : 0), 03431 gafRawKeyState); 03432 KeyEvent.usFlaggedVk = (USHORT)bVk; 03433 } else { 03434 KeyEvent.usFlaggedVk = bVk | KBDINJECTEDVK; 03435 } 03436 03437 if (dwFlags & KEYEVENTF_KEYUP) 03438 KeyEvent.usFlaggedVk |= KBDBREAK; 03439 03440 if (dwFlags & KEYEVENTF_UNICODE) { 03441 KeyEvent.usFlaggedVk |= KBDUNICODE; 03442 KeyEvent.wchInjected = wScan; 03443 } else if (dwFlags & KEYEVENTF_EXTENDEDKEY) { 03444 KeyEvent.usFlaggedVk |= KBDEXT; 03445 } else { 03446 // Is it from the numeric keypad? 03447 if (((bVk >= VK_NUMPAD0) && (bVk <= VK_NUMPAD9)) || (bVk == VK_DECIMAL)) { 03448 KeyEvent.usFlaggedVk |= KBDNUMPAD; 03449 } else { 03450 int i; 03451 for (i = 0; ausNumPadCvt[i] != 0; i++) { 03452 if (bVk == LOBYTE(ausNumPadCvt[i])) { 03453 KeyEvent.usFlaggedVk |= KBDNUMPAD; 03454 break; 03455 } 03456 } 03457 } 03458 } 03459 03460 /* 03461 * This process is providing input so it gets the right to 03462 * call SetForegroundWindow 03463 */ 03464 gppiInputProvider = pti->ppi; 03465 03466 KeyEvent.dwTime = dwTime; 03467 xxxProcessKeyEvent(&KeyEvent, dwExtraInfo, TRUE); 03468 } 03469 03470 03471 /*****************************************************************************\ 03472 * 03473 * _BlockInput() 03474 * 03475 * This disables/enables input into USER via keyboard or mouse 03476 * If input is enabled and the caller 03477 * is disabling it, the caller gets the 'input cookie.' This means two 03478 * things: 03479 * (a) Only the caller's thread can reenable input 03480 * (b) Only the caller's thread can fake input messages by calling 03481 * SendInput(). 03482 * 03483 * This guarantees a sequential uninterrupted input stream. 03484 * 03485 * It can be used in conjunction with a journal playback hook however, 03486 * since USER still does some processing in *_event functions before 03487 * noticing a journal playback hook is around. 03488 * 03489 * Note that the disabled state can be suspended, and will be, when the 03490 * fault dialog comes up. ForceInputState() will save away the enabled 03491 * status, so input is cleared, then whack back the old stuff when done. 03492 * We do the same thing for capture, modality, blah blah. This makes sure 03493 * that if somebody is hung, the end user can still type Ctrl+Alt+Del and 03494 * interact with the dialog. 03495 * 03496 \*****************************************************************************/ 03497 BOOL 03498 _BlockInput(BOOL fBlockIt) 03499 { 03500 PTHREADINFO ptiCurrent; 03501 03502 ptiCurrent = PtiCurrent(); 03503 03504 /* 03505 * The calling thread must be on the active desktop and have journal 03506 * playback access to that desktop if it wants to block input. 03507 * (Unblocking is less restricted) 03508 */ 03509 if (fBlockIt && 03510 (ptiCurrent->rpdesk != grpdeskRitInput || 03511 !RtlAreAllAccessesGranted(ptiCurrent->amdesk, DESKTOP_JOURNALPLAYBACK))) { 03512 03513 RIPNTERR0(STATUS_ACCESS_DENIED, RIP_WARNING, 03514 "BlockInput failed: Non active desktop or access denied"); 03515 return FALSE; 03516 } 03517 UserAssert(!(ptiCurrent->rpdesk->rpwinstaParent->dwWSF_Flags & WSF_NOIO)); 03518 03519 /* 03520 * If we are enabling input 03521 * * Is it disabled? No, then fail the call 03522 * * Is it disabled but we aren't the dude in control? Yes, then 03523 * fail the call. 03524 * If we are disabling input 03525 * * Is it enabled? No, then fail the call 03526 * * Set us up as the dude in control 03527 */ 03528 03529 if (fBlockIt) { 03530 /* 03531 * Is input blocked right now? 03532 */ 03533 if (gptiBlockInput != NULL) { 03534 return FALSE; 03535 } 03536 03537 /* 03538 * Is this thread exiting? If so, fail the call now. User's 03539 * cleanup code won't get a chance to whack this back if so. 03540 */ 03541 if (ptiCurrent->TIF_flags & TIF_INCLEANUP) { 03542 return FALSE; 03543 } 03544 03545 /* 03546 * Set blocking on. 03547 */ 03548 gptiBlockInput = ptiCurrent; 03549 } else { 03550 /* 03551 * Fail if input is not blocked, or blocked by another thread 03552 */ 03553 if (gptiBlockInput != ptiCurrent) { 03554 return FALSE; 03555 } 03556 03557 /* 03558 * This thread was blocking input, so now clear the block. 03559 */ 03560 gptiBlockInput = NULL; 03561 } 03562 03563 return TRUE; 03564 } 03565 03566 03567 /**************************************************************************\ 03568 * xxxSendInput 03569 * 03570 * input injection 03571 * 03572 * History: 03573 * 11-01-96 CLupu Created. 03574 \**************************************************************************/ 03575 UINT xxxSendInput( 03576 UINT nInputs, 03577 LPINPUT pInputs) 03578 { 03579 UINT nEv; 03580 LPINPUT pEvent; 03581 DWORD dwExpWinVer = PtiCurrent()->dwExpWinVer; 03582 03583 for (nEv = 0, pEvent = pInputs; nEv < nInputs; nEv++) { 03584 03585 switch (pEvent->type) { 03586 case INPUT_MOUSE: 03587 xxxMouseEventDirect( 03588 pEvent->mi.dx, 03589 pEvent->mi.dy, 03590 pEvent->mi.mouseData, 03591 pEvent->mi.dwFlags, 03592 pEvent->mi.time, 03593 pEvent->mi.dwExtraInfo); 03594 break; 03595 03596 case INPUT_KEYBOARD: 03597 if ((pEvent->ki.dwFlags & KEYEVENTF_UNICODE) && 03598 (pEvent->ki.wVk == 0) && 03599 ((pEvent->ki.dwFlags & ~(KEYEVENTF_KEYUP | KEYEVENTF_UNICODE)) == 0)) { 03600 xxxInternalKeyEventDirect( 03601 VK_PACKET, 03602 pEvent->ki.wScan, // actually a Unicode character 03603 pEvent->ki.dwFlags, 03604 pEvent->ki.time, 03605 pEvent->ki.dwExtraInfo); 03606 } else { 03607 xxxInternalKeyEventDirect( 03608 LOBYTE(pEvent->ki.wVk), 03609 LOBYTE(pEvent->ki.wScan), 03610 pEvent->ki.dwFlags, 03611 pEvent->ki.time, 03612 pEvent->ki.dwExtraInfo); 03613 } 03614 break; 03615 03616 case INPUT_HARDWARE: 03617 break; 03618 } 03619 03620 pEvent++; 03621 } 03622 return nInputs; 03623 } 03624 03625 /**************************************************************************\ 03626 * _SetConsoleReserveKeys 03627 * 03628 * Sets the reserved keys field in the console's pti. 03629 * 03630 * History: 03631 * 02-17-93 JimA Created. 03632 \**************************************************************************/ 03633 03634 BOOL _SetConsoleReserveKeys( 03635 PWND pwnd, 03636 DWORD fsReserveKeys) 03637 { 03638 GETPTI(pwnd)->fsReserveKeys = fsReserveKeys; 03639 return TRUE; 03640 } 03641 03642 /**************************************************************************\ 03643 * _GetMouseMovePointsEx 03644 * 03645 * Gets the last nPoints mouse moves from the global buffer starting with 03646 * ppt. Returns -1 if it doesn't find it. It uses the timestamp if it was 03647 * provided to differentiate between mouse points with the same coordinates. 03648 * 03649 * History: 03650 * 03-17-97 CLupu Created. 03651 \**************************************************************************/ 03652 int _GetMouseMovePointsEx( 03653 CONST MOUSEMOVEPOINT* ppt, 03654 MOUSEMOVEPOINT* ccxpptBuf, 03655 UINT nPoints, 03656 DWORD resolution) 03657 { 03658 UINT uInd, uStart, nPointsRetrieved, i; 03659 BOOL bFound = FALSE; 03660 int x, y; 03661 DWORD resX, resY; 03662 03663 uStart = PREVPOINT(gptInd); 03664 03665 /* 03666 * Search the point in the global buffer and get the first occurance. 03667 */ 03668 uInd = uStart; 03669 03670 do { 03671 /* 03672 * The resolutions can be zero only if the buffer is still not full 03673 */ 03674 if (HIWORD(gaptMouse[uInd].x) == 0 || HIWORD(gaptMouse[uInd].y) == 0) { 03675 break; 03676 } 03677 03678 resX = (DWORD)HIWORD(gaptMouse[uInd].x) + 1; 03679 resY = (DWORD)HIWORD(gaptMouse[uInd].y) + 1; 03680 03681 if ((int)resX != SYSMET(CXVIRTUALSCREEN)) { 03682 UserAssert(resX == 0x10000); 03683 x = (LOWORD(gaptMouse[uInd].x) * SYSMET(CXVIRTUALSCREEN)) / resX; 03684 } else { 03685 x = LOWORD(gaptMouse[uInd].x); 03686 } 03687 03688 if ((int)resY != SYSMET(CYVIRTUALSCREEN)) { 03689 UserAssert(resY == 0x10000); 03690 y = (LOWORD(gaptMouse[uInd].y) * SYSMET(CYVIRTUALSCREEN)) / resY; 03691 } else { 03692 y = LOWORD(gaptMouse[uInd].y); 03693 } 03694 03695 if (x == ppt->x && y == ppt->y) { 03696 03697 /* 03698 * If the timestamp was provided check to see if it's the right 03699 * timestamp. 03700 */ 03701 if (ppt->time != 0 && ppt->time != gaptMouse[uInd].time) { 03702 uInd = PREVPOINT(uInd); 03703 RIPMSG4(RIP_VERBOSE, 03704 "GetMouseMovePointsEx: Found point (%x, %y) but timestamp %x diff from %x", 03705 x, y, ppt->time, gaptMouse[uInd].time); 03706 continue; 03707 } 03708 03709 bFound = TRUE; 03710 break; 03711 } 03712 uInd = PREVPOINT(uInd); 03713 03714 } while (uInd != uStart); 03715 03716 /* 03717 * The point might not be in the buffer anymore. 03718 */ 03719 if (!bFound) { 03720 RIPERR2(ERROR_POINT_NOT_FOUND, RIP_VERBOSE, 03721 "GetMouseMovePointsEx: point not found (%x, %y)", ppt->x, ppt->y); 03722 return -1; 03723 } 03724 03725 /* 03726 * See how many points we can retrieve. 03727 */ 03728 nPointsRetrieved = (uInd <= uStart ? uInd + MAX_MOUSEPOINTS - uStart : uInd - uStart); 03729 03730 nPointsRetrieved = min(nPointsRetrieved, nPoints); 03731 03732 /* 03733 * Copy the points to the app buffer 03734 */ 03735 try { 03736 for (i = 0; i < nPointsRetrieved; i++) { 03737 03738 resX = (DWORD)HIWORD(gaptMouse[uInd].x) + 1; 03739 resY = (DWORD)HIWORD(gaptMouse[uInd].y) + 1; 03740 03741 /* 03742 * If one of the resolution is 0 then we're done 03743 */ 03744 if (HIWORD(gaptMouse[uInd].x) == 0 || HIWORD(gaptMouse[uInd].y) == 0) { 03745 break; 03746 } 03747 03748 /* 03749 * LOWORD(gaptMouse[uInd].x) contains the x point on the 03750 * scale specified by HIWORD(gaptMouse[uInd].x) 03751 */ 03752 if (resolution == GMMP_USE_HIGH_RESOLUTION_POINTS) { 03753 ccxpptBuf[i].x = ((DWORD)LOWORD(gaptMouse[uInd].x) * 0xFFFF) / (resX - 1); 03754 03755 ccxpptBuf[i].y = ((DWORD)LOWORD(gaptMouse[uInd].y) * 0xFFFF) / (resY - 1); 03756 03757 } else { 03758 UserAssert(resolution == GMMP_USE_DISPLAY_POINTS); 03759 03760 ccxpptBuf[i].x = (LOWORD(gaptMouse[uInd].x) * SYSMET(CXVIRTUALSCREEN)) / resX; 03761 03762 ccxpptBuf[i].y = (LOWORD(gaptMouse[uInd].y) * SYSMET(CYVIRTUALSCREEN)) / resY; 03763 } 03764 ccxpptBuf[i].time = gaptMouse[uInd].time; 03765 ccxpptBuf[i].dwExtraInfo = gaptMouse[uInd].dwExtraInfo; 03766 03767 03768 uInd = PREVPOINT(uInd); 03769 } 03770 } except(W32ExceptionHandler(FALSE, RIP_WARNING)) { 03771 } 03772 return i; 03773 } 03774 03775 03776 /**************************************************************************\ 03777 * ProcessQueuedMouseEvents 03778 * 03779 * Process mouse events. 03780 * 03781 * History: 03782 * 11-01-96 CLupu Created. 03783 \**************************************************************************/ 03784 void ProcessQueuedMouseEvents( 03785 void) 03786 { 03787 MOUSEEVENT MouseEvent; 03788 static POINT ptCursorLast = {0,0}; 03789 03790 while (UnqueueMouseEvent(&MouseEvent)) { 03791 03792 EnterCrit(); 03793 03794 // Setup to shutdown screen saver and exit video power down mode. 03795 if (glinp.dwFlags & LINP_POWERTIMEOUTS) { 03796 // Call video driver here to exit power down mode. 03797 KdPrint(("Exit video power down mode\n")); 03798 DrvSetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD0); 03799 } 03800 glinp.dwFlags &= ~(LINP_INPUTTIMEOUTS | LINP_KEYBOARD); 03801 glinp.timeLastInputMessage = gpsi->dwLastRITEventTickCount = MouseEvent.time; 03802 gpsi->bLastRITWasKeyboard = FALSE; 03803 03804 gpsi->ptCursor = MouseEvent.ptPointer; 03805 03806 if ((ptCursorLast.x != gpsi->ptCursor.x) || 03807 (ptCursorLast.y != gpsi->ptCursor.y)) { 03808 03809 /* 03810 * This mouse move ExtraInfo is global (as ptCursor 03811 * was) and is associated with the current ptCursor 03812 * position. ExtraInfo is sent from the driver - pen 03813 * win people use it. 03814 */ 03815 gdwMouseMoveExtraInfo = MouseEvent.ExtraInfo; 03816 03817 ptCursorLast = gpsi->ptCursor; 03818 03819 /* 03820 * Wake up someone. xxxSetFMouseMoved() clears 03821 * dwMouseMoveExtraInfo, so we must then restore it. 03822 */ 03823 zzzSetFMouseMoved(); 03824 03825 gdwMouseMoveExtraInfo = MouseEvent.ExtraInfo; 03826 } 03827 03828 if (MouseEvent.ButtonFlags != 0) { 03829 xxxDoButtonEvent(&MouseEvent); 03830 } 03831 03832 LeaveCrit(); 03833 } 03834 } 03835 03836 /***************************************************************************\ 03837 * RawInputThread (RIT) 03838 * 03839 * This is the RIT. It gets low-level/raw input from the device drivers 03840 * and posts messages the appropriate queue. It gets the input via APC 03841 * calls requested by calling NtReadFile() for the keyboard and mouse 03842 * drivers. Basically it makes the first calls to Start*Read() and then 03843 * sits in an NtWaitForSingleObject() loop which allows the APC calls to 03844 * occur. 03845 * 03846 * All functions called exclusively on the RIT will have (RIT) next to 03847 * the name in the header. 03848 * 03849 * History: 03850 * 10-18-90 DavidPe Created. 03851 * 11-26-90 DavidPe Rewrote to stop using POS layer. 03852 \***************************************************************************/ 03853 #if DBG 03854 DWORD gBlockDelay = 0; 03855 DWORD gBlockSleep = 0; 03856 #endif 03857 03858 VOID RawInputThread( 03859 PRIT_INIT pInitData) 03860 { 03861 KPRIORITY Priority; 03862 NTSTATUS Status; 03863 UNICODE_STRING strRIT; 03864 PKEVENT pEvent; 03865 UINT NumberOfHandles = ID_NUMBER_NON_HYDRA_HANDLES; 03866 PTERMINAL pTerm; 03867 PMONITOR pMonitorPrimary; 03868 HANDLE hevtShutDown; 03869 static DWORD nLastRetryReadInput = 0; 03870 03871 if (gbRemoteSession) { 03872 NumberOfHandles += 2; 03873 } 03874 03875 pTerm = pInitData->pTerm; 03876 03877 /* 03878 * Initialize GDI accelerators. Identify this thread as a server thread. 03879 */ 03880 apObjects = UserAllocPoolNonPaged(NumberOfHandles * sizeof(PVOID), TAG_SYSTEM); 03881 03882 gWaitBlockArray = UserAllocPoolNonPaged(NumberOfHandles * sizeof(KWAIT_BLOCK), 03883 TAG_SYSTEM); 03884 03885 if (apObjects == NULL || gWaitBlockArray == NULL) { 03886 RIPMSG0(RIP_WARNING, "RIT failed to allocate memory"); 03887 goto Exit; 03888 } 03889 03890 /* 03891 * Set the priority of the RIT to 19. 03892 */ 03893 Priority = LOW_REALTIME_PRIORITY + 3; 03894 03895 ZwSetInformationThread(NtCurrentThread(), 03896 ThreadPriority, 03897 &Priority, 03898 sizeof(KPRIORITY)); 03899 03900 RtlInitUnicodeString(&strRIT, L"WinSta0_RIT"); 03901 03902 /* 03903 * Create an event for signalling mouse/kbd attach/detach and device-change 03904 * notifications such as QueryRemove, RemoveCancelled etc. 03905 */ 03906 aDeviceTemplate[DEVICE_TYPE_KEYBOARD].pkeHidChange = 03907 apObjects[ID_HIDCHANGE] = 03908 CreateKernelEvent(SynchronizationEvent, FALSE); 03909 aDeviceTemplate[DEVICE_TYPE_MOUSE].pkeHidChange = 03910 CreateKernelEvent(SynchronizationEvent, FALSE); 03911 03912 /* 03913 * Create an event for desktop threads to pass mouse input to RIT 03914 */ 03915 apObjects[ID_MOUSE] = CreateKernelEvent(SynchronizationEvent, FALSE); 03916 gpkeMouseData = apObjects[ID_MOUSE]; 03917 03918 if (aDeviceTemplate[DEVICE_TYPE_MOUSE].pkeHidChange == NULL || 03919 apObjects[ID_HIDCHANGE] == NULL || 03920 gpkeMouseData == NULL) { 03921 RIPMSG0(RIP_WARNING, "RIT failed to create a required input event"); 03922 goto Exit; 03923 } 03924 03925 /* 03926 * Initialize keyboard device driver. 03927 */ 03928 EnterCrit(); 03929 InitKeyboard(); 03930 InitMice(); 03931 LeaveCrit(); 03932 03933 Status = InitSystemThread(&strRIT); 03934 03935 if (!NT_SUCCESS(Status)) { 03936 RIPMSG0(RIP_WARNING, "RIT failed InitSystemThread"); 03937 goto Exit; 03938 } 03939 03940 UserAssert(gpepCSRSS != NULL); 03941 03942 /* 03943 * Allow the system to read the screen 03944 */ 03945 ((PW32PROCESS)gpepCSRSS->Win32Process)->W32PF_Flags |= (W32PF_READSCREENACCESSGRANTED|W32PF_IOWINSTA); 03946 03947 /* 03948 * Initialize the cursor clipping rectangle to the screen rectangle. 03949 */ 03950 UserAssert(gpDispInfo != NULL); 03951 grcCursorClip = gpDispInfo->rcScreen; 03952 03953 /* 03954 * Initialize gpsi->ptCursor and gptCursorAsync 03955 */ 03956 pMonitorPrimary = GetPrimaryMonitor(); 03957 03958 UserAssert(gpsi != NULL); 03959 03960 gpsi->ptCursor.x = pMonitorPrimary->rcMonitor.right / 2; 03961 gpsi->ptCursor.y = pMonitorPrimary->rcMonitor.bottom / 2; 03962 gptCursorAsync = gpsi->ptCursor; 03963 03964 /* 03965 * The hung redraw list should already be set to NULL by the compiler, 03966 * linker & loader since it is an uninitialized global variable. Memory will 03967 * be allocated the first time a pwnd is added to this list (hungapp.c) 03968 */ 03969 UserAssert(gpvwplHungRedraw == NULL); 03970 03971 /* 03972 * Initialize the pre-defined hotkeys 03973 */ 03974 EnterCrit(); 03975 _RegisterHotKey(PWND_INPUTOWNER, IDHOT_WINDOWS, MOD_WIN, VK_NONE); 03976 SetDebugHotKeys(); 03977 LeaveCrit(); 03978 03979 /* 03980 * Create a timer for timers. 03981 */ 03982 gptmrMaster = UserAllocPoolNonPaged(sizeof(KTIMER), 03983 TAG_SYSTEM); 03984 if (gptmrMaster == NULL) { 03985 RIPMSG0(RIP_WARNING, "RIT failed to create gptmrMaster"); 03986 goto Exit; 03987 } 03988 03989 KeInitializeTimer(gptmrMaster); 03990 apObjects[ID_TIMER] = gptmrMaster; 03991 03992 /* 03993 * Create an event for mouse device reads to signal the desktop thread to 03994 * move the pointer and QueueMouseEvent(). 03995 * We should do this *before* we have any devices. 03996 */ 03997 UserAssert(gpDeviceInfoList == NULL); 03998 03999 if (gbRemoteSession) { 04000 04001 OBJECT_ATTRIBUTES obja; 04002 UNICODE_STRING ustrName; 04003 BOOL fSuccess = TRUE; 04004 WCHAR szName[MAX_SESSION_PATH]; 04005 04006 /* 04007 * Create and initialize a timer object 04008 * and pass a pointer to this object via the display driver to the WD. 04009 * The RIT will do a KeWaitForObject() on this timer object. 04010 * When the WD calls KeSetTimer() it will NOT specify a DPC routine. 04011 * When the timer goes off the RIT will get signaled and will make the 04012 * appropriate call to the display driver to flush the frame buffer. 04013 */ 04014 gptmrWD = UserAllocPoolNonPaged(sizeof(KTIMER), TAG_SYSTEM); 04015 04016 if (gptmrWD == NULL) { 04017 RIPMSG0(RIP_WARNING, "RIT failed to create gptmrWD"); 04018 goto Exit; 04019 } 04020 04021 KeInitializeTimerEx(gptmrWD, SynchronizationTimer); 04022 apObjects[ID_WDTIMER] = gptmrWD; 04023 04024 RtlInitUnicodeString(&ustrName, NULL); 04025 04026 /* 04027 * Pass a pointer to the timer to the WD via the display driver 04028 */ 04029 EnterCrit(); 04030 fSuccess &= !!HDXDrvEscape(gpDispInfo->hDev, 04031 ESC_SET_WD_TIMEROBJ, 04032 (PVOID)gptmrWD, 04033 sizeof(gptmrWD)); 04034 04035 fSuccess &= !!CreateDeviceInfo(DEVICE_TYPE_MOUSE, &ustrName, 0); 04036 fSuccess &= !!CreateDeviceInfo(DEVICE_TYPE_KEYBOARD, &ustrName, 0); 04037 04038 LeaveCrit(); 04039 04040 if (!fSuccess) { 04041 RIPMSG0(RIP_WARNING, 04042 "RIT failed HDXDrvEscape or the creation of input devices"); 04043 goto Exit; 04044 } 04045 04046 /* 04047 * Create the shutdown event. This event will be signaled 04048 * from W32WinStationTerminate. 04049 * This is a named event opend by CSR to signal that win32k should 04050 * go away. It's used in ntuser\server\api.c 04051 */ 04052 swprintf(szName, L"\\Sessions\\%ld\\BaseNamedObjects\\EventShutDownCSRSS", 04053 gSessionId); 04054 RtlInitUnicodeString(&ustrName, szName); 04055 04056 InitializeObjectAttributes(&obja, 04057 &ustrName, 04058 OBJ_CASE_INSENSITIVE, 04059 NULL, 04060 NULL); 04061 04062 Status = ZwCreateEvent(&hevtShutDown, 04063 EVENT_ALL_ACCESS, 04064 &obja, 04065 SynchronizationEvent, 04066 FALSE); 04067 04068 if (!NT_SUCCESS(Status)) { 04069 RIPMSG0(RIP_WARNING, "RIT failed to create EventShutDownCSRSS"); 04070 goto Exit; 04071 } 04072 04073 ObReferenceObjectByHandle(hevtShutDown, 04074 EVENT_ALL_ACCESS, 04075 *ExEventObjectType, 04076 KernelMode, 04077 &apObjects[ID_SHUTDOWN], 04078 NULL); 04079 } else { 04080 EnterCrit(); 04081 04082 /* 04083 * Register for Plug and Play devices. 04084 * If any PnP devices are already attached, these will be opened and 04085 * we will start reading them at this time. 04086 */ 04087 xxxRegisterForDeviceClassNotifications(); 04088 04089 LeaveCrit(); 04090 } 04091 04092 /* 04093 * Get the rit-thread. 04094 */ 04095 gptiRit = PtiCurrentShared(); 04096 04097 HYDRA_HINT(HH_RITCREATED); 04098 04099 /* 04100 * Don't allow this thread to get involved with journal synchronization. 04101 */ 04102 gptiRit->TIF_flags |= TIF_DONTJOURNALATTACH; 04103 04104 /* 04105 * Also wait on our input event so the cool switch window can 04106 * receive messages. 04107 */ 04108 apObjects[ID_INPUT] = gptiRit->pEventQueueServer; 04109 04110 /* 04111 * Signal that the rit has been initialized 04112 */ 04113 KeSetEvent(pInitData->pRitReadyEvent, EVENT_INCREMENT, FALSE); 04114 04115 /* 04116 * Since this is a SYSTEM-THREAD, we should set the pwinsta 04117 * pointer in the SystemInfoThread to assure that if any 04118 * paints occur from the input-thread, we can process them 04119 * in DoPaint(). 04120 * 04121 * Set the winsta after the first desktop is created. 04122 */ 04123 gptiRit->pwinsta = NULL; 04124 04125 pEvent = pTerm->pEventInputReady; 04126 04127 /* 04128 * Wait until the first desktop is created. 04129 */ 04130 ObReferenceObjectByPointer(pEvent, 04131 EVENT_ALL_ACCESS, 04132 *ExEventObjectType, 04133 KernelMode); 04134 04135 KeWaitForSingleObject(pEvent, WrUserRequest, KernelMode, FALSE, NULL); 04136 ObDereferenceObject(pEvent); 04137 04138 /* 04139 * Switch to the first desktop if no switch has been 04140 * performed. 04141 */ 04142 EnterCrit(); 04143 04144 if (gptiRit->rpdesk == NULL) { 04145 UserVerify(xxxSwitchDesktop(gptiRit->pwinsta, gptiRit->pwinsta->rpdeskList, FALSE)); 04146 } 04147 04148 /* 04149 * Create a timer for hung app detection/redrawing. 04150 */ 04151 StartTimers(); 04152 04153 LeaveCrit(); 04154 04155 /* 04156 * Go into a wait loop so we can process input events and APCs as 04157 * they occur. 04158 */ 04159 while (TRUE) { 04160 04161 CheckCritOut(); 04162 04163 Status = KeWaitForMultipleObjects(NumberOfHandles, 04164 apObjects, 04165 WaitAny, 04166 WrUserRequest, 04167 KernelMode, 04168 TRUE, 04169 NULL, 04170 gWaitBlockArray); 04171 04172 UserAssert(NT_SUCCESS(Status)); 04173 04174 if (gdwUpdateKeyboard != 0) { 04175 /* 04176 * Here's our opportunity to process pending IOCTLs for the kbds: 04177 * These are asynchronous IOCTLS, so be sure any buffers passed 04178 * in to ZwDeviceIoControlFile are not in the stack! 04179 * Using gdwUpdateKeyboard to tell the RIT to issue these IOCTLS 04180 * renders the action asynchronous (delayed until next apObjects 04181 * event), but the IOCTL was asynch anyway 04182 */ 04183 PDEVICEINFO pDeviceInfo; 04184 EnterDeviceInfoListCrit(); 04185 for (pDeviceInfo = gpDeviceInfoList; pDeviceInfo; pDeviceInfo = pDeviceInfo->pNext) { 04186 if ((pDeviceInfo->type == DEVICE_TYPE_KEYBOARD) && (pDeviceInfo->handle)) { 04187 if (gdwUpdateKeyboard & UPDATE_KBD_TYPEMATIC) { 04188 ZwDeviceIoControlFile(pDeviceInfo->handle, NULL, NULL, NULL, 04189 &giosbKbdControl, IOCTL_KEYBOARD_SET_TYPEMATIC, 04190 (PVOID)&gktp, sizeof(gktp), NULL, 0); 04191 } 04192 if (gdwUpdateKeyboard & UPDATE_KBD_LEDS) { 04193 ZwDeviceIoControlFile(pDeviceInfo->handle, NULL, NULL, NULL, 04194 &giosbKbdControl, IOCTL_KEYBOARD_SET_INDICATORS, 04195 (PVOID)&gklp, sizeof(gklp), NULL, 0); 04196 } 04197 } 04198 } 04199 LeaveDeviceInfoListCrit(); 04200 gdwUpdateKeyboard &= ~(UPDATE_KBD_TYPEMATIC | UPDATE_KBD_LEDS); 04201 } 04202 04203 if (Status == ID_MOUSE) { 04204 /* 04205 * A desktop thread got some Mouse input for us. Process it. 04206 */ 04207 ProcessQueuedMouseEvents(); 04208 04209 } else if (Status == ID_HIDCHANGE) { 04210 TAGMSG0(DBGTAG_PNP | RIP_THERESMORE, "RIT wakes for HID Change"); 04211 EnterCrit(); 04212 ProcessDeviceChanges(DEVICE_TYPE_KEYBOARD); 04213 LeaveCrit(); 04214 } else if (Status == ID_SHUTDOWN) { 04215 04216 InitiateWin32kCleanup(); 04217 04218 ZwClose(hevtShutDown); 04219 04220 break; 04221 04222 } else if (Status == ID_WDTIMER) { 04223 //LARGE_INTEGER liTemp; 04224 04225 EnterCrit(); 04226 04227 UserAssert(gbRemoteSession); 04228 04229 /* 04230 * Call the TShare display driver to flush the frame buffer 04231 */ 04232 04233 if (!HDXDrvEscape(gpDispInfo->hDev, ESC_TIMEROBJ_SIGNALED, NULL, 0)) { 04234 UserAssert(FALSE); 04235 } 04236 LeaveCrit(); 04237 04238 } else { 04239 /* 04240 * If the master timer has expired, then process the timer 04241 * list. Otherwise, an APC caused the raw input thread to be 04242 * awakened. 04243 */ 04244 if (Status == ID_TIMER) { 04245 TimersProc(); 04246 /* 04247 * If an input degvice read failed due to insufficient resources, 04248 * we retry by signalling the proper thread: ProcessDeviceChanges 04249 * will call RetryReadInput(). 04250 */ 04251 if (gnRetryReadInput != nLastRetryReadInput) { 04252 nLastRetryReadInput = gnRetryReadInput; 04253 KeSetEvent(aDeviceTemplate[DEVICE_TYPE_MOUSE].pkeHidChange, EVENT_INCREMENT, FALSE); 04254 KeSetEvent(aDeviceTemplate[DEVICE_TYPE_KEYBOARD].pkeHidChange, EVENT_INCREMENT, FALSE); 04255 } 04256 } 04257 04258 #if DBG 04259 /* 04260 * In the debugger set gBlockSleep to n: 04261 * The RIT will sleep n millicseconds, then n timer ticks later 04262 * will sleep n milliseconds again. 04263 */ 04264 if (gBlockDelay) { 04265 gBlockDelay--; 04266 } else if ((gBlockDelay == 0) && (gBlockSleep != 0)) { 04267 UserSleep(gBlockSleep); 04268 gBlockDelay = 100 * gBlockSleep; 04269 } 04270 #endif 04271 04272 /* 04273 * if in cool task switcher window, dispose of the messages 04274 * on the queue 04275 */ 04276 if (gspwndAltTab != NULL) { 04277 EnterCrit(); 04278 xxxReceiveMessages(gptiRit); 04279 LeaveCrit(); 04280 } 04281 } 04282 } 04283 04284 return; 04285 04286 Exit: 04287 04288 UserAssert(gptiRit == NULL); 04289 04290 /* 04291 * Signal that the rit has been initialized 04292 */ 04293 KeSetEvent(pInitData->pRitReadyEvent, EVENT_INCREMENT, FALSE); 04294 04295 RIPMSG0(RIP_WARNING, "RIT initialization failure"); 04296 return; 04297 }

Generated on Sat May 15 19:41:01 2004 for test by doxygen 1.3.7