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