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