initial commit
[profile/ivi/xorg-x11-server.git] / hw / xwin / winmouse.c
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 */
45 static CARD8 const *g_winMouseButtonMap = NULL;
46 #endif
47
48
49 /*
50  * Local prototypes
51  */
52
53 static void
54 winMouseCtrl (DeviceIntPtr pDevice, PtrCtrl *pCtrl);
55
56
57 static void
58 winMouseCtrl (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
68 int
69 winMouseProc (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 */
148 int
149 winMouseWheel (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
238 void
239 winMouseButtonsSendEvent (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
267 int
268 winMouseButtonsHandle (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  */
372 void 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 }