winmouse.c revision 6747b715
105b261ecSmrg/* 205b261ecSmrg *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. 305b261ecSmrg * 405b261ecSmrg *Permission is hereby granted, free of charge, to any person obtaining 505b261ecSmrg * a copy of this software and associated documentation files (the 605b261ecSmrg *"Software"), to deal in the Software without restriction, including 705b261ecSmrg *without limitation the rights to use, copy, modify, merge, publish, 805b261ecSmrg *distribute, sublicense, and/or sell copies of the Software, and to 905b261ecSmrg *permit persons to whom the Software is furnished to do so, subject to 1005b261ecSmrg *the following conditions: 1105b261ecSmrg * 1205b261ecSmrg *The above copyright notice and this permission notice shall be 1305b261ecSmrg *included in all copies or substantial portions of the Software. 1405b261ecSmrg * 1505b261ecSmrg *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1605b261ecSmrg *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1705b261ecSmrg *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 1805b261ecSmrg *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR 1905b261ecSmrg *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 2005b261ecSmrg *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 2105b261ecSmrg *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2205b261ecSmrg * 2305b261ecSmrg *Except as contained in this notice, the name of the XFree86 Project 2405b261ecSmrg *shall not be used in advertising or otherwise to promote the sale, use 2505b261ecSmrg *or other dealings in this Software without prior written authorization 2605b261ecSmrg *from the XFree86 Project. 2705b261ecSmrg * 2805b261ecSmrg * Authors: Dakshinamurthy Karra 2905b261ecSmrg * Suhaib M Siddiqi 3005b261ecSmrg * Peter Busch 3105b261ecSmrg * Harold L Hunt II 3205b261ecSmrg */ 3305b261ecSmrg 3405b261ecSmrg#ifdef HAVE_XWIN_CONFIG_H 3505b261ecSmrg#include <xwin-config.h> 3605b261ecSmrg#endif 3705b261ecSmrg#include "win.h" 3805b261ecSmrg 394642e01fSmrg#if defined(XFree86Server) 4005b261ecSmrg#include "inputstr.h" 416747b715Smrg#include "exevents.h" /* for button/axes labels */ 426747b715Smrg#include "xserver-properties.h" 4305b261ecSmrg 4405b261ecSmrg/* Peek the internal button mapping */ 4505b261ecSmrgstatic CARD8 const *g_winMouseButtonMap = NULL; 4605b261ecSmrg#endif 4705b261ecSmrg 4805b261ecSmrg 4905b261ecSmrg/* 5005b261ecSmrg * Local prototypes 5105b261ecSmrg */ 5205b261ecSmrg 5305b261ecSmrgstatic void 5405b261ecSmrgwinMouseCtrl (DeviceIntPtr pDevice, PtrCtrl *pCtrl); 5505b261ecSmrg 5605b261ecSmrg 5705b261ecSmrgstatic void 5805b261ecSmrgwinMouseCtrl (DeviceIntPtr pDevice, PtrCtrl *pCtrl) 5905b261ecSmrg{ 6005b261ecSmrg} 6105b261ecSmrg 6205b261ecSmrg 6305b261ecSmrg/* 6405b261ecSmrg * See Porting Layer Definition - p. 18 6505b261ecSmrg * This is known as a DeviceProc 6605b261ecSmrg */ 6705b261ecSmrg 6805b261ecSmrgint 6905b261ecSmrgwinMouseProc (DeviceIntPtr pDeviceInt, int iState) 7005b261ecSmrg{ 7105b261ecSmrg int lngMouseButtons, i; 7205b261ecSmrg int lngWheelEvents = 2; 7305b261ecSmrg CARD8 *map; 7405b261ecSmrg DevicePtr pDevice = (DevicePtr) pDeviceInt; 756747b715Smrg Atom *btn_labels; 766747b715Smrg Atom axes_labels[2]; 7705b261ecSmrg 7805b261ecSmrg switch (iState) 7905b261ecSmrg { 8005b261ecSmrg case DEVICE_INIT: 8105b261ecSmrg /* Get number of mouse buttons */ 8205b261ecSmrg lngMouseButtons = GetSystemMetrics(SM_CMOUSEBUTTONS); 8305b261ecSmrg 8405b261ecSmrg /* Mapping of windows events to X events: 8505b261ecSmrg * LEFT:1 MIDDLE:2 RIGHT:3 8605b261ecSmrg * SCROLL_UP:4 SCROLL_DOWN:5 8705b261ecSmrg * XBUTTON 1:6 XBUTTON 2:7 ... 8805b261ecSmrg * 8905b261ecSmrg * To map scroll wheel correctly we need at least the 3 normal buttons 9005b261ecSmrg */ 9105b261ecSmrg if (lngMouseButtons < 3) 9205b261ecSmrg lngMouseButtons = 3; 9305b261ecSmrg winMsg(X_PROBED, "%d mouse buttons found\n", lngMouseButtons); 9405b261ecSmrg 9505b261ecSmrg /* allocate memory: 9605b261ecSmrg * number of buttons + 2x mouse wheel event + 1 extra (offset for map) 9705b261ecSmrg */ 9805b261ecSmrg map = malloc(sizeof(CARD8) * (lngMouseButtons + lngWheelEvents + 1)); 9905b261ecSmrg 10005b261ecSmrg /* initalize button map */ 10105b261ecSmrg map[0] = 0; 10205b261ecSmrg for (i=1; i <= lngMouseButtons + lngWheelEvents; i++) 10305b261ecSmrg map[i] = i; 1046747b715Smrg 1056747b715Smrg btn_labels = calloc((lngMouseButtons + lngWheelEvents), sizeof(Atom)); 1066747b715Smrg btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); 1076747b715Smrg btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); 1086747b715Smrg btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); 1096747b715Smrg btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP); 1106747b715Smrg btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); 1116747b715Smrg 1126747b715Smrg axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); 1136747b715Smrg axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); 1146747b715Smrg 11505b261ecSmrg InitPointerDeviceStruct (pDevice, 11605b261ecSmrg map, 11705b261ecSmrg lngMouseButtons + lngWheelEvents, 1186747b715Smrg btn_labels, 11905b261ecSmrg winMouseCtrl, 12005b261ecSmrg GetMotionHistorySize(), 1216747b715Smrg 2, 1226747b715Smrg axes_labels); 12305b261ecSmrg free(map); 1246747b715Smrg free(btn_labels); 12505b261ecSmrg 1264642e01fSmrg#if defined(XFree86Server) 12705b261ecSmrg g_winMouseButtonMap = pDeviceInt->button->map; 12805b261ecSmrg#endif 12905b261ecSmrg break; 13005b261ecSmrg 13105b261ecSmrg case DEVICE_ON: 13205b261ecSmrg pDevice->on = TRUE; 13305b261ecSmrg break; 13405b261ecSmrg 13505b261ecSmrg case DEVICE_CLOSE: 1364642e01fSmrg#if defined(XFree86Server) 13705b261ecSmrg g_winMouseButtonMap = NULL; 13805b261ecSmrg#endif 13905b261ecSmrg case DEVICE_OFF: 14005b261ecSmrg pDevice->on = FALSE; 14105b261ecSmrg break; 14205b261ecSmrg } 14305b261ecSmrg return Success; 14405b261ecSmrg} 14505b261ecSmrg 14605b261ecSmrg 14705b261ecSmrg/* Handle the mouse wheel */ 14805b261ecSmrgint 14905b261ecSmrgwinMouseWheel (ScreenPtr pScreen, int iDeltaZ) 15005b261ecSmrg{ 15105b261ecSmrg winScreenPriv(pScreen); 15205b261ecSmrg int button; /* Button4 or Button5 */ 15305b261ecSmrg 15405b261ecSmrg /* Button4 = WheelUp */ 15505b261ecSmrg /* Button5 = WheelDown */ 15605b261ecSmrg 15705b261ecSmrg /* Do we have any previous delta stored? */ 15805b261ecSmrg if ((pScreenPriv->iDeltaZ > 0 15905b261ecSmrg && iDeltaZ > 0) 16005b261ecSmrg || (pScreenPriv->iDeltaZ < 0 16105b261ecSmrg && iDeltaZ < 0)) 16205b261ecSmrg { 16305b261ecSmrg /* Previous delta and of same sign as current delta */ 16405b261ecSmrg iDeltaZ += pScreenPriv->iDeltaZ; 16505b261ecSmrg pScreenPriv->iDeltaZ = 0; 16605b261ecSmrg } 16705b261ecSmrg else 16805b261ecSmrg { 16905b261ecSmrg /* 17005b261ecSmrg * Previous delta of different sign, or zero. 17105b261ecSmrg * We will set it to zero for either case, 17205b261ecSmrg * as blindly setting takes just as much time 17305b261ecSmrg * as checking, then setting if necessary :) 17405b261ecSmrg */ 17505b261ecSmrg pScreenPriv->iDeltaZ = 0; 17605b261ecSmrg } 17705b261ecSmrg 17805b261ecSmrg /* 17905b261ecSmrg * Only process this message if the wheel has moved further than 18005b261ecSmrg * WHEEL_DELTA 18105b261ecSmrg */ 18205b261ecSmrg if (iDeltaZ >= WHEEL_DELTA || (-1 * iDeltaZ) >= WHEEL_DELTA) 18305b261ecSmrg { 18405b261ecSmrg pScreenPriv->iDeltaZ = 0; 18505b261ecSmrg 18605b261ecSmrg /* Figure out how many whole deltas of the wheel we have */ 18705b261ecSmrg iDeltaZ /= WHEEL_DELTA; 18805b261ecSmrg } 18905b261ecSmrg else 19005b261ecSmrg { 19105b261ecSmrg /* 19205b261ecSmrg * Wheel has not moved past WHEEL_DELTA threshold; 19305b261ecSmrg * we will store the wheel delta until the threshold 19405b261ecSmrg * has been reached. 19505b261ecSmrg */ 19605b261ecSmrg pScreenPriv->iDeltaZ = iDeltaZ; 19705b261ecSmrg return 0; 19805b261ecSmrg } 19905b261ecSmrg 20005b261ecSmrg /* Set the button to indicate up or down wheel delta */ 20105b261ecSmrg if (iDeltaZ > 0) 20205b261ecSmrg { 20305b261ecSmrg button = Button4; 20405b261ecSmrg } 20505b261ecSmrg else 20605b261ecSmrg { 20705b261ecSmrg button = Button5; 20805b261ecSmrg } 20905b261ecSmrg 21005b261ecSmrg /* 21105b261ecSmrg * Flip iDeltaZ to positive, if negative, 21205b261ecSmrg * because always need to generate a *positive* number of 21305b261ecSmrg * button clicks for the Z axis. 21405b261ecSmrg */ 21505b261ecSmrg if (iDeltaZ < 0) 21605b261ecSmrg { 21705b261ecSmrg iDeltaZ *= -1; 21805b261ecSmrg } 21905b261ecSmrg 22005b261ecSmrg /* Generate X input messages for each wheel delta we have seen */ 22105b261ecSmrg while (iDeltaZ--) 22205b261ecSmrg { 22305b261ecSmrg /* Push the wheel button */ 22405b261ecSmrg winMouseButtonsSendEvent (ButtonPress, button); 22505b261ecSmrg 22605b261ecSmrg /* Release the wheel button */ 22705b261ecSmrg winMouseButtonsSendEvent (ButtonRelease, button); 22805b261ecSmrg } 22905b261ecSmrg 23005b261ecSmrg return 0; 23105b261ecSmrg} 23205b261ecSmrg 23305b261ecSmrg 23405b261ecSmrg/* 23505b261ecSmrg * Enqueue a mouse button event 23605b261ecSmrg */ 23705b261ecSmrg 23805b261ecSmrgvoid 23905b261ecSmrgwinMouseButtonsSendEvent (int iEventType, int iButton) 24005b261ecSmrg{ 2416747b715Smrg EventListPtr events; 2426747b715Smrg int i, nevents; 24305b261ecSmrg 2444642e01fSmrg#if defined(XFree86Server) 24505b261ecSmrg if (g_winMouseButtonMap) 2466747b715Smrg iButton = g_winMouseButtonMap[iButton]; 2476747b715Smrg#endif 2486747b715Smrg 2496747b715Smrg GetEventList(&events); 2506747b715Smrg nevents = GetPointerEvents(events, g_pwinPointer, iEventType, iButton, 2516747b715Smrg POINTER_RELATIVE, 0, 0, NULL); 2526747b715Smrg 2536747b715Smrg for (i = 0; i < nevents; i++) 2546747b715Smrg mieqEnqueue(g_pwinPointer, events[i].event); 2556747b715Smrg 2566747b715Smrg#if CYGDEBUG 2576747b715Smrg ErrorF("winMouseButtonsSendEvent: iEventType: %d, iButton: %d, nEvents %d\n", 2586747b715Smrg iEventType, iButton, nevents); 25905b261ecSmrg#endif 26005b261ecSmrg} 26105b261ecSmrg 26205b261ecSmrg 26305b261ecSmrg/* 26405b261ecSmrg * Decide what to do with a Windows mouse message 26505b261ecSmrg */ 26605b261ecSmrg 26705b261ecSmrgint 26805b261ecSmrgwinMouseButtonsHandle (ScreenPtr pScreen, 26905b261ecSmrg int iEventType, int iButton, 27005b261ecSmrg WPARAM wParam) 27105b261ecSmrg{ 27205b261ecSmrg winScreenPriv(pScreen); 27305b261ecSmrg winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; 27405b261ecSmrg 27505b261ecSmrg /* Send button events right away if emulate 3 buttons is off */ 27605b261ecSmrg if (pScreenInfo->iE3BTimeout == WIN_E3B_OFF) 27705b261ecSmrg { 27805b261ecSmrg /* Emulate 3 buttons is off, send the button event */ 27905b261ecSmrg winMouseButtonsSendEvent (iEventType, iButton); 28005b261ecSmrg return 0; 28105b261ecSmrg } 28205b261ecSmrg 28305b261ecSmrg /* Emulate 3 buttons is on, let the fun begin */ 28405b261ecSmrg if (iEventType == ButtonPress 28505b261ecSmrg && pScreenPriv->iE3BCachedPress == 0 28605b261ecSmrg && !pScreenPriv->fE3BFakeButton2Sent) 28705b261ecSmrg { 28805b261ecSmrg /* 28905b261ecSmrg * Button was pressed, no press is cached, 29005b261ecSmrg * and there is no fake button 2 release pending. 29105b261ecSmrg */ 29205b261ecSmrg 29305b261ecSmrg /* Store button press type */ 29405b261ecSmrg pScreenPriv->iE3BCachedPress = iButton; 29505b261ecSmrg 29605b261ecSmrg /* 29705b261ecSmrg * Set a timer to send this button press if the other button 29805b261ecSmrg * is not pressed within the timeout time. 29905b261ecSmrg */ 30005b261ecSmrg SetTimer (pScreenPriv->hwndScreen, 30105b261ecSmrg WIN_E3B_TIMER_ID, 30205b261ecSmrg pScreenInfo->iE3BTimeout, 30305b261ecSmrg NULL); 30405b261ecSmrg } 30505b261ecSmrg else if (iEventType == ButtonPress 30605b261ecSmrg && pScreenPriv->iE3BCachedPress != 0 30705b261ecSmrg && pScreenPriv->iE3BCachedPress != iButton 30805b261ecSmrg && !pScreenPriv->fE3BFakeButton2Sent) 30905b261ecSmrg { 31005b261ecSmrg /* 31105b261ecSmrg * Button press is cached, other button was pressed, 31205b261ecSmrg * and there is no fake button 2 release pending. 31305b261ecSmrg */ 31405b261ecSmrg 31505b261ecSmrg /* Mouse button was cached and other button was pressed */ 31605b261ecSmrg KillTimer (pScreenPriv->hwndScreen, WIN_E3B_TIMER_ID); 31705b261ecSmrg pScreenPriv->iE3BCachedPress = 0; 31805b261ecSmrg 31905b261ecSmrg /* Send fake middle button */ 32005b261ecSmrg winMouseButtonsSendEvent (ButtonPress, Button2); 32105b261ecSmrg 32205b261ecSmrg /* Indicate that a fake middle button event was sent */ 32305b261ecSmrg pScreenPriv->fE3BFakeButton2Sent = TRUE; 32405b261ecSmrg } 32505b261ecSmrg else if (iEventType == ButtonRelease 32605b261ecSmrg && pScreenPriv->iE3BCachedPress == iButton) 32705b261ecSmrg { 32805b261ecSmrg /* 32905b261ecSmrg * Cached button was released before timer ran out, 33005b261ecSmrg * and before the other mouse button was pressed. 33105b261ecSmrg */ 33205b261ecSmrg KillTimer (pScreenPriv->hwndScreen, WIN_E3B_TIMER_ID); 33305b261ecSmrg pScreenPriv->iE3BCachedPress = 0; 33405b261ecSmrg 33505b261ecSmrg /* Send cached press, then send release */ 33605b261ecSmrg winMouseButtonsSendEvent (ButtonPress, iButton); 33705b261ecSmrg winMouseButtonsSendEvent (ButtonRelease, iButton); 33805b261ecSmrg } 33905b261ecSmrg else if (iEventType == ButtonRelease 34005b261ecSmrg && pScreenPriv->fE3BFakeButton2Sent 34105b261ecSmrg && !(wParam & MK_LBUTTON) 34205b261ecSmrg && !(wParam & MK_RBUTTON)) 34305b261ecSmrg { 34405b261ecSmrg /* 34505b261ecSmrg * Fake button 2 was sent and both mouse buttons have now been released 34605b261ecSmrg */ 34705b261ecSmrg pScreenPriv->fE3BFakeButton2Sent = FALSE; 34805b261ecSmrg 34905b261ecSmrg /* Send middle mouse button release */ 35005b261ecSmrg winMouseButtonsSendEvent (ButtonRelease, Button2); 35105b261ecSmrg } 35205b261ecSmrg else if (iEventType == ButtonRelease 35305b261ecSmrg && pScreenPriv->iE3BCachedPress == 0 35405b261ecSmrg && !pScreenPriv->fE3BFakeButton2Sent) 35505b261ecSmrg { 35605b261ecSmrg /* 35705b261ecSmrg * Button was release, no button is cached, 35805b261ecSmrg * and there is no fake button 2 release is pending. 35905b261ecSmrg */ 36005b261ecSmrg winMouseButtonsSendEvent (ButtonRelease, iButton); 36105b261ecSmrg } 36205b261ecSmrg 36305b261ecSmrg return 0; 36405b261ecSmrg} 3656747b715Smrg 3666747b715Smrg/** 3676747b715Smrg * Enqueue a motion event. 3686747b715Smrg * 3696747b715Smrg * XXX: miPointerMove does exactly this, but is static :-( (and uses a static buffer) 3706747b715Smrg * 3716747b715Smrg */ 3726747b715Smrgvoid winEnqueueMotion(int x, int y) 3736747b715Smrg{ 3746747b715Smrg int i, nevents; 3756747b715Smrg int valuators[2]; 3766747b715Smrg EventListPtr events; 3776747b715Smrg 3786747b715Smrg miPointerSetPosition(g_pwinPointer, &x, &y); 3796747b715Smrg valuators[0] = x; 3806747b715Smrg valuators[1] = y; 3816747b715Smrg 3826747b715Smrg GetEventList(&events); 3836747b715Smrg nevents = GetPointerEvents(events, g_pwinPointer, MotionNotify, 0, 3846747b715Smrg POINTER_ABSOLUTE | POINTER_SCREEN, 0, 2, valuators); 3856747b715Smrg 3866747b715Smrg for (i = 0; i < nevents; i++) 3876747b715Smrg mieqEnqueue(g_pwinPointer, events[i].event); 3886747b715Smrg} 389