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