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