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 * Copyright 2008 by Chris Salch
10 * Copyright 2008 Red Hat, Inc.
12 * Permission to use, copy, modify, distribute, and sell this software
13 * and its documentation for any purpose is hereby granted without
14 * fee, provided that the above copyright notice appear in all copies
15 * and that both that copyright notice and this permission notice
16 * appear in supporting documentation, and that the name of the authors
17 * not be used in advertising or publicity pertaining to distribution of the
18 * software without specific, written prior permission. The authors make no
19 * representations about the suitability of this software for any
20 * purpose. It is provided "as is" without express or implied
23 * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
24 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
25 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
26 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
27 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
28 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
29 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
40 #include <xf86Xinput.h>
41 #include <X11/Xatom.h>
44 #include <evdev-properties.h>
47 #ifdef HAVE_PROPERTIES
48 static Atom prop_dlock = 0; /* Drag lock buttons. */
51 void EvdevDragLockLockButton(InputInfoPtr pInfo, unsigned int button);
54 /* Setup and configuration code */
56 EvdevDragLockPreInit(InputInfoPtr pInfo)
58 EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
59 char *option_string = NULL;
62 char *next_num = NULL;
66 option_string = xf86CheckStrOption(pInfo->options, "DragLockButtons",NULL);
71 next_num = option_string;
73 /* Loop until we hit the end of our option string */
74 while (next_num != NULL) {
76 meta_button = strtol(next_num, &end_str, 10);
78 /* check to see if we found anything */
79 if (next_num != end_str) {
80 /* setup for the next number */
83 /* we have nothing more to parse, drop out of the loop */
87 /* Check for a button to lock if we have a meta button */
88 if (meta_button != 0 && next_num != NULL ) {
89 lock_button = strtol(next_num, &end_str, 10);
91 /* check to see if we found anything */
92 if (next_num != end_str) {
93 /* setup for the next number */
96 /* we have nothing more to parse, drop out of the loop */
101 /* Ok, let the user know what we found on this look */
102 if (meta_button != 0) {
103 if (lock_button == 0) {
105 /* We only have a meta button */
106 pEvdev->dragLock.meta = meta_button;
108 xf86Msg(X_CONFIG, "%s: DragLockButtons : "
110 pInfo->name, meta_button);
112 xf86Msg(X_ERROR, "%s: DragLockButtons : "
113 "Incomplete pair specifying button pairs %s\n",
114 pInfo->name, option_string);
118 /* Do bounds checking to make sure we don't crash */
119 if ((meta_button <= EVDEV_MAXBUTTONS) && (meta_button >= 0 ) &&
120 (lock_button <= EVDEV_MAXBUTTONS) && (lock_button >= 0)) {
122 xf86Msg(X_CONFIG, "%s: DragLockButtons : %i -> %i\n",
123 pInfo->name, meta_button, lock_button);
125 pEvdev->dragLock.lock_pair[meta_button - 1] = lock_button;
128 /* Let the user know something was wrong
129 with this pair of buttons */
130 xf86Msg(X_CONFIG, "%s: DragLockButtons : "
131 "Invalid button pair %i -> %i\n",
132 pInfo->name, meta_button, lock_button);
136 xf86Msg(X_ERROR, "%s: Found DragLockButtons "
137 "with invalid lock button string : '%s'\n",
138 pInfo->name, option_string);
140 /* This should be the case anyhow, just make sure */
144 /* Check for end of string, to avoid annoying error */
145 if (next_num != NULL && *next_num == '\0')
150 /* Updates DragLock button state and fires button event messges */
152 EvdevDragLockLockButton(InputInfoPtr pInfo, unsigned int button)
154 EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
157 /* update button state */
158 state = pEvdev->dragLock.lock_state[button - 1] ? FALSE : TRUE;
159 pEvdev->dragLock.lock_state[button - 1] = state;
161 EvdevQueueButtonEvent(pInfo, button, state);
164 /* Filter button presses looking for either a meta button or the
165 * control of a button pair.
167 * @param button button number (1 for left, 3 for right)
168 * @param value TRUE if button press, FALSE if release
170 * @return TRUE if the event was swallowed here, FALSE otherwise.
173 EvdevDragLockFilterEvent(InputInfoPtr pInfo, unsigned int button, int value)
175 EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
180 /* Do we have a single meta key or
181 several button pairings? */
182 if (pEvdev->dragLock.meta != 0) {
184 if (pEvdev->dragLock.meta == button) {
186 /* setup up for button lock */
188 pEvdev->dragLock.meta_state = TRUE;
191 } else if (pEvdev->dragLock.meta_state) { /* waiting to lock */
193 pEvdev->dragLock.meta_state = FALSE;
195 EvdevDragLockLockButton(pInfo, button);
199 } else if (pEvdev->dragLock.lock_pair[button - 1] && value) {
200 /* A meta button in a meta/lock pair was pressed */
201 EvdevDragLockLockButton(pInfo, pEvdev->dragLock.lock_pair[button - 1]);
205 /* Eat events for buttons that are locked */
206 if (pEvdev->dragLock.lock_state[button - 1])
212 #ifdef HAVE_PROPERTIES
214 * Set the drag lock property.
215 * If only one value is supplied, then this is used as the meta button.
216 * If more than one value is supplied, then each value is the drag lock button
217 * for the pair. 0 disables a pair.
218 * i.e. to set bt 3 to draglock button 1, supply 0,0,1
221 EvdevDragLockSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
224 InputInfoPtr pInfo = dev->public.devicePrivate;
225 EvdevPtr pEvdev = pInfo->private;
227 if (atom == prop_dlock)
231 if (val->format != 8 || val->type != XA_INTEGER)
234 /* Don't allow changes while a lock is active */
235 if (pEvdev->dragLock.meta)
237 if (pEvdev->dragLock.meta_state)
241 for (i = 0; i < EVDEV_MAXBUTTONS; i++)
242 if (pEvdev->dragLock.lock_state[i])
248 else if (val->size == 1)
250 int meta = *((CARD8*)val->data);
251 if (meta > EVDEV_MAXBUTTONS)
256 pEvdev->dragLock.meta = meta;
257 memset(pEvdev->dragLock.lock_pair, 0, sizeof(pEvdev->dragLock.lock_pair));
259 } else if ((val->size % 2) == 0)
261 CARD8* vals = (CARD8*)val->data;
263 for (i = 0; i < val->size && i < EVDEV_MAXBUTTONS; i++)
264 if (vals[i] > EVDEV_MAXBUTTONS)
269 pEvdev->dragLock.meta = 0;
270 memset(pEvdev->dragLock.lock_pair, 0, sizeof(pEvdev->dragLock.lock_pair));
272 for (i = 0; i < val->size && i < EVDEV_MAXBUTTONS; i += 2)
273 pEvdev->dragLock.lock_pair[vals[i] - 1] = vals[i + 1];
283 * Initialise property for drag lock buttons setting.
286 EvdevDragLockInitProperty(DeviceIntPtr dev)
288 InputInfoPtr pInfo = dev->public.devicePrivate;
289 EvdevPtr pEvdev = pInfo->private;
291 if (!dev->button) /* don't init prop for keyboards */
294 prop_dlock = MakeAtom(EVDEV_PROP_DRAGLOCK, strlen(EVDEV_PROP_DRAGLOCK), TRUE);
295 if (pEvdev->dragLock.meta)
297 XIChangeDeviceProperty(dev, prop_dlock, XA_INTEGER, 8,
298 PropModeReplace, 1, &pEvdev->dragLock.meta,
303 CARD8 pair[EVDEV_MAXBUTTONS] = {0};
305 for (i = 0; i < EVDEV_MAXBUTTONS; i++)
307 if (pEvdev->dragLock.lock_pair[i])
309 pair[i] = pEvdev->dragLock.lock_pair[i];
312 XIChangeDeviceProperty(dev, prop_dlock, XA_INTEGER, 8, PropModeReplace,
313 highest + 1, pair, FALSE);
316 XISetDevicePropertyDeletable(dev, prop_dlock, FALSE);
318 XIRegisterPropertyHandler(dev, EvdevDragLockSetProperty, NULL, NULL);