test: ntinput.c Source File

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 }