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/* 49 * Local prototypes 50 */ 51 52static void 53winMouseCtrl (DeviceIntPtr pDevice, PtrCtrl *pCtrl); 54 55 56static void 57winMouseCtrl (DeviceIntPtr pDevice, PtrCtrl *pCtrl) 58{ 59} 60 61 62/* 63 * See Porting Layer Definition - p. 18 64 * This is known as a DeviceProc 65 */ 66 67int 68winMouseProc (DeviceIntPtr pDeviceInt, int iState) 69{ 70 int lngMouseButtons, i; 71 int lngWheelEvents = 2; 72 CARD8 *map; 73 DevicePtr pDevice = (DevicePtr) pDeviceInt; 74 Atom *btn_labels; 75 Atom axes_labels[2]; 76 77 switch (iState) 78 { 79 case DEVICE_INIT: 80 /* Get number of mouse buttons */ 81 lngMouseButtons = GetSystemMetrics(SM_CMOUSEBUTTONS); 82 83 /* Mapping of windows events to X events: 84 * LEFT:1 MIDDLE:2 RIGHT:3 85 * SCROLL_UP:4 SCROLL_DOWN:5 86 * XBUTTON 1:6 XBUTTON 2:7 ... 87 * 88 * To map scroll wheel correctly we need at least the 3 normal buttons 89 */ 90 if (lngMouseButtons < 3) 91 lngMouseButtons = 3; 92 winMsg(X_PROBED, "%d mouse buttons found\n", lngMouseButtons); 93 94 /* allocate memory: 95 * number of buttons + 2x mouse wheel event + 1 extra (offset for map) 96 */ 97 map = malloc(sizeof(CARD8) * (lngMouseButtons + lngWheelEvents + 1)); 98 99 /* initalize button map */ 100 map[0] = 0; 101 for (i=1; i <= lngMouseButtons + lngWheelEvents; i++) 102 map[i] = i; 103 104 btn_labels = calloc((lngMouseButtons + lngWheelEvents), sizeof(Atom)); 105 btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); 106 btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); 107 btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); 108 btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP); 109 btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); 110 111 axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); 112 axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); 113 114 InitPointerDeviceStruct (pDevice, 115 map, 116 lngMouseButtons + lngWheelEvents, 117 btn_labels, 118 winMouseCtrl, 119 GetMotionHistorySize(), 120 2, 121 axes_labels); 122 free(map); 123 free(btn_labels); 124 125 g_winMouseButtonMap = pDeviceInt->button->map; 126 break; 127 128 case DEVICE_ON: 129 pDevice->on = TRUE; 130 break; 131 132 case DEVICE_CLOSE: 133 g_winMouseButtonMap = NULL; 134 135 case DEVICE_OFF: 136 pDevice->on = FALSE; 137 break; 138 } 139 return Success; 140} 141 142 143/* Handle the mouse wheel */ 144int 145winMouseWheel (ScreenPtr pScreen, int iDeltaZ) 146{ 147 winScreenPriv(pScreen); 148 int button; /* Button4 or Button5 */ 149 150 /* Button4 = WheelUp */ 151 /* Button5 = WheelDown */ 152 153 /* Do we have any previous delta stored? */ 154 if ((pScreenPriv->iDeltaZ > 0 155 && iDeltaZ > 0) 156 || (pScreenPriv->iDeltaZ < 0 157 && iDeltaZ < 0)) 158 { 159 /* Previous delta and of same sign as current delta */ 160 iDeltaZ += pScreenPriv->iDeltaZ; 161 pScreenPriv->iDeltaZ = 0; 162 } 163 else 164 { 165 /* 166 * Previous delta of different sign, or zero. 167 * We will set it to zero for either case, 168 * as blindly setting takes just as much time 169 * as checking, then setting if necessary :) 170 */ 171 pScreenPriv->iDeltaZ = 0; 172 } 173 174 /* 175 * Only process this message if the wheel has moved further than 176 * WHEEL_DELTA 177 */ 178 if (iDeltaZ >= WHEEL_DELTA || (-1 * iDeltaZ) >= WHEEL_DELTA) 179 { 180 pScreenPriv->iDeltaZ = 0; 181 182 /* Figure out how many whole deltas of the wheel we have */ 183 iDeltaZ /= WHEEL_DELTA; 184 } 185 else 186 { 187 /* 188 * Wheel has not moved past WHEEL_DELTA threshold; 189 * we will store the wheel delta until the threshold 190 * has been reached. 191 */ 192 pScreenPriv->iDeltaZ = iDeltaZ; 193 return 0; 194 } 195 196 /* Set the button to indicate up or down wheel delta */ 197 if (iDeltaZ > 0) 198 { 199 button = Button4; 200 } 201 else 202 { 203 button = Button5; 204 } 205 206 /* 207 * Flip iDeltaZ to positive, if negative, 208 * because always need to generate a *positive* number of 209 * button clicks for the Z axis. 210 */ 211 if (iDeltaZ < 0) 212 { 213 iDeltaZ *= -1; 214 } 215 216 /* Generate X input messages for each wheel delta we have seen */ 217 while (iDeltaZ--) 218 { 219 /* Push the wheel button */ 220 winMouseButtonsSendEvent (ButtonPress, button); 221 222 /* Release the wheel button */ 223 winMouseButtonsSendEvent (ButtonRelease, button); 224 } 225 226 return 0; 227} 228 229 230/* 231 * Enqueue a mouse button event 232 */ 233 234void 235winMouseButtonsSendEvent (int iEventType, int iButton) 236{ 237 EventListPtr events; 238 int i, nevents; 239 ValuatorMask mask; 240 241 if (g_winMouseButtonMap) 242 iButton = g_winMouseButtonMap[iButton]; 243 244 valuator_mask_zero(&mask); 245 GetEventList(&events); 246 nevents = GetPointerEvents(events, g_pwinPointer, iEventType, iButton, 247 POINTER_RELATIVE, &mask); 248 249 for (i = 0; i < nevents; i++) 250 mieqEnqueue(g_pwinPointer, (InternalEvent*)events[i].event); 251 252#if CYGDEBUG 253 ErrorF("winMouseButtonsSendEvent: iEventType: %d, iButton: %d, nEvents %d\n", 254 iEventType, iButton, nevents); 255#endif 256} 257 258 259/* 260 * Decide what to do with a Windows mouse message 261 */ 262 263int 264winMouseButtonsHandle (ScreenPtr pScreen, 265 int iEventType, int iButton, 266 WPARAM wParam) 267{ 268 winScreenPriv(pScreen); 269 winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; 270 271 /* Send button events right away if emulate 3 buttons is off */ 272 if (pScreenInfo->iE3BTimeout == WIN_E3B_OFF) 273 { 274 /* Emulate 3 buttons is off, send the button event */ 275 winMouseButtonsSendEvent (iEventType, iButton); 276 return 0; 277 } 278 279 /* Emulate 3 buttons is on, let the fun begin */ 280 if (iEventType == ButtonPress 281 && pScreenPriv->iE3BCachedPress == 0 282 && !pScreenPriv->fE3BFakeButton2Sent) 283 { 284 /* 285 * Button was pressed, no press is cached, 286 * and there is no fake button 2 release pending. 287 */ 288 289 /* Store button press type */ 290 pScreenPriv->iE3BCachedPress = iButton; 291 292 /* 293 * Set a timer to send this button press if the other button 294 * is not pressed within the timeout time. 295 */ 296 SetTimer (pScreenPriv->hwndScreen, 297 WIN_E3B_TIMER_ID, 298 pScreenInfo->iE3BTimeout, 299 NULL); 300 } 301 else if (iEventType == ButtonPress 302 && pScreenPriv->iE3BCachedPress != 0 303 && pScreenPriv->iE3BCachedPress != iButton 304 && !pScreenPriv->fE3BFakeButton2Sent) 305 { 306 /* 307 * Button press is cached, other button was pressed, 308 * and there is no fake button 2 release pending. 309 */ 310 311 /* Mouse button was cached and other button was pressed */ 312 KillTimer (pScreenPriv->hwndScreen, WIN_E3B_TIMER_ID); 313 pScreenPriv->iE3BCachedPress = 0; 314 315 /* Send fake middle button */ 316 winMouseButtonsSendEvent (ButtonPress, Button2); 317 318 /* Indicate that a fake middle button event was sent */ 319 pScreenPriv->fE3BFakeButton2Sent = TRUE; 320 } 321 else if (iEventType == ButtonRelease 322 && pScreenPriv->iE3BCachedPress == iButton) 323 { 324 /* 325 * Cached button was released before timer ran out, 326 * and before the other mouse button was pressed. 327 */ 328 KillTimer (pScreenPriv->hwndScreen, WIN_E3B_TIMER_ID); 329 pScreenPriv->iE3BCachedPress = 0; 330 331 /* Send cached press, then send release */ 332 winMouseButtonsSendEvent (ButtonPress, iButton); 333 winMouseButtonsSendEvent (ButtonRelease, iButton); 334 } 335 else if (iEventType == ButtonRelease 336 && pScreenPriv->fE3BFakeButton2Sent 337 && !(wParam & MK_LBUTTON) 338 && !(wParam & MK_RBUTTON)) 339 { 340 /* 341 * Fake button 2 was sent and both mouse buttons have now been released 342 */ 343 pScreenPriv->fE3BFakeButton2Sent = FALSE; 344 345 /* Send middle mouse button release */ 346 winMouseButtonsSendEvent (ButtonRelease, Button2); 347 } 348 else if (iEventType == ButtonRelease 349 && pScreenPriv->iE3BCachedPress == 0 350 && !pScreenPriv->fE3BFakeButton2Sent) 351 { 352 /* 353 * Button was release, no button is cached, 354 * and there is no fake button 2 release is pending. 355 */ 356 winMouseButtonsSendEvent (ButtonRelease, iButton); 357 } 358 359 return 0; 360} 361 362/** 363 * Enqueue a motion event. 364 * 365 * XXX: miPointerMove does exactly this, but is static :-( (and uses a static buffer) 366 * 367 */ 368void winEnqueueMotion(int x, int y) 369{ 370 int i, nevents; 371 int valuators[2]; 372 ValuatorMask mask; 373 EventListPtr events; 374 375 miPointerSetPosition(g_pwinPointer, &x, &y); 376 valuators[0] = x; 377 valuators[1] = y; 378 379 valuator_mask_set_range(&mask, 0, 2, valuators); 380 GetEventList(&events); 381 nevents = GetPointerEvents(events, g_pwinPointer, MotionNotify, 0, 382 POINTER_ABSOLUTE | POINTER_SCREEN, &mask); 383 384 for (i = 0; i < nevents; i++) 385 mieqEnqueue(g_pwinPointer, (InternalEvent*)events[i].event); 386} 387