Initialize Tizen 2.3
[adaptation/xorg/driver/xserver-xorg-input-evdev.git] / src / emuMB.c
1 /*
2  * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
3  * Copyright 1993 by David Dawes <dawes@xfree86.org>
4  * Copyright 2002 by SuSE Linux AG, Author: Egbert Eich
5  * Copyright 1994-2002 by The XFree86 Project, Inc.
6  * Copyright 2002 by Paul Elliott
7  * (Ported from xf86-input-mouse, above copyrights taken from there)
8  * Copyright © 2008 University of South Australia
9  *
10  * Permission to use, copy, modify, distribute, and sell this software
11  * and its documentation for any purpose is hereby granted without
12  * fee, provided that the above copyright notice appear in all copies
13  * and that both that copyright notice and this permission notice
14  * appear in supporting documentation, and that the name of the authors
15  * not be used in advertising or publicity pertaining to distribution of the
16  * software without specific, written prior permission.  The authors make no
17  * representations about the suitability of this software for any
18  * purpose.  It is provided "as is" without express or implied
19  * warranty.
20  *
21  * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
22  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
23  * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
24  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
25  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
26  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
27  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28  *
29  */
30
31 /* Middle mouse button emulation code. */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include "evdev.h"
38
39 #include <X11/Xatom.h>
40 #include <xf86.h>
41 #include <xf86Xinput.h>
42 #include <exevents.h>
43
44 #include <evdev-properties.h>
45
46 static Atom prop_mbemu     = 0; /* Middle button emulation on/off property */
47 static Atom prop_mbtimeout = 0; /* Middle button timeout property */
48 /*
49  * Lets create a simple finite-state machine for 3 button emulation:
50  *
51  * We track buttons 1 and 3 (left and right).  There are 11 states:
52  *   0 ground           - initial state
53  *   1 delayed left     - left pressed, waiting for right
54  *   2 delayed right    - right pressed, waiting for left
55  *   3 pressed middle   - right and left pressed, emulated middle sent
56  *   4 pressed left     - left pressed and sent
57  *   5 pressed right    - right pressed and sent
58  *   6 released left    - left released after emulated middle
59  *   7 released right   - right released after emulated middle
60  *   8 repressed left   - left pressed after released left
61  *   9 repressed right  - right pressed after released right
62  *  10 pressed both     - both pressed, not emulating middle
63  *
64  * At each state, we need handlers for the following events
65  *   0: no buttons down
66  *   1: left button down
67  *   2: right button down
68  *   3: both buttons down
69  *   4: emulate3Timeout passed without a button change
70  * Note that button events are not deltas, they are the set of buttons being
71  * pressed now.  It's possible (ie, mouse hardware does it) to go from (eg)
72  * left down to right down without anything in between, so all cases must be
73  * handled.
74  *
75  * a handler consists of three values:
76  *   0: action1
77  *   1: action2
78  *   2: new emulation state
79  *
80  * action > 0: ButtonPress
81  * action = 0: nothing
82  * action < 0: ButtonRelease
83  *
84  * The comment preceeding each section is the current emulation state.
85  * The comments to the right are of the form
86  *      <button state> (<events>) -> <new emulation state>
87  * which should be read as
88  *      If the buttons are in <button state>, generate <events> then go to
89  *      <new emulation state>.
90  */
91 static signed char stateTab[11][5][3] = {
92 /* 0 ground */
93   {
94     {  0,  0,  0 },   /* nothing -> ground (no change) */
95     {  0,  0,  1 },   /* left -> delayed left */
96     {  0,  0,  2 },   /* right -> delayed right */
97     {  2,  0,  3 },   /* left & right (middle press) -> pressed middle */
98     {  0,  0, -1 }    /* timeout N/A */
99   },
100 /* 1 delayed left */
101   {
102     {  1, -1,  0 },   /* nothing (left event) -> ground */
103     {  0,  0,  1 },   /* left -> delayed left (no change) */
104     {  1, -1,  2 },   /* right (left event) -> delayed right */
105     {  2,  0,  3 },   /* left & right (middle press) -> pressed middle */
106     {  1,  0,  4 },   /* timeout (left press) -> pressed left */
107   },
108 /* 2 delayed right */
109   {
110     {  3, -3,  0 },   /* nothing (right event) -> ground */
111     {  3, -3,  1 },   /* left (right event) -> delayed left (no change) */
112     {  0,  0,  2 },   /* right -> delayed right (no change) */
113     {  2,  0,  3 },   /* left & right (middle press) -> pressed middle */
114     {  3,  0,  5 },   /* timeout (right press) -> pressed right */
115   },
116 /* 3 pressed middle */
117   {
118     { -2,  0,  0 },   /* nothing (middle release) -> ground */
119     {  0,  0,  7 },   /* left -> released right */
120     {  0,  0,  6 },   /* right -> released left */
121     {  0,  0,  3 },   /* left & right -> pressed middle (no change) */
122     {  0,  0, -1 },   /* timeout N/A */
123   },
124 /* 4 pressed left */
125   {
126     { -1,  0,  0 },   /* nothing (left release) -> ground */
127     {  0,  0,  4 },   /* left -> pressed left (no change) */
128     { -1,  0,  2 },   /* right (left release) -> delayed right */
129     {  3,  0, 10 },   /* left & right (right press) -> pressed both */
130     {  0,  0, -1 },   /* timeout N/A */
131   },
132 /* 5 pressed right */
133   {
134     { -3,  0,  0 },   /* nothing (right release) -> ground */
135     { -3,  0,  1 },   /* left (right release) -> delayed left */
136     {  0,  0,  5 },   /* right -> pressed right (no change) */
137     {  1,  0, 10 },   /* left & right (left press) -> pressed both */
138     {  0,  0, -1 },   /* timeout N/A */
139   },
140 /* 6 released left */
141   {
142     { -2,  0,  0 },   /* nothing (middle release) -> ground */
143     { -2,  0,  1 },   /* left (middle release) -> delayed left */
144     {  0,  0,  6 },   /* right -> released left (no change) */
145     {  1,  0,  8 },   /* left & right (left press) -> repressed left */
146     {  0,  0, -1 },   /* timeout N/A */
147   },
148 /* 7 released right */
149   {
150     { -2,  0,  0 },   /* nothing (middle release) -> ground */
151     {  0,  0,  7 },   /* left -> released right (no change) */
152     { -2,  0,  2 },   /* right (middle release) -> delayed right */
153     {  3,  0,  9 },   /* left & right (right press) -> repressed right */
154     {  0,  0, -1 },   /* timeout N/A */
155   },
156 /* 8 repressed left */
157   {
158     { -2, -1,  0 },   /* nothing (middle release, left release) -> ground */
159     { -2,  0,  4 },   /* left (middle release) -> pressed left */
160     { -1,  0,  6 },   /* right (left release) -> released left */
161     {  0,  0,  8 },   /* left & right -> repressed left (no change) */
162     {  0,  0, -1 },   /* timeout N/A */
163   },
164 /* 9 repressed right */
165   {
166     { -2, -3,  0 },   /* nothing (middle release, right release) -> ground */
167     { -3,  0,  7 },   /* left (right release) -> released right */
168     { -2,  0,  5 },   /* right (middle release) -> pressed right */
169     {  0,  0,  9 },   /* left & right -> repressed right (no change) */
170     {  0,  0, -1 },   /* timeout N/A */
171   },
172 /* 10 pressed both */
173   {
174     { -1, -3,  0 },   /* nothing (left release, right release) -> ground */
175     { -3,  0,  4 },   /* left (right release) -> pressed left */
176     { -1,  0,  5 },   /* right (left release) -> pressed right */
177     {  0,  0, 10 },   /* left & right -> pressed both (no change) */
178     {  0,  0, -1 },   /* timeout N/A */
179   },
180 };
181
182
183 int
184 EvdevMBEmuTimer(InputInfoPtr pInfo)
185 {
186     EvdevPtr pEvdev = pInfo->private;
187     int sigstate;
188     int id;
189
190     sigstate = xf86BlockSIGIO ();
191
192     pEvdev->emulateMB.pending = FALSE;
193     if ((id = stateTab[pEvdev->emulateMB.state][4][0]) != 0) {
194         EvdevPostButtonEvent(pInfo, abs(id),
195                              (id >= 0) ? BUTTON_PRESS : BUTTON_RELEASE);
196         pEvdev->emulateMB.state =
197             stateTab[pEvdev->emulateMB.state][4][2];
198     } else {
199         ErrorF("Got unexpected buttonTimer in state %d\n",
200                 pEvdev->emulateMB.state);
201     }
202
203     xf86UnblockSIGIO (sigstate);
204     return 0;
205 }
206
207
208 /**
209  * Emulate a middle button on button press.
210  *
211  * @param code button number (1 for left, 3 for right)
212  * @param press TRUE if press, FALSE if release.
213  *
214  * @return TRUE if event was swallowed by middle mouse button emulation, FALSE
215  * otherwise.
216  */
217 BOOL
218 EvdevMBEmuFilterEvent(InputInfoPtr pInfo, int button, BOOL press)
219 {
220     EvdevPtr pEvdev = pInfo->private;
221     int id;
222     int *btstate;
223     int ret = FALSE;
224
225     if (!pEvdev->emulateMB.enabled)
226         return ret;
227
228     /* don't care about other buttons */
229     if (button != 1 && button != 3)
230         return ret;
231
232     btstate = &pEvdev->emulateMB.buttonstate;
233     if (press)
234         *btstate |= (button == 1) ? 0x1 : 0x2;
235     else
236         *btstate &= (button == 1) ? ~0x1 : ~0x2;
237
238     if ((id = stateTab[pEvdev->emulateMB.state][*btstate][0]) != 0)
239     {
240         EvdevQueueButtonEvent(pInfo, abs(id), (id >= 0));
241         ret = TRUE;
242     }
243     if ((id = stateTab[pEvdev->emulateMB.state][*btstate][1]) != 0)
244     {
245         EvdevQueueButtonEvent(pInfo, abs(id), (id >= 0));
246         ret = TRUE;
247     }
248
249     pEvdev->emulateMB.state =
250         stateTab[pEvdev->emulateMB.state][*btstate][2];
251
252     if (stateTab[pEvdev->emulateMB.state][4][0] != 0) {
253         pEvdev->emulateMB.expires = GetTimeInMillis () + pEvdev->emulateMB.timeout;
254         pEvdev->emulateMB.pending = TRUE;
255         ret = TRUE;
256     } else {
257         pEvdev->emulateMB.pending = FALSE;
258     }
259
260     return ret;
261 }
262
263
264 void EvdevMBEmuWakeupHandler(pointer data,
265                              int i,
266                              pointer LastSelectMask)
267 {
268     InputInfoPtr pInfo = (InputInfoPtr)data;
269     EvdevPtr     pEvdev = (EvdevPtr)pInfo->private;
270     int ms;
271
272     if (pEvdev->emulateMB.pending)
273     {
274         ms = pEvdev->emulateMB.expires - GetTimeInMillis();
275         if (ms <= 0)
276             EvdevMBEmuTimer(pInfo);
277     }
278 }
279
280 void EvdevMBEmuBlockHandler(pointer data,
281                             struct timeval **waitTime,
282                             pointer LastSelectMask)
283 {
284     InputInfoPtr    pInfo = (InputInfoPtr) data;
285     EvdevPtr        pEvdev= (EvdevPtr) pInfo->private;
286     int             ms;
287
288     if (pEvdev->emulateMB.pending)
289     {
290         ms = pEvdev->emulateMB.expires - GetTimeInMillis ();
291         if (ms <= 0)
292             ms = 0;
293         AdjustWaitForDelay (waitTime, ms);
294     }
295 }
296
297 void
298 EvdevMBEmuPreInit(InputInfoPtr pInfo)
299 {
300     EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
301
302     pEvdev->emulateMB.enabled = xf86SetBoolOption(pInfo->options,
303                                                   "Emulate3Buttons",
304                                                   FALSE);
305     pEvdev->emulateMB.timeout = xf86SetIntOption(pInfo->options,
306                                                  "Emulate3Timeout", 50);
307 }
308
309 void
310 EvdevMBEmuOn(InputInfoPtr pInfo)
311 {
312     if (!pInfo->dev->button) /* don't init for keyboards */
313         return;
314
315     RegisterBlockAndWakeupHandlers (EvdevMBEmuBlockHandler,
316                                     EvdevMBEmuWakeupHandler,
317                                     (pointer)pInfo);
318 }
319
320 void
321 EvdevMBEmuFinalize(InputInfoPtr pInfo)
322 {
323     if (!pInfo->dev->button) /* don't cleanup for keyboards */
324         return;
325
326     RemoveBlockAndWakeupHandlers (EvdevMBEmuBlockHandler,
327                                   EvdevMBEmuWakeupHandler,
328                                   (pointer)pInfo);
329
330 }
331
332 static int
333 EvdevMBEmuSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
334                       BOOL checkonly)
335 {
336     InputInfoPtr pInfo  = dev->public.devicePrivate;
337     EvdevPtr     pEvdev = pInfo->private;
338
339     if (atom == prop_mbemu)
340     {
341         if (val->format != 8 || val->size != 1 || val->type != XA_INTEGER)
342             return BadMatch;
343
344         if (!checkonly)
345             pEvdev->emulateMB.enabled = *((BOOL*)val->data);
346     } else if (atom == prop_mbtimeout)
347     {
348         if (val->format != 32 || val->size != 1 || val->type != XA_INTEGER)
349             return BadMatch;
350
351         if (!checkonly)
352             pEvdev->emulateMB.timeout = *((CARD32*)val->data);
353     }
354
355     return Success;
356 }
357
358 /**
359  * Initialise property for MB emulation on/off.
360  */
361 void
362 EvdevMBEmuInitProperty(DeviceIntPtr dev)
363 {
364     InputInfoPtr pInfo  = dev->public.devicePrivate;
365     EvdevPtr     pEvdev = pInfo->private;
366     int          rc;
367
368     if (!dev->button) /* don't init prop for keyboards */
369         return;
370
371     prop_mbemu = MakeAtom(EVDEV_PROP_MIDBUTTON, strlen(EVDEV_PROP_MIDBUTTON), TRUE);
372     rc = XIChangeDeviceProperty(dev, prop_mbemu, XA_INTEGER, 8,
373                                 PropModeReplace, 1,
374                                 &pEvdev->emulateMB.enabled,
375                                 FALSE);
376     if (rc != Success)
377         return;
378     XISetDevicePropertyDeletable(dev, prop_mbemu, FALSE);
379
380     prop_mbtimeout = MakeAtom(EVDEV_PROP_MIDBUTTON_TIMEOUT,
381                               strlen(EVDEV_PROP_MIDBUTTON_TIMEOUT),
382                               TRUE);
383     rc = XIChangeDeviceProperty(dev, prop_mbtimeout, XA_INTEGER, 32, PropModeReplace, 1,
384                                 &pEvdev->emulateMB.timeout, FALSE);
385
386     if (rc != Success)
387         return;
388     XISetDevicePropertyDeletable(dev, prop_mbtimeout, FALSE);
389
390     XIRegisterPropertyHandler(dev, EvdevMBEmuSetProperty, NULL, NULL);
391 }