winmouse.c revision 6747b715
105b261ecSmrg/*
205b261ecSmrg *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
305b261ecSmrg *
405b261ecSmrg *Permission is hereby granted, free of charge, to any person obtaining
505b261ecSmrg * a copy of this software and associated documentation files (the
605b261ecSmrg *"Software"), to deal in the Software without restriction, including
705b261ecSmrg *without limitation the rights to use, copy, modify, merge, publish,
805b261ecSmrg *distribute, sublicense, and/or sell copies of the Software, and to
905b261ecSmrg *permit persons to whom the Software is furnished to do so, subject to
1005b261ecSmrg *the following conditions:
1105b261ecSmrg *
1205b261ecSmrg *The above copyright notice and this permission notice shall be
1305b261ecSmrg *included in all copies or substantial portions of the Software.
1405b261ecSmrg *
1505b261ecSmrg *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1605b261ecSmrg *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1705b261ecSmrg *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1805b261ecSmrg *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
1905b261ecSmrg *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
2005b261ecSmrg *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2105b261ecSmrg *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2205b261ecSmrg *
2305b261ecSmrg *Except as contained in this notice, the name of the XFree86 Project
2405b261ecSmrg *shall not be used in advertising or otherwise to promote the sale, use
2505b261ecSmrg *or other dealings in this Software without prior written authorization
2605b261ecSmrg *from the XFree86 Project.
2705b261ecSmrg *
2805b261ecSmrg * Authors:	Dakshinamurthy Karra
2905b261ecSmrg *		Suhaib M Siddiqi
3005b261ecSmrg *		Peter Busch
3105b261ecSmrg *		Harold L Hunt II
3205b261ecSmrg */
3305b261ecSmrg
3405b261ecSmrg#ifdef HAVE_XWIN_CONFIG_H
3505b261ecSmrg#include <xwin-config.h>
3605b261ecSmrg#endif
3705b261ecSmrg#include "win.h"
3805b261ecSmrg
394642e01fSmrg#if defined(XFree86Server)
4005b261ecSmrg#include "inputstr.h"
416747b715Smrg#include "exevents.h" /* for button/axes labels */
426747b715Smrg#include "xserver-properties.h"
4305b261ecSmrg
4405b261ecSmrg/* Peek the internal button mapping */
4505b261ecSmrgstatic CARD8 const *g_winMouseButtonMap = NULL;
4605b261ecSmrg#endif
4705b261ecSmrg
4805b261ecSmrg
4905b261ecSmrg/*
5005b261ecSmrg * Local prototypes
5105b261ecSmrg */
5205b261ecSmrg
5305b261ecSmrgstatic void
5405b261ecSmrgwinMouseCtrl (DeviceIntPtr pDevice, PtrCtrl *pCtrl);
5505b261ecSmrg
5605b261ecSmrg
5705b261ecSmrgstatic void
5805b261ecSmrgwinMouseCtrl (DeviceIntPtr pDevice, PtrCtrl *pCtrl)
5905b261ecSmrg{
6005b261ecSmrg}
6105b261ecSmrg
6205b261ecSmrg
6305b261ecSmrg/*
6405b261ecSmrg * See Porting Layer Definition - p. 18
6505b261ecSmrg * This is known as a DeviceProc
6605b261ecSmrg */
6705b261ecSmrg
6805b261ecSmrgint
6905b261ecSmrgwinMouseProc (DeviceIntPtr pDeviceInt, int iState)
7005b261ecSmrg{
7105b261ecSmrg  int 			lngMouseButtons, i;
7205b261ecSmrg  int			lngWheelEvents = 2;
7305b261ecSmrg  CARD8			*map;
7405b261ecSmrg  DevicePtr		pDevice = (DevicePtr) pDeviceInt;
756747b715Smrg  Atom *btn_labels;
766747b715Smrg  Atom axes_labels[2];
7705b261ecSmrg
7805b261ecSmrg  switch (iState)
7905b261ecSmrg    {
8005b261ecSmrg    case DEVICE_INIT:
8105b261ecSmrg      /* Get number of mouse buttons */
8205b261ecSmrg      lngMouseButtons = GetSystemMetrics(SM_CMOUSEBUTTONS);
8305b261ecSmrg
8405b261ecSmrg      /* Mapping of windows events to X events:
8505b261ecSmrg       * LEFT:1 MIDDLE:2 RIGHT:3
8605b261ecSmrg       * SCROLL_UP:4 SCROLL_DOWN:5
8705b261ecSmrg       * XBUTTON 1:6 XBUTTON 2:7 ...
8805b261ecSmrg       *
8905b261ecSmrg       * To map scroll wheel correctly we need at least the 3 normal buttons
9005b261ecSmrg       */
9105b261ecSmrg      if (lngMouseButtons < 3)
9205b261ecSmrg        lngMouseButtons = 3;
9305b261ecSmrg      winMsg(X_PROBED, "%d mouse buttons found\n", lngMouseButtons);
9405b261ecSmrg
9505b261ecSmrg      /* allocate memory:
9605b261ecSmrg       * number of buttons + 2x mouse wheel event + 1 extra (offset for map)
9705b261ecSmrg       */
9805b261ecSmrg      map = malloc(sizeof(CARD8) * (lngMouseButtons + lngWheelEvents + 1));
9905b261ecSmrg
10005b261ecSmrg      /* initalize button map */
10105b261ecSmrg      map[0] = 0;
10205b261ecSmrg      for (i=1; i <= lngMouseButtons + lngWheelEvents; i++)
10305b261ecSmrg      	map[i] = i;
1046747b715Smrg
1056747b715Smrg      btn_labels = calloc((lngMouseButtons + lngWheelEvents), sizeof(Atom));
1066747b715Smrg      btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
1076747b715Smrg      btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
1086747b715Smrg      btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
1096747b715Smrg      btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
1106747b715Smrg      btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
1116747b715Smrg
1126747b715Smrg      axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
1136747b715Smrg      axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
1146747b715Smrg
11505b261ecSmrg      InitPointerDeviceStruct (pDevice,
11605b261ecSmrg			       map,
11705b261ecSmrg			       lngMouseButtons + lngWheelEvents,
1186747b715Smrg			       btn_labels,
11905b261ecSmrg			       winMouseCtrl,
12005b261ecSmrg			       GetMotionHistorySize(),
1216747b715Smrg			       2,
1226747b715Smrg			       axes_labels);
12305b261ecSmrg      free(map);
1246747b715Smrg      free(btn_labels);
12505b261ecSmrg
1264642e01fSmrg#if defined(XFree86Server)
12705b261ecSmrg      g_winMouseButtonMap = pDeviceInt->button->map;
12805b261ecSmrg#endif
12905b261ecSmrg      break;
13005b261ecSmrg
13105b261ecSmrg    case DEVICE_ON:
13205b261ecSmrg      pDevice->on = TRUE;
13305b261ecSmrg      break;
13405b261ecSmrg
13505b261ecSmrg    case DEVICE_CLOSE:
1364642e01fSmrg#if defined(XFree86Server)
13705b261ecSmrg      g_winMouseButtonMap = NULL;
13805b261ecSmrg#endif
13905b261ecSmrg    case DEVICE_OFF:
14005b261ecSmrg      pDevice->on = FALSE;
14105b261ecSmrg      break;
14205b261ecSmrg    }
14305b261ecSmrg  return Success;
14405b261ecSmrg}
14505b261ecSmrg
14605b261ecSmrg
14705b261ecSmrg/* Handle the mouse wheel */
14805b261ecSmrgint
14905b261ecSmrgwinMouseWheel (ScreenPtr pScreen, int iDeltaZ)
15005b261ecSmrg{
15105b261ecSmrg  winScreenPriv(pScreen);
15205b261ecSmrg  int button; /* Button4 or Button5 */
15305b261ecSmrg
15405b261ecSmrg  /* Button4 = WheelUp */
15505b261ecSmrg  /* Button5 = WheelDown */
15605b261ecSmrg
15705b261ecSmrg  /* Do we have any previous delta stored? */
15805b261ecSmrg  if ((pScreenPriv->iDeltaZ > 0
15905b261ecSmrg       && iDeltaZ > 0)
16005b261ecSmrg      || (pScreenPriv->iDeltaZ < 0
16105b261ecSmrg	  && iDeltaZ < 0))
16205b261ecSmrg    {
16305b261ecSmrg      /* Previous delta and of same sign as current delta */
16405b261ecSmrg      iDeltaZ += pScreenPriv->iDeltaZ;
16505b261ecSmrg      pScreenPriv->iDeltaZ = 0;
16605b261ecSmrg    }
16705b261ecSmrg  else
16805b261ecSmrg    {
16905b261ecSmrg      /*
17005b261ecSmrg       * Previous delta of different sign, or zero.
17105b261ecSmrg       * We will set it to zero for either case,
17205b261ecSmrg       * as blindly setting takes just as much time
17305b261ecSmrg       * as checking, then setting if necessary :)
17405b261ecSmrg       */
17505b261ecSmrg      pScreenPriv->iDeltaZ = 0;
17605b261ecSmrg    }
17705b261ecSmrg
17805b261ecSmrg  /*
17905b261ecSmrg   * Only process this message if the wheel has moved further than
18005b261ecSmrg   * WHEEL_DELTA
18105b261ecSmrg   */
18205b261ecSmrg  if (iDeltaZ >= WHEEL_DELTA || (-1 * iDeltaZ) >= WHEEL_DELTA)
18305b261ecSmrg    {
18405b261ecSmrg      pScreenPriv->iDeltaZ = 0;
18505b261ecSmrg
18605b261ecSmrg      /* Figure out how many whole deltas of the wheel we have */
18705b261ecSmrg      iDeltaZ /= WHEEL_DELTA;
18805b261ecSmrg    }
18905b261ecSmrg  else
19005b261ecSmrg    {
19105b261ecSmrg      /*
19205b261ecSmrg       * Wheel has not moved past WHEEL_DELTA threshold;
19305b261ecSmrg       * we will store the wheel delta until the threshold
19405b261ecSmrg       * has been reached.
19505b261ecSmrg       */
19605b261ecSmrg      pScreenPriv->iDeltaZ = iDeltaZ;
19705b261ecSmrg      return 0;
19805b261ecSmrg    }
19905b261ecSmrg
20005b261ecSmrg  /* Set the button to indicate up or down wheel delta */
20105b261ecSmrg  if (iDeltaZ > 0)
20205b261ecSmrg    {
20305b261ecSmrg      button = Button4;
20405b261ecSmrg    }
20505b261ecSmrg  else
20605b261ecSmrg    {
20705b261ecSmrg      button = Button5;
20805b261ecSmrg    }
20905b261ecSmrg
21005b261ecSmrg  /*
21105b261ecSmrg   * Flip iDeltaZ to positive, if negative,
21205b261ecSmrg   * because always need to generate a *positive* number of
21305b261ecSmrg   * button clicks for the Z axis.
21405b261ecSmrg   */
21505b261ecSmrg  if (iDeltaZ < 0)
21605b261ecSmrg    {
21705b261ecSmrg      iDeltaZ *= -1;
21805b261ecSmrg    }
21905b261ecSmrg
22005b261ecSmrg  /* Generate X input messages for each wheel delta we have seen */
22105b261ecSmrg  while (iDeltaZ--)
22205b261ecSmrg    {
22305b261ecSmrg      /* Push the wheel button */
22405b261ecSmrg      winMouseButtonsSendEvent (ButtonPress, button);
22505b261ecSmrg
22605b261ecSmrg      /* Release the wheel button */
22705b261ecSmrg      winMouseButtonsSendEvent (ButtonRelease, button);
22805b261ecSmrg    }
22905b261ecSmrg
23005b261ecSmrg  return 0;
23105b261ecSmrg}
23205b261ecSmrg
23305b261ecSmrg
23405b261ecSmrg/*
23505b261ecSmrg * Enqueue a mouse button event
23605b261ecSmrg */
23705b261ecSmrg
23805b261ecSmrgvoid
23905b261ecSmrgwinMouseButtonsSendEvent (int iEventType, int iButton)
24005b261ecSmrg{
2416747b715Smrg  EventListPtr events;
2426747b715Smrg  int i, nevents;
24305b261ecSmrg
2444642e01fSmrg#if defined(XFree86Server)
24505b261ecSmrg  if (g_winMouseButtonMap)
2466747b715Smrg    iButton = g_winMouseButtonMap[iButton];
2476747b715Smrg#endif
2486747b715Smrg
2496747b715Smrg  GetEventList(&events);
2506747b715Smrg  nevents = GetPointerEvents(events, g_pwinPointer, iEventType, iButton,
2516747b715Smrg			     POINTER_RELATIVE, 0, 0, NULL);
2526747b715Smrg
2536747b715Smrg  for (i = 0; i < nevents; i++)
2546747b715Smrg    mieqEnqueue(g_pwinPointer, events[i].event);
2556747b715Smrg
2566747b715Smrg#if CYGDEBUG
2576747b715Smrg  ErrorF("winMouseButtonsSendEvent: iEventType: %d, iButton: %d, nEvents %d\n",
2586747b715Smrg          iEventType, iButton, nevents);
25905b261ecSmrg#endif
26005b261ecSmrg}
26105b261ecSmrg
26205b261ecSmrg
26305b261ecSmrg/*
26405b261ecSmrg * Decide what to do with a Windows mouse message
26505b261ecSmrg */
26605b261ecSmrg
26705b261ecSmrgint
26805b261ecSmrgwinMouseButtonsHandle (ScreenPtr pScreen,
26905b261ecSmrg		       int iEventType, int iButton,
27005b261ecSmrg		       WPARAM wParam)
27105b261ecSmrg{
27205b261ecSmrg  winScreenPriv(pScreen);
27305b261ecSmrg  winScreenInfo		*pScreenInfo = pScreenPriv->pScreenInfo;
27405b261ecSmrg
27505b261ecSmrg  /* Send button events right away if emulate 3 buttons is off */
27605b261ecSmrg  if (pScreenInfo->iE3BTimeout == WIN_E3B_OFF)
27705b261ecSmrg    {
27805b261ecSmrg      /* Emulate 3 buttons is off, send the button event */
27905b261ecSmrg      winMouseButtonsSendEvent (iEventType, iButton);
28005b261ecSmrg      return 0;
28105b261ecSmrg    }
28205b261ecSmrg
28305b261ecSmrg  /* Emulate 3 buttons is on, let the fun begin */
28405b261ecSmrg  if (iEventType == ButtonPress
28505b261ecSmrg      && pScreenPriv->iE3BCachedPress == 0
28605b261ecSmrg      && !pScreenPriv->fE3BFakeButton2Sent)
28705b261ecSmrg    {
28805b261ecSmrg      /*
28905b261ecSmrg       * Button was pressed, no press is cached,
29005b261ecSmrg       * and there is no fake button 2 release pending.
29105b261ecSmrg       */
29205b261ecSmrg
29305b261ecSmrg      /* Store button press type */
29405b261ecSmrg      pScreenPriv->iE3BCachedPress = iButton;
29505b261ecSmrg
29605b261ecSmrg      /*
29705b261ecSmrg       * Set a timer to send this button press if the other button
29805b261ecSmrg       * is not pressed within the timeout time.
29905b261ecSmrg       */
30005b261ecSmrg      SetTimer (pScreenPriv->hwndScreen,
30105b261ecSmrg		WIN_E3B_TIMER_ID,
30205b261ecSmrg		pScreenInfo->iE3BTimeout,
30305b261ecSmrg		NULL);
30405b261ecSmrg    }
30505b261ecSmrg  else if (iEventType == ButtonPress
30605b261ecSmrg	   && pScreenPriv->iE3BCachedPress != 0
30705b261ecSmrg	   && pScreenPriv->iE3BCachedPress != iButton
30805b261ecSmrg	   && !pScreenPriv->fE3BFakeButton2Sent)
30905b261ecSmrg    {
31005b261ecSmrg      /*
31105b261ecSmrg       * Button press is cached, other button was pressed,
31205b261ecSmrg       * and there is no fake button 2 release pending.
31305b261ecSmrg       */
31405b261ecSmrg
31505b261ecSmrg      /* Mouse button was cached and other button was pressed */
31605b261ecSmrg      KillTimer (pScreenPriv->hwndScreen, WIN_E3B_TIMER_ID);
31705b261ecSmrg      pScreenPriv->iE3BCachedPress = 0;
31805b261ecSmrg
31905b261ecSmrg      /* Send fake middle button */
32005b261ecSmrg      winMouseButtonsSendEvent (ButtonPress, Button2);
32105b261ecSmrg
32205b261ecSmrg      /* Indicate that a fake middle button event was sent */
32305b261ecSmrg      pScreenPriv->fE3BFakeButton2Sent = TRUE;
32405b261ecSmrg    }
32505b261ecSmrg  else if (iEventType == ButtonRelease
32605b261ecSmrg	   && pScreenPriv->iE3BCachedPress == iButton)
32705b261ecSmrg    {
32805b261ecSmrg      /*
32905b261ecSmrg       * Cached button was released before timer ran out,
33005b261ecSmrg       * and before the other mouse button was pressed.
33105b261ecSmrg       */
33205b261ecSmrg      KillTimer (pScreenPriv->hwndScreen, WIN_E3B_TIMER_ID);
33305b261ecSmrg      pScreenPriv->iE3BCachedPress = 0;
33405b261ecSmrg
33505b261ecSmrg      /* Send cached press, then send release */
33605b261ecSmrg      winMouseButtonsSendEvent (ButtonPress, iButton);
33705b261ecSmrg      winMouseButtonsSendEvent (ButtonRelease, iButton);
33805b261ecSmrg    }
33905b261ecSmrg  else if (iEventType == ButtonRelease
34005b261ecSmrg	   && pScreenPriv->fE3BFakeButton2Sent
34105b261ecSmrg	   && !(wParam & MK_LBUTTON)
34205b261ecSmrg	   && !(wParam & MK_RBUTTON))
34305b261ecSmrg    {
34405b261ecSmrg      /*
34505b261ecSmrg       * Fake button 2 was sent and both mouse buttons have now been released
34605b261ecSmrg       */
34705b261ecSmrg      pScreenPriv->fE3BFakeButton2Sent = FALSE;
34805b261ecSmrg
34905b261ecSmrg      /* Send middle mouse button release */
35005b261ecSmrg      winMouseButtonsSendEvent (ButtonRelease, Button2);
35105b261ecSmrg    }
35205b261ecSmrg  else if (iEventType == ButtonRelease
35305b261ecSmrg	   && pScreenPriv->iE3BCachedPress == 0
35405b261ecSmrg	   && !pScreenPriv->fE3BFakeButton2Sent)
35505b261ecSmrg    {
35605b261ecSmrg      /*
35705b261ecSmrg       * Button was release, no button is cached,
35805b261ecSmrg       * and there is no fake button 2 release is pending.
35905b261ecSmrg       */
36005b261ecSmrg      winMouseButtonsSendEvent (ButtonRelease, iButton);
36105b261ecSmrg    }
36205b261ecSmrg
36305b261ecSmrg  return 0;
36405b261ecSmrg}
3656747b715Smrg
3666747b715Smrg/**
3676747b715Smrg * Enqueue a motion event.
3686747b715Smrg *
3696747b715Smrg *  XXX: miPointerMove does exactly this, but is static :-( (and uses a static buffer)
3706747b715Smrg *
3716747b715Smrg */
3726747b715Smrgvoid winEnqueueMotion(int x, int y)
3736747b715Smrg{
3746747b715Smrg  int i, nevents;
3756747b715Smrg  int valuators[2];
3766747b715Smrg  EventListPtr events;
3776747b715Smrg
3786747b715Smrg  miPointerSetPosition(g_pwinPointer, &x, &y);
3796747b715Smrg  valuators[0] = x;
3806747b715Smrg  valuators[1] = y;
3816747b715Smrg
3826747b715Smrg  GetEventList(&events);
3836747b715Smrg  nevents = GetPointerEvents(events, g_pwinPointer, MotionNotify, 0,
3846747b715Smrg			     POINTER_ABSOLUTE | POINTER_SCREEN, 0, 2, valuators);
3856747b715Smrg
3866747b715Smrg  for (i = 0; i < nevents; i++)
3876747b715Smrg    mieqEnqueue(g_pwinPointer, events[i].event);
3886747b715Smrg}
389