1706f2543Smrg/* 2706f2543Smrg *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. 3706f2543Smrg * 4706f2543Smrg *Permission is hereby granted, free of charge, to any person obtaining 5706f2543Smrg * a copy of this software and associated documentation files (the 6706f2543Smrg *"Software"), to deal in the Software without restriction, including 7706f2543Smrg *without limitation the rights to use, copy, modify, merge, publish, 8706f2543Smrg *distribute, sublicense, and/or sell copies of the Software, and to 9706f2543Smrg *permit persons to whom the Software is furnished to do so, subject to 10706f2543Smrg *the following conditions: 11706f2543Smrg * 12706f2543Smrg *The above copyright notice and this permission notice shall be 13706f2543Smrg *included in all copies or substantial portions of the Software. 14706f2543Smrg * 15706f2543Smrg *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16706f2543Smrg *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17706f2543Smrg *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18706f2543Smrg *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR 19706f2543Smrg *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 20706f2543Smrg *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21706f2543Smrg *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22706f2543Smrg * 23706f2543Smrg *Except as contained in this notice, the name of the XFree86 Project 24706f2543Smrg *shall not be used in advertising or otherwise to promote the sale, use 25706f2543Smrg *or other dealings in this Software without prior written authorization 26706f2543Smrg *from the XFree86 Project. 27706f2543Smrg * 28706f2543Smrg * Authors: Dakshinamurthy Karra 29706f2543Smrg * Suhaib M Siddiqi 30706f2543Smrg * Peter Busch 31706f2543Smrg * Harold L Hunt II 32706f2543Smrg */ 33706f2543Smrg 34706f2543Smrg#ifdef HAVE_XWIN_CONFIG_H 35706f2543Smrg#include <xwin-config.h> 36706f2543Smrg#endif 37706f2543Smrg#include "win.h" 38706f2543Smrg 39706f2543Smrg#include "inputstr.h" 40706f2543Smrg#include "exevents.h" /* for button/axes labels */ 41706f2543Smrg#include "xserver-properties.h" 42706f2543Smrg#include "inpututils.h" 43706f2543Smrg 44706f2543Smrg/* Peek the internal button mapping */ 45706f2543Smrgstatic CARD8 const *g_winMouseButtonMap = NULL; 46706f2543Smrg 47706f2543Smrg 48706f2543Smrg/* 49706f2543Smrg * Local prototypes 50706f2543Smrg */ 51706f2543Smrg 52706f2543Smrgstatic void 53706f2543SmrgwinMouseCtrl (DeviceIntPtr pDevice, PtrCtrl *pCtrl); 54706f2543Smrg 55706f2543Smrg 56706f2543Smrgstatic void 57706f2543SmrgwinMouseCtrl (DeviceIntPtr pDevice, PtrCtrl *pCtrl) 58706f2543Smrg{ 59706f2543Smrg} 60706f2543Smrg 61706f2543Smrg 62706f2543Smrg/* 63706f2543Smrg * See Porting Layer Definition - p. 18 64706f2543Smrg * This is known as a DeviceProc 65706f2543Smrg */ 66706f2543Smrg 67706f2543Smrgint 68706f2543SmrgwinMouseProc (DeviceIntPtr pDeviceInt, int iState) 69706f2543Smrg{ 70706f2543Smrg int lngMouseButtons, i; 71706f2543Smrg int lngWheelEvents = 2; 72706f2543Smrg CARD8 *map; 73706f2543Smrg DevicePtr pDevice = (DevicePtr) pDeviceInt; 74706f2543Smrg Atom *btn_labels; 75706f2543Smrg Atom axes_labels[2]; 76706f2543Smrg 77706f2543Smrg switch (iState) 78706f2543Smrg { 79706f2543Smrg case DEVICE_INIT: 80706f2543Smrg /* Get number of mouse buttons */ 81706f2543Smrg lngMouseButtons = GetSystemMetrics(SM_CMOUSEBUTTONS); 82706f2543Smrg 83706f2543Smrg /* Mapping of windows events to X events: 84706f2543Smrg * LEFT:1 MIDDLE:2 RIGHT:3 85706f2543Smrg * SCROLL_UP:4 SCROLL_DOWN:5 86706f2543Smrg * XBUTTON 1:6 XBUTTON 2:7 ... 87706f2543Smrg * 88706f2543Smrg * To map scroll wheel correctly we need at least the 3 normal buttons 89706f2543Smrg */ 90706f2543Smrg if (lngMouseButtons < 3) 91706f2543Smrg lngMouseButtons = 3; 92706f2543Smrg winMsg(X_PROBED, "%d mouse buttons found\n", lngMouseButtons); 93706f2543Smrg 94706f2543Smrg /* allocate memory: 95706f2543Smrg * number of buttons + 2x mouse wheel event + 1 extra (offset for map) 96706f2543Smrg */ 97706f2543Smrg map = malloc(sizeof(CARD8) * (lngMouseButtons + lngWheelEvents + 1)); 98706f2543Smrg 99706f2543Smrg /* initalize button map */ 100706f2543Smrg map[0] = 0; 101706f2543Smrg for (i=1; i <= lngMouseButtons + lngWheelEvents; i++) 102706f2543Smrg map[i] = i; 103706f2543Smrg 104706f2543Smrg btn_labels = calloc((lngMouseButtons + lngWheelEvents), sizeof(Atom)); 105706f2543Smrg btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); 106706f2543Smrg btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); 107706f2543Smrg btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); 108706f2543Smrg btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP); 109706f2543Smrg btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); 110706f2543Smrg 111706f2543Smrg axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); 112706f2543Smrg axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); 113706f2543Smrg 114706f2543Smrg InitPointerDeviceStruct (pDevice, 115706f2543Smrg map, 116706f2543Smrg lngMouseButtons + lngWheelEvents, 117706f2543Smrg btn_labels, 118706f2543Smrg winMouseCtrl, 119706f2543Smrg GetMotionHistorySize(), 120706f2543Smrg 2, 121706f2543Smrg axes_labels); 122706f2543Smrg free(map); 123706f2543Smrg free(btn_labels); 124706f2543Smrg 125706f2543Smrg g_winMouseButtonMap = pDeviceInt->button->map; 126706f2543Smrg break; 127706f2543Smrg 128706f2543Smrg case DEVICE_ON: 129706f2543Smrg pDevice->on = TRUE; 130706f2543Smrg break; 131706f2543Smrg 132706f2543Smrg case DEVICE_CLOSE: 133706f2543Smrg g_winMouseButtonMap = NULL; 134706f2543Smrg 135706f2543Smrg case DEVICE_OFF: 136706f2543Smrg pDevice->on = FALSE; 137706f2543Smrg break; 138706f2543Smrg } 139706f2543Smrg return Success; 140706f2543Smrg} 141706f2543Smrg 142706f2543Smrg 143706f2543Smrg/* Handle the mouse wheel */ 144706f2543Smrgint 145706f2543SmrgwinMouseWheel (ScreenPtr pScreen, int iDeltaZ) 146706f2543Smrg{ 147706f2543Smrg winScreenPriv(pScreen); 148706f2543Smrg int button; /* Button4 or Button5 */ 149706f2543Smrg 150706f2543Smrg /* Button4 = WheelUp */ 151706f2543Smrg /* Button5 = WheelDown */ 152706f2543Smrg 153706f2543Smrg /* Do we have any previous delta stored? */ 154706f2543Smrg if ((pScreenPriv->iDeltaZ > 0 155706f2543Smrg && iDeltaZ > 0) 156706f2543Smrg || (pScreenPriv->iDeltaZ < 0 157706f2543Smrg && iDeltaZ < 0)) 158706f2543Smrg { 159706f2543Smrg /* Previous delta and of same sign as current delta */ 160706f2543Smrg iDeltaZ += pScreenPriv->iDeltaZ; 161706f2543Smrg pScreenPriv->iDeltaZ = 0; 162706f2543Smrg } 163706f2543Smrg else 164706f2543Smrg { 165706f2543Smrg /* 166706f2543Smrg * Previous delta of different sign, or zero. 167706f2543Smrg * We will set it to zero for either case, 168706f2543Smrg * as blindly setting takes just as much time 169706f2543Smrg * as checking, then setting if necessary :) 170706f2543Smrg */ 171706f2543Smrg pScreenPriv->iDeltaZ = 0; 172706f2543Smrg } 173706f2543Smrg 174706f2543Smrg /* 175706f2543Smrg * Only process this message if the wheel has moved further than 176706f2543Smrg * WHEEL_DELTA 177706f2543Smrg */ 178706f2543Smrg if (iDeltaZ >= WHEEL_DELTA || (-1 * iDeltaZ) >= WHEEL_DELTA) 179706f2543Smrg { 180706f2543Smrg pScreenPriv->iDeltaZ = 0; 181706f2543Smrg 182706f2543Smrg /* Figure out how many whole deltas of the wheel we have */ 183706f2543Smrg iDeltaZ /= WHEEL_DELTA; 184706f2543Smrg } 185706f2543Smrg else 186706f2543Smrg { 187706f2543Smrg /* 188706f2543Smrg * Wheel has not moved past WHEEL_DELTA threshold; 189706f2543Smrg * we will store the wheel delta until the threshold 190706f2543Smrg * has been reached. 191706f2543Smrg */ 192706f2543Smrg pScreenPriv->iDeltaZ = iDeltaZ; 193706f2543Smrg return 0; 194706f2543Smrg } 195706f2543Smrg 196706f2543Smrg /* Set the button to indicate up or down wheel delta */ 197706f2543Smrg if (iDeltaZ > 0) 198706f2543Smrg { 199706f2543Smrg button = Button4; 200706f2543Smrg } 201706f2543Smrg else 202706f2543Smrg { 203706f2543Smrg button = Button5; 204706f2543Smrg } 205706f2543Smrg 206706f2543Smrg /* 207706f2543Smrg * Flip iDeltaZ to positive, if negative, 208706f2543Smrg * because always need to generate a *positive* number of 209706f2543Smrg * button clicks for the Z axis. 210706f2543Smrg */ 211706f2543Smrg if (iDeltaZ < 0) 212706f2543Smrg { 213706f2543Smrg iDeltaZ *= -1; 214706f2543Smrg } 215706f2543Smrg 216706f2543Smrg /* Generate X input messages for each wheel delta we have seen */ 217706f2543Smrg while (iDeltaZ--) 218706f2543Smrg { 219706f2543Smrg /* Push the wheel button */ 220706f2543Smrg winMouseButtonsSendEvent (ButtonPress, button); 221706f2543Smrg 222706f2543Smrg /* Release the wheel button */ 223706f2543Smrg winMouseButtonsSendEvent (ButtonRelease, button); 224706f2543Smrg } 225706f2543Smrg 226706f2543Smrg return 0; 227706f2543Smrg} 228706f2543Smrg 229706f2543Smrg 230706f2543Smrg/* 231706f2543Smrg * Enqueue a mouse button event 232706f2543Smrg */ 233706f2543Smrg 234706f2543Smrgvoid 235706f2543SmrgwinMouseButtonsSendEvent (int iEventType, int iButton) 236706f2543Smrg{ 237706f2543Smrg EventListPtr events; 238706f2543Smrg int i, nevents; 239706f2543Smrg ValuatorMask mask; 240706f2543Smrg 241706f2543Smrg if (g_winMouseButtonMap) 242706f2543Smrg iButton = g_winMouseButtonMap[iButton]; 243706f2543Smrg 244706f2543Smrg valuator_mask_zero(&mask); 245706f2543Smrg GetEventList(&events); 246706f2543Smrg nevents = GetPointerEvents(events, g_pwinPointer, iEventType, iButton, 247706f2543Smrg POINTER_RELATIVE, &mask); 248706f2543Smrg 249706f2543Smrg for (i = 0; i < nevents; i++) 250706f2543Smrg mieqEnqueue(g_pwinPointer, (InternalEvent*)events[i].event); 251706f2543Smrg 252706f2543Smrg#if CYGDEBUG 253706f2543Smrg ErrorF("winMouseButtonsSendEvent: iEventType: %d, iButton: %d, nEvents %d\n", 254706f2543Smrg iEventType, iButton, nevents); 255706f2543Smrg#endif 256706f2543Smrg} 257706f2543Smrg 258706f2543Smrg 259706f2543Smrg/* 260706f2543Smrg * Decide what to do with a Windows mouse message 261706f2543Smrg */ 262706f2543Smrg 263706f2543Smrgint 264706f2543SmrgwinMouseButtonsHandle (ScreenPtr pScreen, 265706f2543Smrg int iEventType, int iButton, 266706f2543Smrg WPARAM wParam) 267706f2543Smrg{ 268706f2543Smrg winScreenPriv(pScreen); 269706f2543Smrg winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; 270706f2543Smrg 271706f2543Smrg /* Send button events right away if emulate 3 buttons is off */ 272706f2543Smrg if (pScreenInfo->iE3BTimeout == WIN_E3B_OFF) 273706f2543Smrg { 274706f2543Smrg /* Emulate 3 buttons is off, send the button event */ 275706f2543Smrg winMouseButtonsSendEvent (iEventType, iButton); 276706f2543Smrg return 0; 277706f2543Smrg } 278706f2543Smrg 279706f2543Smrg /* Emulate 3 buttons is on, let the fun begin */ 280706f2543Smrg if (iEventType == ButtonPress 281706f2543Smrg && pScreenPriv->iE3BCachedPress == 0 282706f2543Smrg && !pScreenPriv->fE3BFakeButton2Sent) 283706f2543Smrg { 284706f2543Smrg /* 285706f2543Smrg * Button was pressed, no press is cached, 286706f2543Smrg * and there is no fake button 2 release pending. 287706f2543Smrg */ 288706f2543Smrg 289706f2543Smrg /* Store button press type */ 290706f2543Smrg pScreenPriv->iE3BCachedPress = iButton; 291706f2543Smrg 292706f2543Smrg /* 293706f2543Smrg * Set a timer to send this button press if the other button 294706f2543Smrg * is not pressed within the timeout time. 295706f2543Smrg */ 296706f2543Smrg SetTimer (pScreenPriv->hwndScreen, 297706f2543Smrg WIN_E3B_TIMER_ID, 298706f2543Smrg pScreenInfo->iE3BTimeout, 299706f2543Smrg NULL); 300706f2543Smrg } 301706f2543Smrg else if (iEventType == ButtonPress 302706f2543Smrg && pScreenPriv->iE3BCachedPress != 0 303706f2543Smrg && pScreenPriv->iE3BCachedPress != iButton 304706f2543Smrg && !pScreenPriv->fE3BFakeButton2Sent) 305706f2543Smrg { 306706f2543Smrg /* 307706f2543Smrg * Button press is cached, other button was pressed, 308706f2543Smrg * and there is no fake button 2 release pending. 309706f2543Smrg */ 310706f2543Smrg 311706f2543Smrg /* Mouse button was cached and other button was pressed */ 312706f2543Smrg KillTimer (pScreenPriv->hwndScreen, WIN_E3B_TIMER_ID); 313706f2543Smrg pScreenPriv->iE3BCachedPress = 0; 314706f2543Smrg 315706f2543Smrg /* Send fake middle button */ 316706f2543Smrg winMouseButtonsSendEvent (ButtonPress, Button2); 317706f2543Smrg 318706f2543Smrg /* Indicate that a fake middle button event was sent */ 319706f2543Smrg pScreenPriv->fE3BFakeButton2Sent = TRUE; 320706f2543Smrg } 321706f2543Smrg else if (iEventType == ButtonRelease 322706f2543Smrg && pScreenPriv->iE3BCachedPress == iButton) 323706f2543Smrg { 324706f2543Smrg /* 325706f2543Smrg * Cached button was released before timer ran out, 326706f2543Smrg * and before the other mouse button was pressed. 327706f2543Smrg */ 328706f2543Smrg KillTimer (pScreenPriv->hwndScreen, WIN_E3B_TIMER_ID); 329706f2543Smrg pScreenPriv->iE3BCachedPress = 0; 330706f2543Smrg 331706f2543Smrg /* Send cached press, then send release */ 332706f2543Smrg winMouseButtonsSendEvent (ButtonPress, iButton); 333706f2543Smrg winMouseButtonsSendEvent (ButtonRelease, iButton); 334706f2543Smrg } 335706f2543Smrg else if (iEventType == ButtonRelease 336706f2543Smrg && pScreenPriv->fE3BFakeButton2Sent 337706f2543Smrg && !(wParam & MK_LBUTTON) 338706f2543Smrg && !(wParam & MK_RBUTTON)) 339706f2543Smrg { 340706f2543Smrg /* 341706f2543Smrg * Fake button 2 was sent and both mouse buttons have now been released 342706f2543Smrg */ 343706f2543Smrg pScreenPriv->fE3BFakeButton2Sent = FALSE; 344706f2543Smrg 345706f2543Smrg /* Send middle mouse button release */ 346706f2543Smrg winMouseButtonsSendEvent (ButtonRelease, Button2); 347706f2543Smrg } 348706f2543Smrg else if (iEventType == ButtonRelease 349706f2543Smrg && pScreenPriv->iE3BCachedPress == 0 350706f2543Smrg && !pScreenPriv->fE3BFakeButton2Sent) 351706f2543Smrg { 352706f2543Smrg /* 353706f2543Smrg * Button was release, no button is cached, 354706f2543Smrg * and there is no fake button 2 release is pending. 355706f2543Smrg */ 356706f2543Smrg winMouseButtonsSendEvent (ButtonRelease, iButton); 357706f2543Smrg } 358706f2543Smrg 359706f2543Smrg return 0; 360706f2543Smrg} 361706f2543Smrg 362706f2543Smrg/** 363706f2543Smrg * Enqueue a motion event. 364706f2543Smrg * 365706f2543Smrg * XXX: miPointerMove does exactly this, but is static :-( (and uses a static buffer) 366706f2543Smrg * 367706f2543Smrg */ 368706f2543Smrgvoid winEnqueueMotion(int x, int y) 369706f2543Smrg{ 370706f2543Smrg int i, nevents; 371706f2543Smrg int valuators[2]; 372706f2543Smrg ValuatorMask mask; 373706f2543Smrg EventListPtr events; 374706f2543Smrg 375706f2543Smrg miPointerSetPosition(g_pwinPointer, &x, &y); 376706f2543Smrg valuators[0] = x; 377706f2543Smrg valuators[1] = y; 378706f2543Smrg 379706f2543Smrg valuator_mask_set_range(&mask, 0, 2, valuators); 380706f2543Smrg GetEventList(&events); 381706f2543Smrg nevents = GetPointerEvents(events, g_pwinPointer, MotionNotify, 0, 382706f2543Smrg POINTER_ABSOLUTE | POINTER_SCREEN, &mask); 383706f2543Smrg 384706f2543Smrg for (i = 0; i < nevents; i++) 385706f2543Smrg mieqEnqueue(g_pwinPointer, (InternalEvent*)events[i].event); 386706f2543Smrg} 387