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