1e8a9312aStsutsui/*
2e8a9312aStsutsui *
3e8a9312aStsutsui * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
4e8a9312aStsutsui * Copyright 1993 by David Dawes <dawes@xfree86.org>
5e8a9312aStsutsui * Copyright 2002 by SuSE Linux AG, Author: Egbert Eich
6e8a9312aStsutsui * Copyright 1994-2002 by The XFree86 Project, Inc.
7e8a9312aStsutsui * Copyright 2002 by Paul Elliott
8e8a9312aStsutsui *
9e8a9312aStsutsui * Permission to use, copy, modify, distribute, and sell this software and its
10e8a9312aStsutsui * documentation for any purpose is hereby granted without fee, provided that
11e8a9312aStsutsui * the above copyright notice appear in all copies and that both that
12e8a9312aStsutsui * copyright notice and this permission notice appear in supporting
13e8a9312aStsutsui * documentation, and that the names of copyright holders not be
14e8a9312aStsutsui * used in advertising or publicity pertaining to distribution of the
15e8a9312aStsutsui * software without specific, written prior permission.  The copyright holders
16e8a9312aStsutsui * make no representations about the suitability of this
17e8a9312aStsutsui * software for any purpose.  It is provided "as is" without express or
18e8a9312aStsutsui * implied warranty.
19e8a9312aStsutsui *
20e8a9312aStsutsui * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
21e8a9312aStsutsui * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
22e8a9312aStsutsui * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
23e8a9312aStsutsui * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
24e8a9312aStsutsui * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
25e8a9312aStsutsui * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
26e8a9312aStsutsui * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
27e8a9312aStsutsui *
28e8a9312aStsutsui */
29e8a9312aStsutsui
30e8a9312aStsutsui/*
31e8a9312aStsutsui * 3 button emulation stuff
32e8a9312aStsutsui * based on the emulation method in xf86-input-mouse/dist/src/mouse.c
33e8a9312aStsutsui */
34e8a9312aStsutsui
35e8a9312aStsutsui#include "inpututils.h"
36e8a9312aStsutsui#include "mouseEmu3btn.h"
37e8a9312aStsutsui
38e8a9312aStsutsuistatic CARD32 buttonTimer(MouseEmu3btnPtr pEmu3btn);
39e8a9312aStsutsuistatic void Emulate3ButtonsSetEnabled(MouseEmu3btnPtr pEmu3btn, Bool enable);
40e8a9312aStsutsuistatic Bool Emulate3ButtonsSoft(MouseEmu3btnPtr pEmu3btn);
41e8a9312aStsutsui
42e8a9312aStsutsuistatic void MouseBlockHandler(void *data, void *waitTime);
43e8a9312aStsutsuistatic void MouseWakeupHandler(void *data, int i);
44e8a9312aStsutsui
45e8a9312aStsutsui/**********************************************************************
46e8a9312aStsutsui *
47e8a9312aStsutsui *  Emulate3Button support code
48e8a9312aStsutsui *
49e8a9312aStsutsui **********************************************************************/
50e8a9312aStsutsui
51e8a9312aStsutsui
52e8a9312aStsutsui/*
53e8a9312aStsutsui * Lets create a simple finite-state machine for 3 button emulation:
54e8a9312aStsutsui *
55e8a9312aStsutsui * We track buttons 1 and 3 (left and right).  There are 11 states:
56e8a9312aStsutsui *   0 ground           - initial state
57e8a9312aStsutsui *   1 delayed left     - left pressed, waiting for right
58e8a9312aStsutsui *   2 delayed right    - right pressed, waiting for left
59e8a9312aStsutsui *   3 pressed middle   - right and left pressed, emulated middle sent
60e8a9312aStsutsui *   4 pressed left     - left pressed and sent
61e8a9312aStsutsui *   5 pressed right    - right pressed and sent
62e8a9312aStsutsui *   6 released left    - left released after emulated middle
63e8a9312aStsutsui *   7 released right   - right released after emulated middle
64e8a9312aStsutsui *   8 repressed left   - left pressed after released left
65e8a9312aStsutsui *   9 repressed right  - right pressed after released right
66e8a9312aStsutsui *  10 pressed both     - both pressed, not emulating middle
67e8a9312aStsutsui */
68e8a9312aStsutsui#define ST_INVALID		-1
69e8a9312aStsutsui#define ST_GROUND		0	/* initial state */
70e8a9312aStsutsui#define ST_DELAYED_LEFT		1	/* left pressed and waiting timeout */
71e8a9312aStsutsui#define ST_DELAYED_RIGHT	2	/* right pressed and waiting timeout */
72e8a9312aStsutsui#define ST_PRESSED_MIDDLE	3	/* middle pressed deteremined */
73e8a9312aStsutsui#define ST_PRESSED_LEFT		4	/* left pressed determined */
74e8a9312aStsutsui#define ST_PRESSED_RIGHT	5	/* right pressed determined */
75e8a9312aStsutsui#define ST_RELEASED_LEFT	6	/* left released after pressed both */
76e8a9312aStsutsui#define ST_RELEASED_RIGHT	7	/* right released after pressed both */
77e8a9312aStsutsui#define ST_REPRESSED_LEFT	8	/* left repressed after release */
78e8a9312aStsutsui#define ST_REPRESSED_RIGHT	9	/* right repressed after release  */
79e8a9312aStsutsui#define ST_PRESSED_BOTH		10	/* both pressed (not as middle) */
80e8a9312aStsutsui#define NSTATES			11
81e8a9312aStsutsui
82e8a9312aStsutsui/*
83e8a9312aStsutsui * At each state, we need handlers for the following events
84e8a9312aStsutsui *   0: no buttons down
85e8a9312aStsutsui *   1: left button down
86e8a9312aStsutsui *   2: right button down
87e8a9312aStsutsui *   3: both buttons down
88e8a9312aStsutsui *   4: emulate3Timeout passed without a button change
89e8a9312aStsutsui * Note that button events are not deltas, they are the set of buttons being
90e8a9312aStsutsui * pressed now.  It's possible (ie, mouse hardware does it) to go from (eg)
91e8a9312aStsutsui * left down to right down without anything in between, so all cases must be
92e8a9312aStsutsui * handled.
93e8a9312aStsutsui *
94e8a9312aStsutsui * a handler consists of three values:
95e8a9312aStsutsui *   0: action1
96e8a9312aStsutsui *   1: action2
97e8a9312aStsutsui *   2: new emulation state
98e8a9312aStsutsui */
99e8a9312aStsutsuistruct button_event {
100e8a9312aStsutsui	int type;	/* ButtonNone / ButtonPress / ButtonRelease */
101e8a9312aStsutsui#define ButtonNone	0
102e8a9312aStsutsui	int button;
103e8a9312aStsutsui#define ButtonLeft	Button1
104e8a9312aStsutsui#define ButtonMiddle	Button2
105e8a9312aStsutsui#define ButtonRight	Button3
106e8a9312aStsutsui};
107e8a9312aStsutsui
108e8a9312aStsutsuistruct button_action {
109e8a9312aStsutsui	struct button_event event1;
110e8a9312aStsutsui	struct button_event event2;
111e8a9312aStsutsui	int new_state;
112e8a9312aStsutsui};
113e8a9312aStsutsui
114e8a9312aStsutsui/* The set of buttons being pressed passed from DDX mouse events */
115e8a9312aStsutsui#define BMASK_LEFT	0x01
116e8a9312aStsutsui#define BMASK_MIDDLE	0x02
117e8a9312aStsutsui#define BMASK_RIGHT	0x04
118e8a9312aStsutsui
119e8a9312aStsutsui/* Event index values per buttons being pressed */
120e8a9312aStsutsui#define EMU_BUTTONS_NONE	0
121e8a9312aStsutsui#define EMU_BUTTONS_LEFT	1
122e8a9312aStsutsui#define EMU_BUTTONS_RIGHT	2
123e8a9312aStsutsui#define EMU_BUTTONS_BOTH	3
124e8a9312aStsutsui#define NEMU_BUTTONSTATE	4
125e8a9312aStsutsui
126e8a9312aStsutsui#define BMASKTOINDEX(bmask)						\
127e8a9312aStsutsui	((((bmask) & BMASK_RIGHT) >> 1) | ((bmask) & BMASK_LEFT))
128e8a9312aStsutsui
129e8a9312aStsutsuistruct button_state {
130e8a9312aStsutsui	struct button_action buttons[NEMU_BUTTONSTATE];
131e8a9312aStsutsui	struct button_action timeout;
132e8a9312aStsutsui};
133e8a9312aStsutsui
134e8a9312aStsutsui/*
135e8a9312aStsutsui * The comment preceeding each section is the current emulation state.
136e8a9312aStsutsui * The comments to the right are of the form
137e8a9312aStsutsui *      <button state> (<events>) -> <new emulation state>
138e8a9312aStsutsui * which should be read as
139e8a9312aStsutsui *      If the buttons are in <button state>, generate <events> then go to
140e8a9312aStsutsui *      <new emulation state>.
141e8a9312aStsutsui */
142e8a9312aStsutsuistatic const struct button_state stateTab[NSTATES] = {
143e8a9312aStsutsui
144e8a9312aStsutsui  /*   0 ground           - initial state */
145e8a9312aStsutsui  [ST_GROUND] = {
146e8a9312aStsutsui
147e8a9312aStsutsui    .buttons[EMU_BUTTONS_NONE] = {
148e8a9312aStsutsui      /* nothing -> ground (no change) */
149e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
150e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
151e8a9312aStsutsui      .new_state = ST_GROUND,
152e8a9312aStsutsui    },
153e8a9312aStsutsui
154e8a9312aStsutsui    .buttons[EMU_BUTTONS_LEFT] = {
155e8a9312aStsutsui      /* left -> delayed left */
156e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
157e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
158e8a9312aStsutsui      .new_state = ST_DELAYED_LEFT,
159e8a9312aStsutsui    },
160e8a9312aStsutsui
161e8a9312aStsutsui    .buttons[EMU_BUTTONS_RIGHT] = {
162e8a9312aStsutsui      /* right -> delayed right */
163e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
164e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
165e8a9312aStsutsui      .new_state = ST_DELAYED_RIGHT,
166e8a9312aStsutsui    },
167e8a9312aStsutsui
168e8a9312aStsutsui    .buttons[EMU_BUTTONS_BOTH] = {
169e8a9312aStsutsui      /* left & right (middle press) -> pressed middle */
170e8a9312aStsutsui      .event1 = { ButtonPress,   ButtonMiddle },
171e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
172e8a9312aStsutsui      .new_state = ST_PRESSED_MIDDLE,
173e8a9312aStsutsui    },
174e8a9312aStsutsui
175e8a9312aStsutsui    .timeout = {
176e8a9312aStsutsui      /* timeout N/A */
177e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
178e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
179e8a9312aStsutsui      .new_state = ST_INVALID,
180e8a9312aStsutsui    },
181e8a9312aStsutsui  },
182e8a9312aStsutsui
183e8a9312aStsutsui  /*   1 delayed left     - left pressed, waiting for right */
184e8a9312aStsutsui  [ST_DELAYED_LEFT] = {
185e8a9312aStsutsui
186e8a9312aStsutsui    .buttons[EMU_BUTTONS_NONE] = {
187e8a9312aStsutsui      /* nothing (left event) -> ground */
188e8a9312aStsutsui      .event1 = { ButtonPress,   ButtonLeft   },
189e8a9312aStsutsui      .event2 = { ButtonRelease, ButtonLeft   },
190e8a9312aStsutsui      .new_state = ST_GROUND,
191e8a9312aStsutsui    },
192e8a9312aStsutsui
193e8a9312aStsutsui    .buttons[EMU_BUTTONS_LEFT] = {
194e8a9312aStsutsui      /* left -> delayed left (no change) */
195e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
196e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
197e8a9312aStsutsui      .new_state = ST_DELAYED_LEFT,
198e8a9312aStsutsui    },
199e8a9312aStsutsui
200e8a9312aStsutsui    .buttons[EMU_BUTTONS_RIGHT] = {
201e8a9312aStsutsui      /* right (left event) -> delayed right */
202e8a9312aStsutsui      .event1 = { ButtonPress,   ButtonLeft   },
203e8a9312aStsutsui      .event2 = { ButtonRelease, ButtonLeft   },
204e8a9312aStsutsui      .new_state = ST_DELAYED_RIGHT,
205e8a9312aStsutsui    },
206e8a9312aStsutsui
207e8a9312aStsutsui    .buttons[EMU_BUTTONS_BOTH] = {
208e8a9312aStsutsui      /* left & right (middle press) -> pressed middle */
209e8a9312aStsutsui      .event1 = { ButtonPress,   ButtonMiddle },
210e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
211e8a9312aStsutsui      .new_state = ST_PRESSED_MIDDLE,
212e8a9312aStsutsui    },
213e8a9312aStsutsui
214e8a9312aStsutsui    .timeout = {
215e8a9312aStsutsui     /* timeout (left press) -> pressed left */
216e8a9312aStsutsui      .event1 = { ButtonPress,   ButtonLeft   },
217e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
218e8a9312aStsutsui      .new_state = ST_PRESSED_LEFT,
219e8a9312aStsutsui    },
220e8a9312aStsutsui  },
221e8a9312aStsutsui
222e8a9312aStsutsui  /*   2 delayed right    - right pressed, waiting for left */
223e8a9312aStsutsui  [ST_DELAYED_RIGHT] = {
224e8a9312aStsutsui
225e8a9312aStsutsui    .buttons[EMU_BUTTONS_NONE] = {
226e8a9312aStsutsui      /* nothing (right event) -> ground */
227e8a9312aStsutsui      .event1 = { ButtonPress,   ButtonRight  },
228e8a9312aStsutsui      .event2 = { ButtonRelease, ButtonRight  },
229e8a9312aStsutsui      .new_state = ST_GROUND,
230e8a9312aStsutsui    },
231e8a9312aStsutsui
232e8a9312aStsutsui    .buttons[EMU_BUTTONS_LEFT] = {
233e8a9312aStsutsui      /* left (right event) -> delayed left */
234e8a9312aStsutsui      .event1 = { ButtonPress,   ButtonRight  },
235e8a9312aStsutsui      .event2 = { ButtonRelease, ButtonRight  },
236e8a9312aStsutsui      .new_state = ST_DELAYED_LEFT,
237e8a9312aStsutsui    },
238e8a9312aStsutsui
239e8a9312aStsutsui    .buttons[EMU_BUTTONS_RIGHT] = {
240e8a9312aStsutsui      /* right -> delayed right (no change) */
241e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
242e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
243e8a9312aStsutsui      .new_state = ST_DELAYED_RIGHT,
244e8a9312aStsutsui    },
245e8a9312aStsutsui
246e8a9312aStsutsui    .buttons[EMU_BUTTONS_BOTH] = {
247e8a9312aStsutsui      /* left & right (middle press) -> pressed middle */
248e8a9312aStsutsui      .event1 = { ButtonPress,   ButtonMiddle },
249e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
250e8a9312aStsutsui      .new_state = ST_PRESSED_MIDDLE,
251e8a9312aStsutsui    },
252e8a9312aStsutsui
253e8a9312aStsutsui    .timeout = {
254e8a9312aStsutsui     /* timeout (right press) -> pressed right */
255e8a9312aStsutsui      .event1 = { ButtonPress,   ButtonRight  },
256e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
257e8a9312aStsutsui      .new_state = ST_PRESSED_RIGHT,
258e8a9312aStsutsui    },
259e8a9312aStsutsui  },
260e8a9312aStsutsui
261e8a9312aStsutsui  /*   3 pressed middle   - right and left pressed, emulated middle sent */
262e8a9312aStsutsui  [ST_PRESSED_MIDDLE] = {
263e8a9312aStsutsui
264e8a9312aStsutsui    .buttons[EMU_BUTTONS_NONE] = {
265e8a9312aStsutsui      /* nothing (middle release) -> ground */
266e8a9312aStsutsui      .event1 = { ButtonRelease, ButtonMiddle },
267e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
268e8a9312aStsutsui      .new_state = ST_GROUND,
269e8a9312aStsutsui    },
270e8a9312aStsutsui
271e8a9312aStsutsui    .buttons[EMU_BUTTONS_LEFT] = {
272e8a9312aStsutsui      /* left -> released right */
273e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
274e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
275e8a9312aStsutsui      .new_state = ST_RELEASED_RIGHT,
276e8a9312aStsutsui    },
277e8a9312aStsutsui
278e8a9312aStsutsui    .buttons[EMU_BUTTONS_RIGHT] = {
279e8a9312aStsutsui      /* right -> released left */
280e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
281e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
282e8a9312aStsutsui      .new_state = ST_RELEASED_LEFT,
283e8a9312aStsutsui    },
284e8a9312aStsutsui
285e8a9312aStsutsui    .buttons[EMU_BUTTONS_BOTH] = {
286e8a9312aStsutsui      /* left & right -> pressed middle (no change) */
287e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
288e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
289e8a9312aStsutsui      .new_state = ST_PRESSED_MIDDLE,
290e8a9312aStsutsui    },
291e8a9312aStsutsui
292e8a9312aStsutsui    .timeout = {
293e8a9312aStsutsui      /* timeout N/A */
294e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
295e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
296e8a9312aStsutsui      .new_state = ST_INVALID,
297e8a9312aStsutsui    },
298e8a9312aStsutsui  },
299e8a9312aStsutsui
300e8a9312aStsutsui  /*   4 pressed left     - left pressed and sent */
301e8a9312aStsutsui  [ST_PRESSED_LEFT] = {
302e8a9312aStsutsui
303e8a9312aStsutsui    .buttons[EMU_BUTTONS_NONE] = {
304e8a9312aStsutsui      /* nothing (left release) -> ground */
305e8a9312aStsutsui      .event1 = { ButtonRelease, ButtonLeft   },
306e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
307e8a9312aStsutsui      .new_state = ST_GROUND,
308e8a9312aStsutsui    },
309e8a9312aStsutsui
310e8a9312aStsutsui    .buttons[EMU_BUTTONS_LEFT] = {
311e8a9312aStsutsui      /* left -> pressed left (no change) */
312e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
313e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
314e8a9312aStsutsui      .new_state = ST_PRESSED_LEFT,
315e8a9312aStsutsui    },
316e8a9312aStsutsui
317e8a9312aStsutsui    .buttons[EMU_BUTTONS_RIGHT] = {
318e8a9312aStsutsui      /* right (left release) -> delayed right */
319e8a9312aStsutsui      .event1 = { ButtonRelease, ButtonLeft   },
320e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
321e8a9312aStsutsui      .new_state = ST_DELAYED_RIGHT,
322e8a9312aStsutsui    },
323e8a9312aStsutsui
324e8a9312aStsutsui    .buttons[EMU_BUTTONS_BOTH] = {
325e8a9312aStsutsui      /* left & right (right press) -> pressed both */
326e8a9312aStsutsui      .event1 = { ButtonPress,   ButtonRight  },
327e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
328e8a9312aStsutsui      .new_state = ST_PRESSED_BOTH,
329e8a9312aStsutsui    },
330e8a9312aStsutsui
331e8a9312aStsutsui    .timeout = {
332e8a9312aStsutsui      /* timeout N/A */
333e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
334e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
335e8a9312aStsutsui      .new_state = ST_INVALID,
336e8a9312aStsutsui    },
337e8a9312aStsutsui  },
338e8a9312aStsutsui
339e8a9312aStsutsui  /*   5 pressed right    - right pressed and sent */
340e8a9312aStsutsui  [ST_PRESSED_RIGHT] = {
341e8a9312aStsutsui
342e8a9312aStsutsui    .buttons[EMU_BUTTONS_NONE] = {
343e8a9312aStsutsui      /* nothing (right release) -> ground */
344e8a9312aStsutsui      .event1 = { ButtonRelease, ButtonRight  },
345e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
346e8a9312aStsutsui      .new_state = ST_GROUND,
347e8a9312aStsutsui    },
348e8a9312aStsutsui
349e8a9312aStsutsui    .buttons[EMU_BUTTONS_LEFT] = {
350e8a9312aStsutsui      /* left (right release) -> delayed left */
351e8a9312aStsutsui      .event1 = { ButtonRelease, ButtonRight  },
352e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
353e8a9312aStsutsui      .new_state = ST_DELAYED_LEFT,
354e8a9312aStsutsui    },
355e8a9312aStsutsui
356e8a9312aStsutsui    .buttons[EMU_BUTTONS_RIGHT] = {
357e8a9312aStsutsui      /* right -> pressed right (no change) */
358e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
359e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
360e8a9312aStsutsui      .new_state = ST_PRESSED_RIGHT,
361e8a9312aStsutsui    },
362e8a9312aStsutsui
363e8a9312aStsutsui    .buttons[EMU_BUTTONS_BOTH] = {
364e8a9312aStsutsui      /* left & right (left press) -> pressed both */
365e8a9312aStsutsui      .event1 = { ButtonPress,   ButtonLeft   },
366e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
367e8a9312aStsutsui      .new_state = ST_PRESSED_BOTH,
368e8a9312aStsutsui    },
369e8a9312aStsutsui
370e8a9312aStsutsui    .timeout = {
371e8a9312aStsutsui      /* timeout N/A */
372e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
373e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
374e8a9312aStsutsui      .new_state = ST_INVALID,
375e8a9312aStsutsui    },
376e8a9312aStsutsui  },
377e8a9312aStsutsui
378e8a9312aStsutsui  /*   6 released left    - left released after emulated middle */
379e8a9312aStsutsui  [ST_RELEASED_LEFT] = {
380e8a9312aStsutsui
381e8a9312aStsutsui    .buttons[EMU_BUTTONS_NONE] = {
382e8a9312aStsutsui      /* nothing (middle release) -> ground */
383e8a9312aStsutsui      .event1 = { ButtonRelease, ButtonMiddle },
384e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
385e8a9312aStsutsui      .new_state = ST_GROUND,
386e8a9312aStsutsui    },
387e8a9312aStsutsui
388e8a9312aStsutsui    .buttons[EMU_BUTTONS_LEFT] = {
389e8a9312aStsutsui      /* left (middle release) -> delayed left */
390e8a9312aStsutsui      .event1 = { ButtonRelease, ButtonMiddle },
391e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
392e8a9312aStsutsui      .new_state = ST_DELAYED_LEFT,
393e8a9312aStsutsui    },
394e8a9312aStsutsui
395e8a9312aStsutsui    .buttons[EMU_BUTTONS_RIGHT] = {
396e8a9312aStsutsui      /* right -> released left (no change) */
397e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
398e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
399e8a9312aStsutsui      .new_state = ST_RELEASED_LEFT,
400e8a9312aStsutsui    },
401e8a9312aStsutsui
402e8a9312aStsutsui    .buttons[EMU_BUTTONS_BOTH] = {
403e8a9312aStsutsui      /* left & right (left press) -> repressed left */
404e8a9312aStsutsui      .event1 = { ButtonPress,   ButtonLeft   },
405e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
406e8a9312aStsutsui      .new_state = ST_REPRESSED_LEFT,
407e8a9312aStsutsui    },
408e8a9312aStsutsui
409e8a9312aStsutsui    .timeout = {
410e8a9312aStsutsui      /* timeout N/A */
411e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
412e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
413e8a9312aStsutsui      .new_state = ST_INVALID,
414e8a9312aStsutsui    },
415e8a9312aStsutsui  },
416e8a9312aStsutsui
417e8a9312aStsutsui  /*   7 released right   - right released after emulated middle */
418e8a9312aStsutsui  [ST_RELEASED_RIGHT] = {
419e8a9312aStsutsui
420e8a9312aStsutsui    .buttons[EMU_BUTTONS_NONE] = {
421e8a9312aStsutsui      /* nothing (middle release) -> ground */
422e8a9312aStsutsui      .event1 = { ButtonRelease, ButtonMiddle },
423e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
424e8a9312aStsutsui      .new_state = ST_GROUND,
425e8a9312aStsutsui    },
426e8a9312aStsutsui
427e8a9312aStsutsui    .buttons[EMU_BUTTONS_LEFT] = {
428e8a9312aStsutsui      /* left -> released right (no change) */
429e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
430e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
431e8a9312aStsutsui      .new_state = ST_RELEASED_RIGHT,
432e8a9312aStsutsui    },
433e8a9312aStsutsui
434e8a9312aStsutsui    .buttons[EMU_BUTTONS_RIGHT] = {
435e8a9312aStsutsui      /* right (middle release) -> delayed right */
436e8a9312aStsutsui      .event1 = { ButtonRelease, ButtonMiddle },
437e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
438e8a9312aStsutsui      .new_state = ST_DELAYED_RIGHT,
439e8a9312aStsutsui    },
440e8a9312aStsutsui
441e8a9312aStsutsui    .buttons[EMU_BUTTONS_BOTH] = {
442e8a9312aStsutsui      /* left & right (right press) -> repressed right */
443e8a9312aStsutsui      .event1 = { ButtonPress,   ButtonRight  },
444e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
445e8a9312aStsutsui      .new_state = ST_REPRESSED_RIGHT,
446e8a9312aStsutsui    },
447e8a9312aStsutsui
448e8a9312aStsutsui    .timeout = {
449e8a9312aStsutsui      /* timeout N/A */
450e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
451e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
452e8a9312aStsutsui      .new_state = ST_INVALID,
453e8a9312aStsutsui    },
454e8a9312aStsutsui  },
455e8a9312aStsutsui
456e8a9312aStsutsui  /*   8 repressed left   - left pressed after released left */
457e8a9312aStsutsui  [ST_REPRESSED_LEFT] = {
458e8a9312aStsutsui
459e8a9312aStsutsui    .buttons[EMU_BUTTONS_NONE] = {
460e8a9312aStsutsui      /* nothing (middle release, left release) -> ground */
461e8a9312aStsutsui      .event1 = { ButtonRelease, ButtonMiddle },
462e8a9312aStsutsui      .event2 = { ButtonRelease, ButtonLeft   },
463e8a9312aStsutsui      .new_state = ST_GROUND,
464e8a9312aStsutsui    },
465e8a9312aStsutsui
466e8a9312aStsutsui    .buttons[EMU_BUTTONS_LEFT] = {
467e8a9312aStsutsui      /* left (middle release) -> pressed left */
468e8a9312aStsutsui      .event1 = { ButtonRelease, ButtonMiddle },
469e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
470e8a9312aStsutsui      .new_state = ST_PRESSED_LEFT,
471e8a9312aStsutsui    },
472e8a9312aStsutsui
473e8a9312aStsutsui    .buttons[EMU_BUTTONS_RIGHT] = {
474e8a9312aStsutsui      /* right (left release) -> released left */
475e8a9312aStsutsui      .event1 = { ButtonRelease, ButtonLeft   },
476e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
477e8a9312aStsutsui      .new_state = ST_RELEASED_LEFT,
478e8a9312aStsutsui    },
479e8a9312aStsutsui
480e8a9312aStsutsui    .buttons[EMU_BUTTONS_BOTH] = {
481e8a9312aStsutsui      /* left & right -> repressed left (no change) */
482e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
483e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
484e8a9312aStsutsui      .new_state = ST_REPRESSED_LEFT,
485e8a9312aStsutsui    },
486e8a9312aStsutsui
487e8a9312aStsutsui    .timeout = {
488e8a9312aStsutsui      /* timeout N/A */
489e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
490e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
491e8a9312aStsutsui      .new_state = ST_INVALID,
492e8a9312aStsutsui    },
493e8a9312aStsutsui  },
494e8a9312aStsutsui
495e8a9312aStsutsui  /*   9 repressed right  - right pressed after released right */
496e8a9312aStsutsui  [ST_REPRESSED_RIGHT] = {
497e8a9312aStsutsui
498e8a9312aStsutsui    .buttons[EMU_BUTTONS_NONE] = {
499e8a9312aStsutsui      /* nothing (middle release, right release) -> ground */
500e8a9312aStsutsui      .event1 = { ButtonRelease, ButtonMiddle },
501e8a9312aStsutsui      .event2 = { ButtonRelease, ButtonRight  },
502e8a9312aStsutsui      .new_state = ST_GROUND,
503e8a9312aStsutsui    },
504e8a9312aStsutsui
505e8a9312aStsutsui    .buttons[EMU_BUTTONS_LEFT] = {
506e8a9312aStsutsui      /* left (right release) -> released right */
507e8a9312aStsutsui      .event1 = { ButtonRelease, ButtonRight  },
508e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
509e8a9312aStsutsui      .new_state = ST_RELEASED_RIGHT,
510e8a9312aStsutsui    },
511e8a9312aStsutsui
512e8a9312aStsutsui    .buttons[EMU_BUTTONS_RIGHT] = {
513e8a9312aStsutsui      /* right (middle release) -> pressed right */
514e8a9312aStsutsui      .event1 = { ButtonRelease, ButtonMiddle },
515e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
516e8a9312aStsutsui      .new_state = ST_PRESSED_RIGHT,
517e8a9312aStsutsui    },
518e8a9312aStsutsui
519e8a9312aStsutsui    .buttons[EMU_BUTTONS_BOTH] = {
520e8a9312aStsutsui      /* left & right -> repressed right (no change) */
521e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
522e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
523e8a9312aStsutsui      .new_state = ST_REPRESSED_RIGHT,
524e8a9312aStsutsui    },
525e8a9312aStsutsui
526e8a9312aStsutsui    .timeout = {
527e8a9312aStsutsui      /* timeout N/A */
528e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
529e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
530e8a9312aStsutsui      .new_state = ST_INVALID,
531e8a9312aStsutsui    },
532e8a9312aStsutsui  },
533e8a9312aStsutsui
534e8a9312aStsutsui  /*  10 pressed both     - both pressed, not emulating middle */
535e8a9312aStsutsui  [ST_PRESSED_BOTH] = {
536e8a9312aStsutsui
537e8a9312aStsutsui    .buttons[EMU_BUTTONS_NONE] = {
538e8a9312aStsutsui      /* nothing (left release, right release) -> ground */
539e8a9312aStsutsui      .event1 = { ButtonRelease, ButtonLeft   },
540e8a9312aStsutsui      .event2 = { ButtonRelease, ButtonRight  },
541e8a9312aStsutsui      .new_state = ST_GROUND,
542e8a9312aStsutsui    },
543e8a9312aStsutsui
544e8a9312aStsutsui    .buttons[EMU_BUTTONS_LEFT] = {
545e8a9312aStsutsui      /* left (right release) -> pressed left */
546e8a9312aStsutsui      .event1 = { ButtonRelease, ButtonRight  },
547e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
548e8a9312aStsutsui      .new_state = ST_PRESSED_LEFT,
549e8a9312aStsutsui    },
550e8a9312aStsutsui
551e8a9312aStsutsui    .buttons[EMU_BUTTONS_RIGHT] = {
552e8a9312aStsutsui      /* right (left release) -> pressed right */
553e8a9312aStsutsui      .event1 = { ButtonRelease, ButtonLeft   },
554e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
555e8a9312aStsutsui      .new_state = ST_PRESSED_RIGHT,
556e8a9312aStsutsui    },
557e8a9312aStsutsui
558e8a9312aStsutsui    .buttons[EMU_BUTTONS_BOTH] = {
559e8a9312aStsutsui      /* left & right -> pressed both (no change) */
560e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
561e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
562e8a9312aStsutsui      .new_state = ST_PRESSED_BOTH,
563e8a9312aStsutsui    },
564e8a9312aStsutsui
565e8a9312aStsutsui    .timeout = {
566e8a9312aStsutsui      /* timeout N/A */
567e8a9312aStsutsui      .event1 = { ButtonNone,    0            },
568e8a9312aStsutsui      .event2 = { ButtonNone,    0            },
569e8a9312aStsutsui      .new_state = ST_INVALID,
570e8a9312aStsutsui    },
571e8a9312aStsutsui  },
572e8a9312aStsutsui};
573e8a9312aStsutsui
574e8a9312aStsutsuistatic CARD32
575e8a9312aStsutsuibuttonTimer(MouseEmu3btnPtr pEmu3btn)
576e8a9312aStsutsui{
577e8a9312aStsutsui    int type, button, flag;
578e8a9312aStsutsui    ValuatorMask mask;
579e8a9312aStsutsui    const struct button_action *timeout_action;
580e8a9312aStsutsui
5811406604bStsutsui    input_lock();
582e8a9312aStsutsui
583e8a9312aStsutsui    pEmu3btn->emulate3Pending = FALSE;
584e8a9312aStsutsui    timeout_action = &stateTab[pEmu3btn->emulateState].timeout;
585e8a9312aStsutsui    if ((type = timeout_action->event1.type) != ButtonNone) {
586e8a9312aStsutsui        button = timeout_action->event1.button;
587e8a9312aStsutsui        flag = POINTER_RELATIVE;
588e8a9312aStsutsui        valuator_mask_zero(&mask);
589e8a9312aStsutsui        QueuePointerEvents(pEmu3btn->device, type, button, flag, &mask);
590e8a9312aStsutsui        pEmu3btn->emulateState = timeout_action->new_state;
591e8a9312aStsutsui    } else {
592e8a9312aStsutsui        LogMessageVerbSigSafe(X_WARNING, -1,
593e8a9312aStsutsui            "Got unexpected buttonTimer in state %d\n", pEmu3btn->emulateState);
594e8a9312aStsutsui    }
595e8a9312aStsutsui
5961406604bStsutsui    input_unlock();
597e8a9312aStsutsui    return 0;
598e8a9312aStsutsui}
599e8a9312aStsutsui
600e8a9312aStsutsuistatic void
601e8a9312aStsutsuiEmulate3ButtonsSetEnabled(MouseEmu3btnPtr pEmu3btn, Bool enable)
602e8a9312aStsutsui{
603e8a9312aStsutsui
604e8a9312aStsutsui    if (pEmu3btn->emulate3Buttons == enable)
605e8a9312aStsutsui        return;
606e8a9312aStsutsui
607e8a9312aStsutsui    pEmu3btn->emulate3Buttons = enable;
608e8a9312aStsutsui
609e8a9312aStsutsui    if (enable) {
610e8a9312aStsutsui        pEmu3btn->emulateState = ST_GROUND;
611e8a9312aStsutsui        pEmu3btn->emulate3Pending = FALSE;
612e8a9312aStsutsui        pEmu3btn->emulate3ButtonsSoft = FALSE; /* specifically requested now */
613e8a9312aStsutsui
614e8a9312aStsutsui        RegisterBlockAndWakeupHandlers(MouseBlockHandler, MouseWakeupHandler,
615e8a9312aStsutsui                                       (void *)pEmu3btn);
616e8a9312aStsutsui    } else {
617e8a9312aStsutsui        if (pEmu3btn->emulate3Pending)
618e8a9312aStsutsui            buttonTimer(pEmu3btn);
619e8a9312aStsutsui
620e8a9312aStsutsui        RemoveBlockAndWakeupHandlers(MouseBlockHandler, MouseWakeupHandler,
621e8a9312aStsutsui                                     (void *)pEmu3btn);
622e8a9312aStsutsui    }
623e8a9312aStsutsui}
624e8a9312aStsutsui
625e8a9312aStsutsuistatic Bool
626e8a9312aStsutsuiEmulate3ButtonsSoft(MouseEmu3btnPtr pEmu3btn)
627e8a9312aStsutsui{
628e8a9312aStsutsui
629e8a9312aStsutsui    if (!pEmu3btn->emulate3ButtonsSoft)
630e8a9312aStsutsui        return TRUE;
631e8a9312aStsutsui
632e8a9312aStsutsui#if defined(__NetBSD__) && defined(WSCONS_SUPPORT)
633e8a9312aStsutsui    /*
634e8a9312aStsutsui     * On NetBSD a wsmouse is a multiplexed device. Imagine a notebook
635e8a9312aStsutsui     * with two-button mousepad, and an external USB mouse plugged in
636e8a9312aStsutsui     * temporarily. After using button 3 on the external mouse and
637e8a9312aStsutsui     * unplugging it again, the mousepad will still need to emulate
638e8a9312aStsutsui     * 3 buttons.
639e8a9312aStsutsui     */
640e8a9312aStsutsui    return TRUE;
641e8a9312aStsutsui#else
642e8a9312aStsutsui    LogMessageVerbSigSafe(X_INFO, 4,
643e8a9312aStsutsui        "mouse: 3rd Button detected: disabling emulate3Button\n");
644e8a9312aStsutsui
645e8a9312aStsutsui    Emulate3ButtonsSetEnabled(pEmu3btn, FALSE);
646e8a9312aStsutsui
647e8a9312aStsutsui    return FALSE;
648e8a9312aStsutsui#endif
649e8a9312aStsutsui}
650e8a9312aStsutsui
651e8a9312aStsutsuistatic void
652e8a9312aStsutsuiMouseBlockHandler(void *data, void *waitTime)
653e8a9312aStsutsui{
654e8a9312aStsutsui    MouseEmu3btnPtr pEmu3btn = data;
655e8a9312aStsutsui    int ms;
656e8a9312aStsutsui
657e8a9312aStsutsui    if (pEmu3btn->emulate3Pending) {
658e8a9312aStsutsui        ms = pEmu3btn->emulate3Expires - GetTimeInMillis();
659e8a9312aStsutsui        if (ms <= 0)
660e8a9312aStsutsui            ms = 0;
661e8a9312aStsutsui        AdjustWaitForDelay(waitTime, ms);
662e8a9312aStsutsui    }
663e8a9312aStsutsui}
664e8a9312aStsutsui
665e8a9312aStsutsuistatic void
666e8a9312aStsutsuiMouseWakeupHandler(void *data, int i)
667e8a9312aStsutsui{
668e8a9312aStsutsui    MouseEmu3btnPtr pEmu3btn = data;
669e8a9312aStsutsui    int ms;
670e8a9312aStsutsui
671e8a9312aStsutsui    if (pEmu3btn->emulate3Pending) {
672e8a9312aStsutsui        ms = pEmu3btn->emulate3Expires - GetTimeInMillis();
673e8a9312aStsutsui        if (ms <= 0)
674e8a9312aStsutsui            buttonTimer(pEmu3btn);
675e8a9312aStsutsui    }
676e8a9312aStsutsui}
677e8a9312aStsutsui
678e8a9312aStsutsui/*******************************************************************
679e8a9312aStsutsui * function "Emulate3ButtonsEnable"
680e8a9312aStsutsui *
681e8a9312aStsutsui *  purpose:
682e8a9312aStsutsui *   Enable and initialize Emulate3Buttons structures.
683e8a9312aStsutsui *  argument:
684e8a9312aStsutsui *    (MouseEmu3btnPtr)pEmu3btn : Emu3btn private record
685e8a9312aStsutsui *    (DeviceIntPtr)device      : pointer device private record
686e8a9312aStsutsui *    (int)timeout              : timeout to wait another button [ms]
687e8a9312aStsutsui *
688e8a9312aStsutsui *******************************************************************/
689e8a9312aStsutsuivoid
690e8a9312aStsutsuiEmulate3ButtonsEnable(MouseEmu3btnPtr pEmu3btn, DeviceIntPtr device, int timeout)
691e8a9312aStsutsui{
692e8a9312aStsutsui
693e8a9312aStsutsui    BUG_RETURN_MSG(device == NULL, "Invalid DeviceIntPtr.\n");
694e8a9312aStsutsui
695e8a9312aStsutsui    if (timeout <= 0) {
696e8a9312aStsutsui        timeout = EMU3B_DEF_TIMEOUT;
697e8a9312aStsutsui    }
698e8a9312aStsutsui    pEmu3btn->device = device;
699e8a9312aStsutsui    pEmu3btn->emulate3Timeout = timeout;
700e8a9312aStsutsui
701e8a9312aStsutsui    Emulate3ButtonsSetEnabled(pEmu3btn, TRUE);
702e8a9312aStsutsui}
703e8a9312aStsutsui
704e8a9312aStsutsui/*******************************************************************
705e8a9312aStsutsui * function "Emulate3ButtonsQueueEvent"
706e8a9312aStsutsui *
707e8a9312aStsutsui *  purpose:
708e8a9312aStsutsui *   Emulate middle button per left/right button events and post events.
709e8a9312aStsutsui *  argument:
710e8a9312aStsutsui *    (MouseEmu3btnPtr)pEmu3btn : Emu3btn private record
711e8a9312aStsutsui *    (int)type                 : event  (ButtonPress / ButtonRelease)
712e8a9312aStsutsui *    (int)buttons              : button (Button1 / Button2 / Button3)
713e8a9312aStsutsui *    (int)bmask                : buttons being pressed (0x1:left / 0x4:right)
714e8a9312aStsutsui *
715e8a9312aStsutsui *******************************************************************/
716e8a9312aStsutsui
717e8a9312aStsutsuivoid
718e8a9312aStsutsuiEmulate3ButtonsQueueEvent(MouseEmu3btnPtr pEmu3btn, int type, int buttons, int bmask)
719e8a9312aStsutsui{
720e8a9312aStsutsui    DeviceIntPtr device = pEmu3btn->device;
721e8a9312aStsutsui    int emulateButtons;
722e8a9312aStsutsui    int button, flag;
723e8a9312aStsutsui    ValuatorMask mask;
724e8a9312aStsutsui
725e8a9312aStsutsui    BUG_RETURN_MSG(buttons != ButtonLeft && buttons != ButtonRight,
726e8a9312aStsutsui      "not left or right button event\n");
727e8a9312aStsutsui
728e8a9312aStsutsui    if (pEmu3btn->emulate3ButtonsSoft && pEmu3btn->emulate3Pending)
729e8a9312aStsutsui        buttonTimer(pEmu3btn);
730e8a9312aStsutsui
731e8a9312aStsutsui    if (pEmu3btn->emulate3Buttons
732e8a9312aStsutsui        && ((bmask & BMASK_MIDDLE) == 0 || Emulate3ButtonsSoft(pEmu3btn))) {
733e8a9312aStsutsui        const struct button_action *button_action, *timeout_action;
734e8a9312aStsutsui
735e8a9312aStsutsui        /* emulate the third button by the other two */
736e8a9312aStsutsui
737e8a9312aStsutsui        emulateButtons = BMASKTOINDEX(bmask);
738e8a9312aStsutsui        button_action =
739e8a9312aStsutsui          &stateTab[pEmu3btn->emulateState].buttons[emulateButtons];
740e8a9312aStsutsui
741e8a9312aStsutsui        if ((type = button_action->event1.type) != ButtonNone) {
742e8a9312aStsutsui            button = button_action->event1.button;
743e8a9312aStsutsui            flag = POINTER_RELATIVE;
744e8a9312aStsutsui            valuator_mask_zero(&mask);
745e8a9312aStsutsui            QueuePointerEvents(device, type, button, flag, &mask);
746e8a9312aStsutsui        }
747e8a9312aStsutsui        if ((type = button_action->event2.type) != ButtonNone) {
748e8a9312aStsutsui            button = button_action->event2.button;
749e8a9312aStsutsui            flag = POINTER_RELATIVE;
750e8a9312aStsutsui            valuator_mask_zero(&mask);
751e8a9312aStsutsui            QueuePointerEvents(device, type, button, flag, &mask);
752e8a9312aStsutsui        }
753e8a9312aStsutsui
754e8a9312aStsutsui        pEmu3btn->emulateState = button_action->new_state;
755e8a9312aStsutsui
756e8a9312aStsutsui        timeout_action = &stateTab[pEmu3btn->emulateState].timeout;
757e8a9312aStsutsui        if (timeout_action->event1.type != ButtonNone) {
758e8a9312aStsutsui            pEmu3btn->emulate3Expires =
759e8a9312aStsutsui                GetTimeInMillis() + pEmu3btn->emulate3Timeout;
760e8a9312aStsutsui            pEmu3btn->emulate3Pending = TRUE;
761e8a9312aStsutsui        } else {
762e8a9312aStsutsui            pEmu3btn->emulate3Pending = FALSE;
763e8a9312aStsutsui        }
764e8a9312aStsutsui    } else {
765e8a9312aStsutsui        /* no emulation; post left or right button event as is */
766e8a9312aStsutsui        flag = POINTER_RELATIVE;
767e8a9312aStsutsui        valuator_mask_zero(&mask);
768e8a9312aStsutsui        QueuePointerEvents(device, type, buttons, flag, &mask);
769e8a9312aStsutsui    }
770e8a9312aStsutsui}
771