1/* 2 *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. 3 * 4 *Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files (the 6 *"Software"), to deal in the Software without restriction, including 7 *without limitation the rights to use, copy, modify, merge, publish, 8 *distribute, sublicense, and/or sell copies of the Software, and to 9 *permit persons to whom the Software is furnished to do so, subject to 10 *the following conditions: 11 * 12 *The above copyright notice and this permission notice shall be 13 *included in all copies or substantial portions of the Software. 14 * 15 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR 19 *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 20 *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 * 23 *Except as contained in this notice, the name of the XFree86 Project 24 *shall not be used in advertising or otherwise to promote the sale, use 25 *or other dealings in this Software without prior written authorization 26 *from the XFree86 Project. 27 * 28 * Authors: Dakshinamurthy Karra 29 * Suhaib M Siddiqi 30 * Peter Busch 31 * Harold L Hunt II 32 */ 33 34#ifdef HAVE_XWIN_CONFIG_H 35#include <xwin-config.h> 36#endif 37#include "win.h" 38 39#include "inputstr.h" 40#include "exevents.h" /* for button/axes labels */ 41#include "xserver-properties.h" 42#include "inpututils.h" 43 44/* Peek the internal button mapping */ 45static CARD8 const *g_winMouseButtonMap = NULL; 46 47/* 48 * Local prototypes 49 */ 50 51static void 52 winMouseCtrl(DeviceIntPtr pDevice, PtrCtrl * pCtrl); 53 54static void 55winMouseCtrl(DeviceIntPtr pDevice, PtrCtrl * pCtrl) 56{ 57} 58 59/* 60 * See Porting Layer Definition - p. 18 61 * This is known as a DeviceProc 62 */ 63 64int 65winMouseProc(DeviceIntPtr pDeviceInt, int iState) 66{ 67 int lngMouseButtons, i; 68 int lngWheelEvents = 4; 69 CARD8 *map; 70 DevicePtr pDevice = (DevicePtr) pDeviceInt; 71 Atom btn_labels[9]; 72 Atom axes_labels[2]; 73 74 switch (iState) { 75 case DEVICE_INIT: 76 /* Get number of mouse buttons */ 77 lngMouseButtons = GetSystemMetrics(SM_CMOUSEBUTTONS); 78 winMsg(X_PROBED, "%d mouse buttons found\n", lngMouseButtons); 79 80 /* Mapping of windows events to X events: 81 * LEFT:1 MIDDLE:2 RIGHT:3 82 * SCROLL_UP:4 SCROLL_DOWN:5 83 * TILT_LEFT:6 TILT_RIGHT:7 84 * XBUTTON 1:8 XBUTTON 2:9 (most commonly 'back' and 'forward') 85 * ... 86 * 87 * The current Windows API only defines 2 extra buttons, so we don't 88 * expect more than 5 buttons to be reported, but more than that 89 * should be handled correctly 90 */ 91 92 /* 93 * To map scroll wheel correctly we need at least the 3 normal buttons 94 */ 95 if (lngMouseButtons < 3) 96 lngMouseButtons = 3; 97 98 /* allocate memory: 99 * number of buttons + 4 x mouse wheel event + 1 extra (offset for map) 100 */ 101 map = malloc(sizeof(CARD8) * (lngMouseButtons + lngWheelEvents + 1)); 102 103 /* initialize button map */ 104 map[0] = 0; 105 for (i = 1; i <= lngMouseButtons + lngWheelEvents; i++) 106 map[i] = i; 107 108 btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); 109 btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); 110 btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); 111 btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP); 112 btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); 113 btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT); 114 btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT); 115 btn_labels[7] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_BACK); 116 btn_labels[8] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_FORWARD); 117 118 axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); 119 axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); 120 121 InitPointerDeviceStruct(pDevice, 122 map, 123 lngMouseButtons + lngWheelEvents, 124 btn_labels, 125 winMouseCtrl, 126 GetMotionHistorySize(), 2, axes_labels); 127 free(map); 128 129 g_winMouseButtonMap = pDeviceInt->button->map; 130 break; 131 132 case DEVICE_ON: 133 pDevice->on = TRUE; 134 break; 135 136 case DEVICE_CLOSE: 137 g_winMouseButtonMap = NULL; 138 139 case DEVICE_OFF: 140 pDevice->on = FALSE; 141 break; 142 } 143 return Success; 144} 145 146/* Handle the mouse wheel */ 147int 148winMouseWheel(int *iTotalDeltaZ, int iDeltaZ, int iButtonUp, int iButtonDown) 149{ 150 int button; 151 152 /* Do we have any previous delta stored? */ 153 if ((*iTotalDeltaZ > 0 && iDeltaZ > 0) 154 || (*iTotalDeltaZ < 0 && iDeltaZ < 0)) { 155 /* Previous delta and of same sign as current delta */ 156 iDeltaZ += *iTotalDeltaZ; 157 *iTotalDeltaZ = 0; 158 } 159 else { 160 /* 161 * Previous delta of different sign, or zero. 162 * We will set it to zero for either case, 163 * as blindly setting takes just as much time 164 * as checking, then setting if necessary :) 165 */ 166 *iTotalDeltaZ = 0; 167 } 168 169 /* 170 * Only process this message if the wheel has moved further than 171 * WHEEL_DELTA 172 */ 173 if (iDeltaZ >= WHEEL_DELTA || (-1 * iDeltaZ) >= WHEEL_DELTA) { 174 *iTotalDeltaZ = 0; 175 176 /* Figure out how many whole deltas of the wheel we have */ 177 iDeltaZ /= WHEEL_DELTA; 178 } 179 else { 180 /* 181 * Wheel has not moved past WHEEL_DELTA threshold; 182 * we will store the wheel delta until the threshold 183 * has been reached. 184 */ 185 *iTotalDeltaZ = iDeltaZ; 186 return 0; 187 } 188 189 /* Set the button to indicate up or down wheel delta */ 190 if (iDeltaZ > 0) { 191 button = iButtonUp; 192 } 193 else { 194 button = iButtonDown; 195 } 196 197 /* 198 * Flip iDeltaZ to positive, if negative, 199 * because always need to generate a *positive* number of 200 * button clicks for the Z axis. 201 */ 202 if (iDeltaZ < 0) { 203 iDeltaZ *= -1; 204 } 205 206 /* Generate X input messages for each wheel delta we have seen */ 207 while (iDeltaZ--) { 208 /* Push the wheel button */ 209 winMouseButtonsSendEvent(ButtonPress, button); 210 211 /* Release the wheel button */ 212 winMouseButtonsSendEvent(ButtonRelease, button); 213 } 214 215 return 0; 216} 217 218/* 219 * Enqueue a mouse button event 220 */ 221 222void 223winMouseButtonsSendEvent(int iEventType, int iButton) 224{ 225 ValuatorMask mask; 226 227 if (g_winMouseButtonMap) 228 iButton = g_winMouseButtonMap[iButton]; 229 230 valuator_mask_zero(&mask); 231 QueuePointerEvents(g_pwinPointer, iEventType, iButton, 232 POINTER_RELATIVE, &mask); 233 234#if CYGDEBUG 235 ErrorF("winMouseButtonsSendEvent: iEventType: %d, iButton: %d\n", 236 iEventType, iButton); 237#endif 238} 239 240/* 241 * Decide what to do with a Windows mouse message 242 */ 243 244int 245winMouseButtonsHandle(ScreenPtr pScreen, 246 int iEventType, int iButton, WPARAM wParam) 247{ 248 winScreenPriv(pScreen); 249 winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; 250 251 /* Send button events right away if emulate 3 buttons is off */ 252 if (pScreenInfo->iE3BTimeout == WIN_E3B_OFF) { 253 /* Emulate 3 buttons is off, send the button event */ 254 winMouseButtonsSendEvent(iEventType, iButton); 255 return 0; 256 } 257 258 /* Emulate 3 buttons is on, let the fun begin */ 259 if (iEventType == ButtonPress 260 && pScreenPriv->iE3BCachedPress == 0 261 && !pScreenPriv->fE3BFakeButton2Sent) { 262 /* 263 * Button was pressed, no press is cached, 264 * and there is no fake button 2 release pending. 265 */ 266 267 /* Store button press type */ 268 pScreenPriv->iE3BCachedPress = iButton; 269 270 /* 271 * Set a timer to send this button press if the other button 272 * is not pressed within the timeout time. 273 */ 274 SetTimer(pScreenPriv->hwndScreen, 275 WIN_E3B_TIMER_ID, pScreenInfo->iE3BTimeout, NULL); 276 } 277 else if (iEventType == ButtonPress 278 && pScreenPriv->iE3BCachedPress != 0 279 && pScreenPriv->iE3BCachedPress != iButton 280 && !pScreenPriv->fE3BFakeButton2Sent) { 281 /* 282 * Button press is cached, other button was pressed, 283 * and there is no fake button 2 release pending. 284 */ 285 286 /* Mouse button was cached and other button was pressed */ 287 KillTimer(pScreenPriv->hwndScreen, WIN_E3B_TIMER_ID); 288 pScreenPriv->iE3BCachedPress = 0; 289 290 /* Send fake middle button */ 291 winMouseButtonsSendEvent(ButtonPress, Button2); 292 293 /* Indicate that a fake middle button event was sent */ 294 pScreenPriv->fE3BFakeButton2Sent = TRUE; 295 } 296 else if (iEventType == ButtonRelease 297 && pScreenPriv->iE3BCachedPress == iButton) { 298 /* 299 * Cached button was released before timer ran out, 300 * and before the other mouse button was pressed. 301 */ 302 KillTimer(pScreenPriv->hwndScreen, WIN_E3B_TIMER_ID); 303 pScreenPriv->iE3BCachedPress = 0; 304 305 /* Send cached press, then send release */ 306 winMouseButtonsSendEvent(ButtonPress, iButton); 307 winMouseButtonsSendEvent(ButtonRelease, iButton); 308 } 309 else if (iEventType == ButtonRelease 310 && pScreenPriv->fE3BFakeButton2Sent && !(wParam & MK_LBUTTON) 311 && !(wParam & MK_RBUTTON)) { 312 /* 313 * Fake button 2 was sent and both mouse buttons have now been released 314 */ 315 pScreenPriv->fE3BFakeButton2Sent = FALSE; 316 317 /* Send middle mouse button release */ 318 winMouseButtonsSendEvent(ButtonRelease, Button2); 319 } 320 else if (iEventType == ButtonRelease 321 && pScreenPriv->iE3BCachedPress == 0 322 && !pScreenPriv->fE3BFakeButton2Sent) { 323 /* 324 * Button was release, no button is cached, 325 * and there is no fake button 2 release is pending. 326 */ 327 winMouseButtonsSendEvent(ButtonRelease, iButton); 328 } 329 330 return 0; 331} 332 333/** 334 * Enqueue a motion event. 335 * 336 */ 337void 338winEnqueueMotion(int x, int y) 339{ 340 int valuators[2]; 341 ValuatorMask mask; 342 343 valuators[0] = x; 344 valuators[1] = y; 345 346 valuator_mask_set_range(&mask, 0, 2, valuators); 347 QueuePointerEvents(g_pwinPointer, MotionNotify, 0, 348 POINTER_ABSOLUTE | POINTER_SCREEN, &mask); 349 350} 351