|
|
/*++
Copyright (c) 2000 Microsoft Corporation. All rights reserved.
Module Name: digidev.cpp
Abstract: This module contains all the digitizer functions.
Author: Michael Tsang (MikeTs) 01-Jun-2000
Environment: User mode
Revision History: --*/
#include "pch.h"
/*++
@doc INTERNAL
@func BOOL | GetMinMax | Get the logical min & max for a report values.
@parm IN USAGE | UsagePage | Specifies the UsagePage of the report. @parm IN USAGE | Usage | Specifies the Usage of the report. @parm OUT PULONG | pulMin | To hold the min value. @parm OUT PULONG | pulMax | To hold the max value.
@rvalue SUCCESS | Returns TRUE. @rvalue FAILURE | Returns FALSE. --*/
BOOL GetMinMax( IN USAGE UsagePage, IN USAGE Usage, OUT PULONG pulMin, OUT PULONG pulMax ) { TRACEPROC("GetMinMax", 3) BOOL rc = FALSE; NTSTATUS status; HIDP_VALUE_CAPS ValueCaps; USHORT cValueCaps = 1;
TRACEENTER(("(UsagePage=%x,Usage=%x,pulMin=%p,pulMax=%p)\n", UsagePage, Usage, pulMin, pulMax));
status = HidP_GetSpecificValueCaps(HidP_Input, UsagePage, 0, Usage, &ValueCaps, &cValueCaps, gdevDigitizer.pPreParsedData);
if ((status == HIDP_STATUS_SUCCESS) && (cValueCaps == 1)) { if ((ValueCaps.LogicalMin >= 0) && (ValueCaps.LogicalMax > ValueCaps.LogicalMin)) { *pulMin = ValueCaps.LogicalMin; *pulMax = ValueCaps.LogicalMax; rc = TRUE; } }
TRACEEXIT(("=%x\n", rc)); return rc; } //GetMinMax
/*++
@doc INTERNAL
@func VOID | ProcessDigitizerReport | Process a digitizer input report.
@parm IN PCHAR | pBuff | Buffer containing report data.
@rvalue None. --*/
VOID ProcessDigitizerReport( IN PCHAR pBuff ) { TRACEPROC("ProcessDigitizerReport", 5) NTSTATUS StatusX, StatusY, StatusBtn; DWORD dwCurrentTime; ULONG x, y; ULONG ulLength;
TRACEENTER(("(pBuff=%p)\n", pBuff));
dwCurrentTime = GetTickCount(); StatusX = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_X, &x, gdevDigitizer.pPreParsedData, pBuff, gdevDigitizer.hidCaps.InputReportByteLength);
StatusY = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Y, &y, gdevDigitizer.pPreParsedData, pBuff, gdevDigitizer.hidCaps.InputReportByteLength);
ulLength = gdevDigitizer.dwcButtons;// ulLength == max # possible buttons
StatusBtn = HidP_GetButtons(HidP_Input, HID_USAGE_PAGE_DIGITIZER, 0, gdevDigitizer.pDownButtonUsages, &ulLength, gdevDigitizer.pPreParsedData, pBuff, gdevDigitizer.hidCaps.InputReportByteLength);
if ((StatusX == HIDP_STATUS_SUCCESS) && (StatusY == HIDP_STATUS_SUCCESS) && (StatusBtn == HIDP_STATUS_SUCCESS)) { ULONG i; WORD wCurrentButtons = 0;
for (i = 0; i < ulLength; i++) { if (gdevDigitizer.pDownButtonUsages[i] == HID_USAGE_DIGITIZER_TIP_SWITCH) { wCurrentButtons |= TIP_SWITCH; } else if (gdevDigitizer.pDownButtonUsages[i] == HID_USAGE_DIGITIZER_BARREL_SWITCH) { wCurrentButtons |= BARREL_SWITCH; } }
if ((gdwPenState == PENSTATE_PENDOWN) && (dwCurrentTime - gdwPenDownTime > (DWORD)gConfig.GestureSettings.iPressHoldTime)) { //
// PressHold timer has expired, simulate a right down.
//
PressHoldMode(TRUE); } else if ((gdwPenState == PENSTATE_PRESSHOLD) && (dwCurrentTime - gdwPenDownTime > (DWORD)gConfig.GestureSettings.iPressHoldTime + gConfig.GestureSettings.iCancelPressHoldTime)) { TRACEINFO(3, ("Simulate a left-down on CancelPressHold timeout.\n")); gdwPenState = PENSTATE_NORMAL; SetPressHoldCursor(FALSE); gInput.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE | SWAPBUTTONS(giButtonsSwapped, MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_RIGHTDOWN); gInput.mi.dx = glPenDownX; gInput.mi.dy = glPenDownY; SendInput(1, &gInput, sizeof(INPUT)); } else if ((gdwPenState == PENSTATE_LEFTUP_PENDING) && (dwCurrentTime - gdwPenUpTime > TIMEOUT_LEFTCLICK)) { //
// Left up timer has expired, simulate a left up.
//
TRACEINFO(3, ("Simulate a left-up on timeout.\n")); gdwPenState = PENSTATE_NORMAL; gInput.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE | SWAPBUTTONS(giButtonsSwapped, MOUSEEVENTF_LEFTUP, MOUSEEVENTF_RIGHTUP); gInput.mi.dx = glPenUpX; gInput.mi.dy = glPenUpY; SendInput(1, &gInput, sizeof(INPUT)); }
//
// If the report is the same as last, skip it.
//
if ((x != gLastRawDigiReport.wX) || (y != gLastRawDigiReport.wY) || (wCurrentButtons != gLastRawDigiReport.wButtonState)) { //
// Generate mouse movement info.
//
if (gdwfTabSrv & TSF_HAS_LINEAR_MAP) { gInput.mi.dx = x; gInput.mi.dy = y; AdjustLinearity((PUSHORT)&gInput.mi.dx, (PUSHORT)&gInput.mi.dy); } else { ULONG t;
// Since we treat the digitizer as an 'absolute' pointing
// device, both the X/Y coordinates must be scaled to a range
// of 0 - 65535.
// (((t = x - gdwMinX) << 16) - t) == ((x - gdwMinX) * 65535)
// In non-raw mode, the pen driver should already be scaled to
// the range of 0-65535, but in raw mode, we still have to do
// this work.
gInput.mi.dx = (x >= gdwMaxX)? MAX_NORMALIZED_X: // too high
((x <= gdwMinX)? 0: // too low
((((t = x - gdwMinX) << 16) - t) / gdwRngX));
gInput.mi.dy = (y >= gdwMaxY)? MAX_NORMALIZED_Y : // too high
((y <= gdwMinY)? 0: // too low
((((t = y - gdwMinY) << 16) - t) / gdwRngY)); }
gInput.mi.dx = (((gInput.mi.dx > glLongOffset)? gInput.mi.dx - glLongOffset: 0)*NUM_PIXELS_LONG)/ max(gcxPrimary, gcyPrimary); gInput.mi.dy = (((gInput.mi.dy > glShortOffset)? gInput.mi.dy - glShortOffset: 0)*NUM_PIXELS_SHORT)/ min(gcxPrimary, gcyPrimary);
if (gdwfTabSrv & TSF_PORTRAIT_MODE) { LONG temp;
if (gdwfTabSrv & TSF_PORTRAIT_MODE2) { temp = gInput.mi.dx; gInput.mi.dx = MAX_NORMALIZED_Y - gInput.mi.dy; } else { temp = MAX_NORMALIZED_X - gInput.mi.dx; gInput.mi.dx = gInput.mi.dy; } gInput.mi.dy = temp; }
//
// Pen tilt compensation.
//
gInput.mi.dx += gConfig.PenTilt.dx; gInput.mi.dy += gConfig.PenTilt.dy;
NotifyClient(RawPtEvent, wCurrentButtons, (y << 16) | (x & 0xffff));
ProcessMouseEvent(gInput.mi.dx, gInput.mi.dy, wCurrentButtons, dwCurrentTime, FALSE);
#ifdef DRAW_INK
if (ghwndDrawInk != NULL) { static BOOL fPenDown = FALSE; static POINT ptPrev = {0, 0}; static HPEN hpen = NULL; HDC hdc;
if (!(gwLastButtons & TIP_SWITCH) && (wCurrentButtons & TIP_SWITCH)) { hpen = CreatePen(PS_SOLID, 0, RGB(255, 255, 255)); fPenDown = TRUE; ptPrev.x = NORMAL_TO_SCREEN_X(gInput.mi.dx); ptPrev.y = NORMAL_TO_SCREEN_Y(gInput.mi.dy); } else if ((gwLastButtons & TIP_SWITCH) && !(wCurrentButtons & TIP_SWITCH)) { DeleteObject(hpen); hpen = NULL; fPenDown = FALSE; } else if (fPenDown) { HPEN hpenOld; POINT pt;
pt.x = NORMAL_TO_SCREEN_X(gInput.mi.dx); pt.y = NORMAL_TO_SCREEN_Y(gInput.mi.dy); hdc = GetDC(ghwndDrawInk); hpenOld = (HPEN)SelectObject(hdc, hpen); MoveToEx(hdc, ptPrev.x, ptPrev.y, NULL); LineTo(hdc, pt.x, pt.y); SelectObject(hdc, hpenOld); ReleaseDC(ghwndDrawInk, hdc); ptPrev = pt; } } #endif
gwLastButtons = wCurrentButtons; gLastRawDigiReport.wX = (WORD)x; gLastRawDigiReport.wY = (WORD)y; gLastRawDigiReport.wButtonState = wCurrentButtons; gLastRawDigiReport.dwTime = dwCurrentTime; } } else { TABSRVERR(("failed getting data (StatusX=%d,StatusY=%d,StatusBtn=%d,Len=%d)\n", StatusX, StatusY, StatusBtn, ulLength)); }
TRACEEXIT(("!\n")); return; } //ProcessDigitizerReport
/*++
@doc INTERNAL
@func VOID | AdjustLinearity | Adjust data according to the linearity map.
@parm IN OUT PUSHORT | pwX | Points to the X data. @parm IN OUT PUSHORT | pwY | Points to the Y data.
@rvalue None. --*/
VOID AdjustLinearity( IN OUT PUSHORT pwX, IN OUT PUSHORT pwY ) { TRACEPROC("AdjustLinearity", 5) int ix, iy, dix, diy, n; DIGIRECT Rect; LONG x, y;
TRACEENTER(("(x=%d,y=%d)\n", *pwX, *pwY));
for (n = 0, ix = gixIndex, iy = giyIndex; ; ix += dix, iy += diy, n++) { //
// Safe guard from never-ending loop.
//
TRACEASSERT(n <= NUM_LINEAR_XPTS + NUM_LINEAR_YPTS); if (n > NUM_LINEAR_XPTS + NUM_LINEAR_YPTS) { TABSRVERR(("AdjustLinearity caught in a loop.\n")); break; }
if ((*pwX < gConfig.LinearityMap.Data[iy][ix].wDigiPtX) && (*pwX < gConfig.LinearityMap.Data[iy+1][ix].wDigiPtX)) { dix = ix? -1: 0; } else if ((*pwX >= gConfig.LinearityMap.Data[iy][ix+1].wDigiPtX) && (*pwX >= gConfig.LinearityMap.Data[iy+1][ix+1].wDigiPtX)) { dix = (ix + 2 < NUM_LINEAR_XPTS)? 1: 0; } else { dix = 0; }
if ((*pwY < gConfig.LinearityMap.Data[iy][ix].wDigiPtY) && (*pwY < gConfig.LinearityMap.Data[iy][ix+1].wDigiPtY)) { diy = iy? -1: 0; } else if ((*pwY >= gConfig.LinearityMap.Data[iy+1][ix].wDigiPtY) && (*pwY >= gConfig.LinearityMap.Data[iy+1][ix+1].wDigiPtY)) { diy = (iy + 2 < NUM_LINEAR_YPTS)? 1: 0; } else { diy = 0; } //
// If delta-X and delta-Y are both zeros, we found the containing
// rectangle.
//
if ((dix == 0) && (diy == 0)) { break; } }
TRACEASSERT(gConfig.LinearityMap.Data[iy+1][ix].wDigiPtY - gConfig.LinearityMap.Data[iy][ix].wDigiPtY); TRACEASSERT(gConfig.LinearityMap.Data[iy+1][ix+1].wDigiPtY - gConfig.LinearityMap.Data[iy][ix+1].wDigiPtY); Rect.wx0 = gConfig.LinearityMap.Data[iy][ix].wDigiPtX + ((*pwY - gConfig.LinearityMap.Data[iy][ix].wDigiPtY)* (gConfig.LinearityMap.Data[iy+1][ix].wDigiPtX - gConfig.LinearityMap.Data[iy][ix].wDigiPtX))/ (gConfig.LinearityMap.Data[iy+1][ix].wDigiPtY - gConfig.LinearityMap.Data[iy][ix].wDigiPtY); Rect.wx1 = gConfig.LinearityMap.Data[iy][ix+1].wDigiPtX + ((*pwY - gConfig.LinearityMap.Data[iy][ix+1].wDigiPtY)* (gConfig.LinearityMap.Data[iy+1][ix+1].wDigiPtX - gConfig.LinearityMap.Data[iy][ix+1].wDigiPtX))/ (gConfig.LinearityMap.Data[iy+1][ix+1].wDigiPtY - gConfig.LinearityMap.Data[iy][ix+1].wDigiPtY);
TRACEASSERT(gConfig.LinearityMap.Data[iy][ix+1].wDigiPtX - gConfig.LinearityMap.Data[iy][ix].wDigiPtX); TRACEASSERT(gConfig.LinearityMap.Data[iy+1][ix+1].wDigiPtX - gConfig.LinearityMap.Data[iy+1][ix].wDigiPtX); Rect.wy0 = gConfig.LinearityMap.Data[iy][ix].wDigiPtY + ((*pwX - gConfig.LinearityMap.Data[iy][ix].wDigiPtX)* (gConfig.LinearityMap.Data[iy][ix+1].wDigiPtY - gConfig.LinearityMap.Data[iy][ix].wDigiPtY))/ (gConfig.LinearityMap.Data[iy][ix+1].wDigiPtX - gConfig.LinearityMap.Data[iy][ix].wDigiPtX); Rect.wy1 = gConfig.LinearityMap.Data[iy+1][ix].wDigiPtY + ((*pwX - gConfig.LinearityMap.Data[iy+1][ix].wDigiPtX)* (gConfig.LinearityMap.Data[iy+1][ix+1].wDigiPtY - gConfig.LinearityMap.Data[iy+1][ix].wDigiPtY))/ (gConfig.LinearityMap.Data[iy+1][ix+1].wDigiPtX - gConfig.LinearityMap.Data[iy+1][ix].wDigiPtX);
//
// Remember the upper-left corner of the containing rectangle so that
// we will start with this rectangle the next time.
//
gixIndex = ix; giyIndex = iy;
//
// Calculate the adjustment:
// x = x0Ref + (xDigi - x0Digi)*(x1Ref - x0Ref)/(x1Digi - x0Digi)
// y = y0Ref + (yDigi - y0Digi)*(y1Ref - y0Ref)/(y1Digi - y1Digi)
//
TRACEASSERT((Rect.wx1 - Rect.wx0) != 0); TRACEASSERT((Rect.wy1 - Rect.wy0) != 0); x = gConfig.LinearityMap.Data[iy][ix].wRefPtX + ((*pwX - Rect.wx0)* (gConfig.LinearityMap.Data[iy][ix + 1].wRefPtX - gConfig.LinearityMap.Data[iy][ix].wRefPtX))/ (Rect.wx1 - Rect.wx0); *pwX = (USHORT)((x < 0)? 0: (x > MAX_NORMALIZED_X)? MAX_NORMALIZED_X: x); y = gConfig.LinearityMap.Data[iy][ix].wRefPtY + ((*pwY - Rect.wy0)* (gConfig.LinearityMap.Data[iy + 1][ix].wRefPtY - gConfig.LinearityMap.Data[iy][ix].wRefPtY))/ (Rect.wy1 - Rect.wy0); *pwY = (USHORT)((y < 0)? 0: (y > MAX_NORMALIZED_Y)? MAX_NORMALIZED_Y: y);
TRACEEXIT(("!(x=%d,y=%d)\n", *pwX, *pwY)); return; } //AdjustLinearity
/*++
@doc INTERNAL
@func LRESULT | ProcessMouseEvent | Process the mouse event.
@parm IN LONG | x | Current X. @parm IN LONG | y | Current Y. @parm IN WORD | wButtons | Current buttons state. @parm IN DWORD | dwTime | Current time. @parm IN BOOL | fLowLevelMouse | TRUE if called by LowLevelMouseProc.
@rvalue SUCCESS | Returns non-zero to eat the mouse event. @rvalue FAILURE | Returns 0 to pass along the event to next handler. --*/
LRESULT ProcessMouseEvent( IN LONG x, IN LONG y, IN WORD wButtons, IN DWORD dwTime, IN BOOL fLowLevelMouse ) { TRACEPROC("ProcessMouseEvent", 5) LRESULT rc = 0; DWORD dwEvent;
TRACEENTER(("(x=%d,y=%d,Buttons=%x,Time=%d,fLLMouse=%x)\n", x, y, wButtons, dwTime, fLowLevelMouse));
gInput.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; if (fLowLevelMouse) { gInput.mi.dwFlags |= MOUSEEVENTF_VIRTUALDESK; }
// Has the tip switch changed state?
if (((gwLastButtons ^ wButtons) & TIP_SWITCH) != 0) { if (wButtons & TIP_SWITCH) { //
// Tip switch is down.
//
if (gdwPenState == PENSTATE_LEFTUP_PENDING) { if (fLowLevelMouse) { KillTimer(ghwndMouse, TIMERID_PRESSHOLD); } TRACEINFO(3, ("Simulate a left up on pen down.\n")); gdwPenState = PENSTATE_NORMAL; dwEvent = SWAPBUTTONS(giButtonsSwapped, MOUSEEVENTF_LEFTUP, MOUSEEVENTF_RIGHTUP); gInput.mi.dwFlags |= dwEvent; gInput.mi.dx = glPenUpX; gInput.mi.dy = glPenUpY; SendInput(1, &gInput, sizeof(INPUT)); gInput.mi.dwFlags &= ~dwEvent; gInput.mi.dx = x; gInput.mi.dy = y; }
if (gConfig.GestureSettings.dwfFeatures & GESTURE_FEATURE_PRESSHOLD_ENABLED) { if (CanDoPressHold(x, y)) { TRACEINFO(3, ("Pendown.\n")); //
// Press and Hold is enabled, so hold back the left down event.
//
gdwPenDownTime = dwTime; glPenDownX = x; glPenDownY = y; gdwPenState = PENSTATE_PENDOWN; if (fLowLevelMouse) { SetTimer(ghwndMouse, TIMERID_PRESSHOLD, gConfig.GestureSettings.iPressHoldTime, NULL); } rc = 1; } else { gInput.mi.dwFlags |= SWAPBUTTONS(giButtonsSwapped, MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_RIGHTDOWN); } } else { gInput.mi.dwFlags |= SWAPBUTTONS(giButtonsSwapped, MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_RIGHTDOWN); } } else { //
// Tip switch is up.
//
if (gdwPenState == PENSTATE_PENDOWN) { //
// If we still have pendown pending, it means presshold timer
// has not expired, so we must cancel pendown pending and
// simulate a left click.
//
TRACEINFO(3, ("Simulate a left-down.\n")); if (fLowLevelMouse) { KillTimer(ghwndMouse, TIMERID_PRESSHOLD); } gdwPenState = PENSTATE_LEFTUP_PENDING;
//
// Simulate a left down.
//
gInput.mi.dwFlags |= SWAPBUTTONS(giButtonsSwapped, MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_RIGHTDOWN); gInput.mi.dx = glPenDownX; gInput.mi.dy = glPenDownY; SendInput(1, &gInput, sizeof(INPUT));
gdwPenUpTime = dwTime; glPenUpX = x; glPenUpY = y; rc = 1;
if (fLowLevelMouse) { SetTimer(ghwndMouse, TIMERID_PRESSHOLD, TIMEOUT_LEFTCLICK, NULL); } } else if ((gdwPenState == PENSTATE_PRESSHOLD) || (gdwPenState == PENSTATE_RIGHTDRAG)) { if (gdwPenState == PENSTATE_PRESSHOLD) { TRACEINFO(3, ("Simulate a right click.\n")); SetPressHoldCursor(FALSE); dwEvent = SWAPBUTTONS(giButtonsSwapped, MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_LEFTDOWN); gInput.mi.dwFlags |= dwEvent; gInput.mi.dx = glPenDownX; gInput.mi.dy = glPenDownY; SendInput(1, &gInput, sizeof(INPUT));
gInput.mi.dwFlags &= ~dwEvent; gInput.mi.dx = x; gInput.mi.dy = y; } else { TRACEINFO(3, ("Simulate a right up.\n")); }
gInput.mi.dwFlags |= SWAPBUTTONS(giButtonsSwapped, MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_LEFTUP); if (fLowLevelMouse) { SendInput(1, &gInput, sizeof(INPUT)); rc = 1; } PressHoldMode(FALSE); } else { TRACEINFO(3, ("Do a left up.\n")); gInput.mi.dwFlags |= SWAPBUTTONS(giButtonsSwapped, MOUSEEVENTF_LEFTUP, MOUSEEVENTF_RIGHTUP); } } } else if (gdwPenState == PENSTATE_PENDOWN) { int cxScreen = fLowLevelMouse? gcxScreen: gcxPrimary, cyScreen = fLowLevelMouse? gcyScreen: gcyPrimary;
if ((((abs(x - glPenDownX)*cxScreen) >> 16) > gConfig.GestureSettings.iHoldTolerance) || (((abs(y - glPenDownY)*cyScreen) >> 16) > gConfig.GestureSettings.iHoldTolerance)) { TRACEINFO(3, ("Cancel pen down pending, simulate a left down.\n")); if (fLowLevelMouse) { KillTimer(ghwndMouse, 1); } gdwPenState = PENSTATE_NORMAL; dwEvent = SWAPBUTTONS(giButtonsSwapped, MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_RIGHTDOWN); gInput.mi.dwFlags |= dwEvent; gInput.mi.dx = glPenDownX; gInput.mi.dy = glPenDownY; SendInput(1, &gInput, sizeof(INPUT)); gInput.mi.dwFlags &= ~dwEvent;
gInput.mi.dx = x; gInput.mi.dy = y; } } else if (gdwPenState == PENSTATE_PRESSHOLD) { int cxScreen = fLowLevelMouse? gcxScreen: gcxPrimary, cyScreen = fLowLevelMouse? gcyScreen: gcyPrimary;
if ((((abs(x - glPenDownX)*cxScreen) >> 16) > gConfig.GestureSettings.iHoldTolerance) || (((abs(y - glPenDownY)*cyScreen) >> 16) > gConfig.GestureSettings.iHoldTolerance)) { KillTimer(ghwndMouse, TIMERID_PRESSHOLD); TRACEINFO(3, ("Simulate a right drag.\n")); SetPressHoldCursor(FALSE); gdwPenState = PENSTATE_RIGHTDRAG;
dwEvent = SWAPBUTTONS(giButtonsSwapped, MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_LEFTDOWN); gInput.mi.dwFlags |= dwEvent; gInput.mi.dx = glPenDownX; gInput.mi.dy = glPenDownY; SendInput(1, &gInput, sizeof(INPUT)); gInput.mi.dwFlags &= ~dwEvent;
gInput.mi.dx = x; gInput.mi.dy = y; } } else if (gdwPenState == PENSTATE_LEFTUP_PENDING) { //
// Eat any movement before left-up timer expires.
//
rc = 1; }
if (gConfig.GestureSettings.dwfFeatures & GESTURE_FEATURE_RECOG_ENABLED) { RecognizeGesture(gInput.mi.dx, gInput.mi.dy, wButtons, dwTime, fLowLevelMouse); }
if (gdwfTabSrv & TSF_SUPERTIP_SENDINK) { LONG x, y;
x = NORMAL_TO_SCREEN_X(gInput.mi.dx); y = NORMAL_TO_SCREEN_Y(gInput.mi.dy); PostMessage(ghwndSuperTIPInk, guimsgSuperTIPInk, gInput.mi.dwFlags, (LPARAM)((y << 16) | (x & 0xffff))); if (gInput.mi.dwFlags & MOUSEEVENTF_LEFTUP) { gdwfTabSrv &= ~TSF_SUPERTIP_SENDINK; } rc = 1; } else if (!fLowLevelMouse && (rc == 0)) { // Convert digitizer input to mouse input
SendInput(1, &gInput, sizeof(INPUT)); }
TRACEEXIT(("=%x\n", rc)); return rc; } //ProcessMouseEvent
/*++
@doc INTERNAL
@func VOID | PressHoldMode | Enable or disable Press and Hold mode.
@parm IN BOOL | fEnable | TRUE if entering Press and Hold mode.
@rvalue None. --*/
VOID PressHoldMode( IN BOOL fEnable ) { TRACEPROC("PressHold", 3) TRACEENTER(("(fEnable=%x)\n", fEnable));
if (fEnable) { TRACEINFO(3, ("Entering Press and Hold mode.\n"));
SetPressHoldCursor(TRUE); gdwPenState = PENSTATE_PRESSHOLD; } else { TRACEINFO(3, ("Exiting Press and Hold mode.\n")); gdwPenState = PENSTATE_NORMAL; }
TRACEEXIT(("!\n")); return; } //PressHoldMode
/*++
@doc INTERNAL
@func VOID | SetPressHoldCursor | Set Press and Hold cursor.
@parm IN BOOL | fPressHold | TRUE to set press and hold cursor.
@rvalue None. --*/
VOID SetPressHoldCursor( IN BOOL fPressHold ) { TRACEPROC("SetPressHoldCursor", 3) // BOOL rc = FALSE;
// static HCURSOR hcurPrev = NULL;
static POINT pt = {0, 0}; HDC hDC; HRGN hrgn;
TRACEENTER(("(fPressHold=%x)\n", fPressHold));
if (fPressHold) { GetCursorPos(&pt); }
hDC = GetDC(NULL); TRACEASSERT(hDC != NULL); if (hDC != NULL) { hrgn = CreateEllipticRgn(pt.x - 10, pt.y - 10, pt.x + 10, pt.y + 10); TRACEASSERT(hrgn != NULL); if (hrgn != NULL) { InvertRgn(hDC, hrgn); DeleteObject(hrgn); } ReleaseDC(NULL, hDC); }
#if 0
if (fPressHold) { #if 0
hcurPrev = (HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(OCR_NORMAL), IMAGE_CURSOR, 0, 0, LR_SHARED | LR_DEFAULTSIZE); TRACEASSERT(hcurPrev != NULL); #endif
rc = SetSystemCursor(CopyCursor(ghcurPressHold), OCR_NORMAL); TRACEASSERT(rc == TRUE); } else { #if 0
if (hcurPrev != NULL) { SetCursor(hcurPrev); rc = SetSystemCursor(CopyCursor(hcurPrev), OCR_NORMAL); TRACEASSERT(rc == TRUE); hcurPrev = NULL; } else { TABSRVERR(("Failed to restore normal cursor (err=%d.\n", GetLastError())); } #endif
//#if 0
LONG rcReg; HKEY hkUser, hkey; HCURSOR hcursor = NULL;
rcReg = RegOpenCurrentUser(KEY_READ, &hkUser); if (rcReg == ERROR_SUCCESS) { rcReg = RegOpenKey(hkUser, REGSTR_PATH_CURSORS, &hkey); if (rcReg == ERROR_SUCCESS) { TCHAR szFile[MAX_PATH]; DWORD dwcb = sizeof(szFile);
rcReg = RegQueryValueEx(hkey, TEXT("Arrow"), NULL, NULL, (LPBYTE)szFile, &dwcb); if (rcReg == ERROR_SUCCESS) { TRACEINFO(1, ("CursorArrow=%s\n", szFile)); hcursor = (HCURSOR)LoadImage(NULL, MakeFileName(szFile), IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE); } else { TRACEWARN(("Failed to read Arrow registry value (rcReg=%x)\n", rcReg)); } RegCloseKey(hkey); } else { TRACEWARN(("Failed to open cursor registry key (rcReg=%x).\n", rcReg)); } RegCloseKey(hkUser); } else { TRACEWARN(("Failed to open current user (rcReg=%x).\n", rcReg)); }
if (hcursor == NULL) { hcursor = CopyCursor(ghcurNormal); }
TRACEASSERT(hcursor != NULL); if (hcursor != NULL) { rc = SetSystemCursor(hcursor, OCR_NORMAL); } else { TABSRVERR(("Failed to restore system cursor.\n")); } //#endif
} #endif
TRACEEXIT(("!\n")); return; } //SetPressHoldCursor
/*++
@doc INTERNAL
@func LPTSTR | MakeFileName | Make a valid path by doing environment substitution.
@parm IN OUT LPTSTR | szFile | Points to the file name string.
@rvalue returns szFile. --*/
LPTSTR MakeFileName( IN OUT LPTSTR pszFile ) { TRACEPROC("MakeFileName", 3) TCHAR szTmp[MAX_PATH];
TRACEENTER(("(File=%s)\n", pszFile));
ExpandEnvironmentStrings(pszFile, szTmp, ARRAYSIZE(szTmp)); if ((szTmp[0] == TEXT('\\')) || (szTmp[1] == TEXT(':'))) { lstrcpy(pszFile, szTmp); } else { GetSystemDirectory(pszFile, MAX_PATH); lstrcat(pszFile, TEXT("\\")); lstrcat(pszFile, szTmp); }
TRACEEXIT(("! (File=%s)\n", pszFile)); return pszFile; } //MakeFileName
/*++
@doc INTERNAL
@func BOOL | CanDoPressHold | Check if we can do press and hold.
@parm IN LONG | x | Cursor X. @parm IN LONG | y | Cursor Y.
@rvalue SUCCESS | Returns TRUE. @rvalue FAILURE | Returns FALSE. --*/
BOOL CanDoPressHold( IN LONG x, IN LONG y ) { TRACEPROC("CanDoPressHold", 3) BOOL rc = TRUE;
TRACEENTER(("(x=%d,y=%d)\n", x, y));
if (gpISuperTip != NULL) { __try { TIP_HIT_TEST_TYPE HitType; POINT pt;
pt.x = NORMAL_TO_SCREEN_X(x); pt.y = NORMAL_TO_SCREEN_Y(y);
if (SUCCEEDED(gpISuperTip->HitTest(pt, &HitType)) && (HitType != TIP_HT_NONE) && (HitType != TIP_HT_STAGE)) { TRACEINFO(3, ("Cursor is on HitType=%x\n", HitType)); rc = FALSE; if ((HitType == TIP_HT_INK_AREA) && (ghwndSuperTIPInk != NULL)) { gdwfTabSrv |= TSF_SUPERTIP_SENDINK; } } } __except(EXCEPTION_EXECUTE_HANDLER) { TABSRVERR(("Exception in SuperTIP HitTest (%x).\n", _exception_code())); } }
TRACEEXIT(("=%x\n", rc)); return rc; } //CanDoPressHold
|