2
* wacomxi.c -- Add X11 extended input handling capability for wacomcpl.
5
* Creation date : 04/05/2003
7
* Based on xi.c 1998-99 Patrick Lecoanet --
9
* This code is free software; you can redistribute it and/or
10
* modify it under the terms of the GNU Library General Public
11
* License as published by the Free Software Foundation; either
12
* version 2 of the License, or (at your option) any later version.
14
* This code is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
* Library General Public License for more details.
19
* You should have received a copy of the GNU Library General Public
20
* License along with this code; if not, write to the Free
21
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29
#include <X11/extensions/XInput.h>
31
* Included to obtain the number of events used by the xinput
34
#include <X11/extensions/XIproto.h>
39
*----------------------------------------------------------------------
41
* This code implements tcl commands that give access
42
* to additional input devices manipulation at the tcl level.
44
* The command 'bindevent' binds tcl scripts to xinput events
45
* occuring in a widget.
47
*----------------------------------------------------------------------
50
#define CORE_KEYBOARD 1
51
#define CORE_POINTER 2
54
* These constants are used to represent fixed
55
* event types. These types are computed by
56
* mapping event types send by each server. The
57
* mapping is done by a table maintained for
61
#define BUTTON_EVENT 2
62
#define MOTION_EVENT 3
64
#define PROXIMITY_EVENT 5
65
#define CHANGE_DEVICE_EVENT 6
66
#define DEVICE_MAPPING_EVENT 7
67
#define DEVICE_STATE_EVENT 8
70
* These constants must be kept in sync with the
71
* xi_event_names array.
75
#define BUTTON_PRESS 2
76
#define BUTTON_PRESS_GRAB 3
77
#define BUTTON_PRESS_OWNER_GRAB 4
78
#define BUTTON_RELEASE 5
81
#define BUTTON_MOTION 8
89
#define PROXIMITY_IN 16
90
#define PROXIMITY_OUT 17
91
#define DEVICE_STATE 18
92
#define DEVICE_MAPPING 19
93
#define CHANGE_DEVICE 20
95
#define NUM_XI_EVENTS 21
96
#define NUM_EVENTS 256 /* Core limit of the protocol */
100
static Tk_Uid xi_event_names[NUM_XI_EVENTS] = {
105
"ButtonPressOwnerGrab",
124
typedef struct _EventHandlerStruct {
126
ClientData client_data;
132
struct _EventHandlerStruct *next;
133
} EventHandlerStruct;
135
typedef struct _EventScriptRecord {
136
struct _DeviceInfoStruct *device;
141
struct _EventScriptRecord *next;
144
typedef struct _AxeInfo {
151
typedef struct _DeviceInfoStruct {
152
struct _DisplayInfoStruct *dpy_info;
156
char core; /* If the device is the core keyboard or pointer */
157
unsigned char x_index; /* index of valuator corresponding to core X */
158
unsigned char y_index; /* index of valuator corresponding to core Y */
162
char focusable; /* True if the device can be explicitly focused */
163
char proximity; /* True if the device can emit proximity events */
164
char feedback; /* True if the device has some feedback control */
165
int mode; /* ABSOLUTE or RELATIVE */
167
Time last_motion_time;
170
int *valuator_cache; /* Used to store valuators if the device reports
171
* more than six axes. The array is allocated
172
* dynamically to match the number of axes. */
173
int event_classes[NUM_XI_EVENTS];
177
typedef struct _DisplayInfoStruct {
178
char has_xdevices; /* Non zero if some devices are available
179
* (other than core devices). */
180
Display *display; /* The display that is described. */
181
DeviceInfoStruct *devices; /* The device list */
183
char event_types[NUM_XI_EVENTS];
184
char event_atypes[NUM_EVENTS]; /* Mapping from server local event types
185
* to absolutes types independant from
187
int event_base; /* The first event type reported by the
188
* xinput extension on this server. */
189
Tcl_HashTable per_wins; /* Records for all handlers per windows on
191
EventHandlerStruct *other_handlers; /* The handlers associated with events not
192
* reported relative to a window. */
193
EventHandlerStruct *frozen_handlers; /* The handlers on hold because theirs
194
* devices are currently core devices. */
195
struct _DisplayInfoStruct *next;
198
typedef struct _WindowInfoStruct {
199
EventHandlerStruct *handlers;
200
EventScriptRecord *scripts;
203
typedef struct _InProgress {
204
ClientData next_handler; /* Next handler in search. */
205
struct _InProgress *next; /* Next higher nested search. */
209
static DisplayInfoStruct *display_infos = NULL;
210
static InProgress *pending_handlers = NULL;
212
static void InvokeEventScript(ClientData client_data, XEvent *e);
213
static WindowInfoStruct *GetWindowInfo(Tk_Window w, int create);
217
*----------------------------------------------------------------------
220
* Return all known information known about the display.
221
* This gets all the needed informations on the available devices
222
* including their name.
223
* This has the side effect (on the first call) of gathering from
224
* the server, all devices that are hooked on the display.
226
*----------------------------------------------------------------------
228
static DisplayInfoStruct *
229
GetDisplayInfo(Display *dpy)
231
XDeviceInfoPtr device_list;
232
DisplayInfoStruct *info;
233
DeviceInfoStruct *device;
234
int i, axe, num_classes;
241
/*printf("Begin of GetDisplayInfo\n");*/
244
* Lookup the display in the already known list.
246
info = display_infos;
249
if (dpy == info->display)
251
/*printf("End of GetDisplayInfo\n");*/
260
* Nothing found, make a new entry and fill it with all the available info.
263
* First ask if the server has made the xinput extension available.
265
info = (DisplayInfoStruct *) ckalloc(sizeof(DisplayInfoStruct));
266
info->next = display_infos;
267
display_infos = info;
268
info->has_xdevices = XQueryExtension(dpy, INAME, &dummy,
269
&info->event_base, &dummy);
271
Tcl_InitHashTable(&info->per_wins, TCL_ONE_WORD_KEYS);
272
info->other_handlers = NULL;
273
info->frozen_handlers = NULL;
275
* Then ask the device list.
277
if (info->has_xdevices)
279
device_list = (XDeviceInfoPtr) XListInputDevices(dpy, &info->num_dev);
283
info->devices = (DeviceInfoStruct *)
284
ckalloc(info->num_dev * sizeof(DeviceInfoStruct));
287
for (device = info->devices, i = 0; i < info->num_dev; i++, device++)
289
device->dpy_info = info;
291
device->id = device_list[i].id;
292
device->name = Tk_GetUid(device_list[i].name);
293
device->core = ((device_list[i].use == IsXExtensionDevice) ? 0 :
294
((device_list[i].use == IsXPointer) ? CORE_POINTER : CORE_KEYBOARD));
297
device->num_axes = 0;
298
device->num_keys = 0;
299
device->num_buttons = 0;
300
device->focusable = 0;
301
device->proximity = 0;
302
device->feedback = 0;
304
* Setup each input class declared by the device.
306
if (device_list[i].num_classes > 0)
308
num_classes = device_list[i].num_classes;
309
any = (XAnyClassPtr) device_list[i].inputclassinfo;
310
while (num_classes--)
315
k = (XKeyInfoPtr) any;
316
device->num_keys = k->num_keys;
319
b = (XButtonInfoPtr) any;
320
device->num_buttons = b->num_buttons;
323
v = (XValuatorInfoPtr) any;
324
device->num_axes = v->num_axes;
325
device->axe_info = (AxeInfo*)
326
ckalloc(sizeof(AxeInfo)*v->num_axes);
327
device->history_size = v->motion_buffer;
328
for (axe = 0; axe < v->num_axes; axe++)
330
device->axe_info[axe].min_value =
331
v->axes[axe].min_value;
332
device->axe_info[axe].max_value =
333
v->axes[axe].max_value;
334
device->axe_info[axe].resolution =
335
v->axes[axe].resolution;
336
device->axe_info[axe].value = 0;
342
any = (XAnyClassPtr) ((char *) any + any->length);
346
XFreeDeviceList(device_list);
350
info->has_xdevices = 0;
357
*----------------------------------------------------------------------
359
* LookupDeviceById --
360
* Return a device record from the display and the id of
361
* the device on the display. This is typically used to
362
* retrieve a device record from an event.
364
*----------------------------------------------------------------------
366
static DeviceInfoStruct *
367
LookupDeviceById(Display *dpy,
370
DisplayInfoStruct *info;
373
info = GetDisplayInfo(dpy);
374
for (i = 0; i < info->num_dev; i++)
376
if (info->devices[i].id == device_id)
378
return &info->devices[i];
385
*----------------------------------------------------------------------
388
* Extended event handler bound to ChangeDevice events.
390
* It's purpose is to maintain the core bits (CORE_POINTER,
391
* CORE_KEYBOARD) in the device structs when the core devices
393
* This also implies that all handlers registered for the new
394
* core device are put on hold and all handlers put on hold for
395
* the previous core device are revived.
397
*----------------------------------------------------------------------
400
UpdateCoreMark(ClientData client_data,
403
XChangeDeviceNotifyEvent *cdne = (XChangeDeviceNotifyEvent *) e;
404
DeviceInfoStruct *device, *old_device = NULL;
405
DisplayInfoStruct *info;
407
EventHandlerStruct *handlers, *h_prev, *h_next;
408
Tcl_HashEntry *entry;
409
Tcl_HashSearch search;
410
WindowInfoStruct *pw;
412
/*printf("UpdateCoreMark: type=%d, win=0x%X\n", e->type, (int)e->xany.window);*/
414
device = LookupDeviceById(cdne->display, cdne->deviceid);
415
info = device->dpy_info;
416
for (i = 0; i < info->num_dev; i++)
418
if ((info->devices[i].core == CORE_POINTER) &&
419
(cdne->request == NewPointer))
421
old_device = &info->devices[i];
422
old_device->core = 0;
423
/*printf("old pointer is %s\n", old_device->name);*/
426
else if ((info->devices[i].core == CORE_KEYBOARD) &&
427
(cdne->request == NewKeyboard))
429
old_device = &info->devices[i];
430
old_device->core = 0;
434
if (cdne->request == NewKeyboard)
436
device->core = CORE_KEYBOARD;
438
else if (cdne->request == NewPointer)
440
device->core = CORE_POINTER;
441
/*printf("new pointer is %s\n", device->name);*/
445
* Try to unfreeze all handlers associated with the previous
448
for (handlers = info->frozen_handlers, h_prev = NULL; handlers != NULL;
451
h_next = handlers->next;
452
if (handlers->device_id == old_device->id)
454
if (handlers == info->frozen_handlers)
456
info->frozen_handlers = handlers->next;
460
h_prev->next = handlers->next;
462
event_atype = info->event_atypes[handlers->type];
463
if ((event_atype == CHANGE_DEVICE_EVENT) ||
464
(event_atype == DEVICE_MAPPING_EVENT) ||
465
(event_atype == DEVICE_STATE_EVENT))
467
handlers->next = info->other_handlers;
468
info->other_handlers = handlers;
472
WindowInfoStruct *pw = GetWindowInfo(handlers->tkwin, 0);
473
handlers->next = pw->handlers;
474
pw->handlers = handlers;
483
* Then try to freeze all handlers associated with the new
484
* core device. First traverse the other_handlers list and
485
* then all the per window handlers.
487
for (handlers = info->other_handlers, h_prev = NULL;
488
handlers != NULL; handlers = h_next)
490
h_next = handlers->next;
491
if (handlers->device_id == device->id)
493
if (handlers == info->other_handlers)
495
info->other_handlers = handlers->next;
499
h_prev->next = handlers->next;
501
handlers->next = info->frozen_handlers;
502
info->frozen_handlers = handlers;
509
entry = Tcl_FirstHashEntry(&info->per_wins, &search);
512
pw = (WindowInfoStruct *) Tcl_GetHashValue(entry);
513
for (handlers = pw->handlers, h_prev = NULL;
514
handlers != NULL; handlers = h_next)
516
h_next = handlers->next;
517
if (handlers->device_id == device->id)
519
if (handlers == pw->handlers)
521
pw->handlers = handlers->next;
525
h_prev->next = handlers->next;
527
handlers->next = info->frozen_handlers;
528
info->frozen_handlers = handlers;
535
entry = Tcl_NextHashEntry(&search);
540
*----------------------------------------------------------------------
543
* Get the device descriptor for the device named 'name' on
544
* the given window's display. The device is opened as needed.
545
* If no such device exists on the display the function returns
548
*----------------------------------------------------------------------
550
static DeviceInfoStruct *
551
GetDeviceInfo(Tk_Window tkwin, /* Used to get the display */
554
Display *dpy = Tk_Display(tkwin);
555
DisplayInfoStruct *info;
556
DeviceInfoStruct *device = NULL;
557
XInputClassInfo *classes;
560
info = GetDisplayInfo(dpy);
561
/*printf("display_info=0x%X, display=0x%X\n", info, dpy);*/
562
for (i = 0; i < info->num_dev; i++)
564
if (info->devices[i].name == name)
566
device = &info->devices[i];
572
* Open the xdevice if not already done and not currently
575
/*printf("device=%s(0x%X), id=%d\n", device->name, device, (int)device->id);*/
576
if (!device->xdev && !device->core)
579
device->xdev = XOpenDevice(dpy, device->id);
583
* Process all declared input classes. This code finalizes
584
* the work done when getting the device list for the display.
585
* Some input classes are not reported until the device is open.
587
for (i = 0, classes = device->xdev->classes;
588
i < device->xdev->num_classes; i++, classes++)
590
switch (classes->input_class)
593
DeviceButtonRelease(device->xdev,
594
info->event_types[BUTTON_RELEASE],
595
device->event_classes[BUTTON_RELEASE]);
596
DeviceButtonPress(device->xdev,
597
info->event_types[BUTTON_PRESS],
598
device->event_classes[BUTTON_PRESS]);
599
info->event_atypes[(int)info->
600
event_types[BUTTON_RELEASE]] = BUTTON_EVENT;
601
info->event_atypes[(int)info->
602
event_types[BUTTON_PRESS]] = BUTTON_EVENT;
605
DeviceKeyRelease(device->xdev,
606
info->event_types[KEY_RELEASE],
607
device->event_classes[KEY_RELEASE]);
608
DeviceKeyPress(device->xdev,
609
info->event_types[KEY_PRESS],
610
device->event_classes[KEY_PRESS]);
611
info->event_atypes[(int)info->
612
event_types[KEY_RELEASE]] = KEY_EVENT;
613
info->event_atypes[(int)info->
614
event_types[KEY_PRESS]] = KEY_EVENT;
617
DeviceMotionNotify(device->xdev,
618
info->event_types[MOTION],
619
device->event_classes[MOTION]);
620
DevicePointerMotionHint(device->xdev, dummy,
621
device->event_classes[MOTION_HINT]);
622
info->event_types[MOTION_HINT] =
623
info->event_types[MOTION];
624
info->event_atypes[(int)info->
625
event_types[MOTION]] = MOTION_EVENT;
628
device->focusable = 1;
629
DeviceFocusIn(device->xdev,
630
info->event_types[FOCUS_IN],
631
device->event_classes[FOCUS_IN]);
632
DeviceFocusOut(device->xdev,
633
info->event_types[FOCUS_OUT],
634
device->event_classes[FOCUS_OUT]);
635
info->event_atypes[(int)info->
636
event_types[FOCUS_IN]] = FOCUS_EVENT;
637
info->event_atypes[(int)info->
638
event_types[FOCUS_OUT]] = FOCUS_EVENT;
641
device->proximity = 1;
642
ProximityIn(device->xdev,
643
info->event_types[PROXIMITY_IN],
644
device->event_classes[PROXIMITY_IN]);
645
ProximityOut(device->xdev,
646
info->event_types[PROXIMITY_OUT],
647
device->event_classes[PROXIMITY_OUT]);
648
info->event_atypes[(int)info->
649
event_types[PROXIMITY_OUT]] = PROXIMITY_EVENT;
650
info->event_atypes[(int)info->
651
event_types[PROXIMITY_IN]] = PROXIMITY_EVENT;
654
device->feedback = 1;
659
* If the device can report both valuators and buttons, it is
660
* possible to ask for these events. The event type is Motion.
662
if (device->num_buttons && device->num_axes)
664
DeviceButtonMotion(device->xdev, dummy,
665
device->event_classes[BUTTON_MOTION]);
666
info->event_types[BUTTON_MOTION] =
667
info->event_types[MOTION];
668
DeviceButton1Motion(device->xdev, dummy,
669
device->event_classes[B1_MOTION]);
670
info->event_types[B1_MOTION] =
671
info->event_types[MOTION];
672
DeviceButton2Motion(device->xdev, dummy,
673
device->event_classes[B2_MOTION]);
674
info->event_types[B2_MOTION] =
675
info->event_types[MOTION];
676
DeviceButton3Motion(device->xdev, dummy,
677
device->event_classes[B3_MOTION]);
678
info->event_types[B3_MOTION] =
679
info->event_types[MOTION];
680
DeviceButton4Motion(device->xdev, dummy,
681
device->event_classes[B4_MOTION]);
682
info->event_types[B4_MOTION] =
683
info->event_types[MOTION];
684
DeviceButton5Motion(device->xdev, dummy,
685
device->event_classes[B5_MOTION]);
686
info->event_types[B5_MOTION] =
687
info->event_types[MOTION];
690
* Setup the no-event class for this device.
692
NoExtensionEvent(device->xdev, dummy, device->no_event_class);
694
* Setup the ChangeDevice, DeviceMapping and DeviceState
697
ChangeDeviceNotify(device->xdev,
698
info->event_types[CHANGE_DEVICE],
699
device->event_classes[CHANGE_DEVICE]);
700
info->event_atypes[(int)info->
701
event_types[CHANGE_DEVICE]] = CHANGE_DEVICE_EVENT;
702
DeviceMappingNotify(device->xdev,
703
info->event_types[DEVICE_MAPPING],
704
device->event_classes[DEVICE_MAPPING]);
705
info->event_atypes[(int)info->
706
event_types[DEVICE_MAPPING]] = DEVICE_MAPPING_EVENT;
707
DeviceStateNotify(device->xdev,
708
info->event_types[DEVICE_STATE],
709
device->event_classes[DEVICE_STATE]);
710
info->event_atypes[(int)info->
711
event_types[DEVICE_STATE]] = DEVICE_STATE_EVENT;
713
* If the device has more than six valuators, allocate an
714
* array big enough to hold all the valuators of the device.
716
if (device->num_axes)
718
device->valuator_cache = (int *)
719
ckalloc(device->num_axes*sizeof(int));
723
device->valuator_cache = NULL;
726
* Create an event handler on ChangeDevice
727
* to update the core field.
729
Tk_CreateXiEventHandler(tkwin,
730
xi_event_names[CHANGE_DEVICE],
732
UpdateCoreMark, NULL);
735
if (!device->xdev || device->core)
738
* Open failed or access denied, return NULL to inform the caller.
743
/*printf("End of GetDeviceInfo\n");*/
749
*----------------------------------------------------------------------
752
* Given an event spec uid, the function return the corresponding
753
* event index, needed to retrieve the type and class values.
754
* If the string does not describe a valid event, the function
757
*----------------------------------------------------------------------
760
GetEventIndex(Tk_Uid event_spec)
764
for (i = 0; i < NUM_XI_EVENTS; i++)
766
if (xi_event_names[i] == event_spec)
775
*----------------------------------------------------------------------
777
* DestroyPerWindow --
778
* Called when a window is destroyed to cleanup the event handlers
779
* that remain registered.
780
* No care is taken to prevent a race with Tk_DispatchXiEvent
781
* since DestroyPerWindow is also triggered as an event handler
782
* and thus should not be active at the same time. This is unfor-
783
* tunately a _FALSE_ guess, DestroyNotify is generated internally
784
* and processed as soon as the destroy command is emitted.
786
*----------------------------------------------------------------------
789
DestroyPerWindow(ClientData client_data,
792
Tk_Window w = (Tk_Window) client_data;
793
DisplayInfoStruct *info;
794
EventScriptRecord *escripts, *es_next;
795
EventHandlerStruct *handlers, *h_next, *h_prev;
796
WindowInfoStruct *pw;
800
if (e->type == DestroyNotify)
802
/*printf("Begin of DestroyPerWindow\n");*/
803
info = GetDisplayInfo(e->xany.display);
804
he = Tcl_FindHashEntry(&info->per_wins, (char *) w);
807
pw = (WindowInfoStruct *) Tcl_GetHashValue(he);
808
for (handlers = pw->handlers; handlers != NULL; handlers = h_next)
810
h_next = handlers->next;
812
* Need to see if Tk_DispatchXiEvent is not about to
813
* fire this handler. If it is, just abort the whole
814
* dispatch thread, the window is gone.
816
for (ip = pending_handlers; ip != NULL; ip = ip->next)
818
if (ip->next_handler == (ClientData) handlers)
820
ip->next_handler = NULL;
823
ckfree((char *) handlers);
825
for (escripts = pw->scripts; escripts != NULL; escripts = es_next)
827
es_next = escripts->next;
828
ckfree(escripts->script);
829
ckfree((char *) escripts);
832
Tcl_DeleteHashEntry(he);
835
* Scan through the 'special events' handlers.
837
for (handlers = info->other_handlers, h_prev = NULL;
838
handlers != NULL; handlers = h_next)
840
h_next = handlers->next;
841
if (handlers->tkwin == w)
843
if (handlers == info->other_handlers)
845
info->other_handlers = h_next;
849
h_prev->next = h_next;
852
* Need to see if Tk_DispatchXiEvent is not about to
853
* fire this handler. If it is, point it to the next.
855
for (ip = pending_handlers; ip != NULL; ip = ip->next)
857
if (ip->next_handler == (ClientData) handlers)
859
ip->next_handler = h_next;
862
ckfree((char *) handlers);
870
* Scan through the frozen handlers.
872
for (handlers = info->frozen_handlers, h_prev = NULL;
873
handlers != NULL; handlers = h_next)
875
h_next = handlers->next;
876
if (handlers->tkwin == w)
878
if (handlers == info->frozen_handlers)
880
info->frozen_handlers = handlers->next;
884
h_prev->next = handlers->next;
886
ckfree((char *) handlers);
893
/*printf("End of DestroyPerWindow\n");*/
898
*----------------------------------------------------------------------
901
* Return the handlers registered for the window.
903
*----------------------------------------------------------------------
905
static WindowInfoStruct *
906
GetWindowInfo(Tk_Window w,
909
DisplayInfoStruct *info = GetDisplayInfo(Tk_Display(w));
911
WindowInfoStruct *pw;
914
/*printf("Begin of GetWindowInfo\n");*/
916
he = Tcl_FindHashEntry(&info->per_wins, (char *) w);
921
pw = (WindowInfoStruct *) ckalloc(sizeof(WindowInfoStruct));
924
he = Tcl_CreateHashEntry(&info->per_wins, (char *) w, &new);
925
Tcl_SetHashValue(he, pw);
926
Tk_CreateEventHandler(w, StructureNotifyMask, DestroyPerWindow, w);
932
/*printf("End of GetWindowInfo\n");*/
936
/*printf("End of GetWindowInfo\n");*/
937
return (WindowInfoStruct *) Tcl_GetHashValue(he);
941
*----------------------------------------------------------------------
944
* Traverse all event handlers for a given window and collect
945
* all classes needed for correct event selection. With this,
946
* select the requested events on the window. This may also
947
* unselect as needed all events from a device.
949
*----------------------------------------------------------------------
952
SelectEvents(Tk_Window w,
955
DisplayInfoStruct *info = GetDisplayInfo(Tk_Display(w));
956
WindowInfoStruct *pw = GetWindowInfo(w, 0);
957
EventHandlerStruct *handlers;
961
/*printf("Begin SelectEvents\n");*/
962
if (no_event_class >= 0)
968
for (handlers = pw->handlers; handlers; handlers = handlers->next)
970
count += handlers->num_classes;
973
for (handlers = info->other_handlers; handlers; handlers = handlers->next)
975
if (handlers->tkwin == w)
977
count += handlers->num_classes;
981
if (count == 0) return;
983
classes = (int *) alloca(count * sizeof(int));
985
if (no_event_class >= 0)
987
classes[count] = no_event_class;
992
for (handlers = pw->handlers; handlers; handlers = handlers->next)
994
for (i = 0; i < handlers->num_classes; i++, count++)
996
classes[count] = handlers->classes[i];
1000
for (handlers = info->other_handlers; handlers; handlers = handlers->next)
1002
if (handlers->tkwin == w)
1004
for (i = 0; i < handlers->num_classes; i++, count++)
1006
classes[count] = handlers->classes[i];
1011
XSelectExtensionEvent(Tk_Display(w), Tk_WindowId(w),
1012
(XEventClass *) classes, count);
1016
*----------------------------------------------------------------------
1018
* Tk_CreateXiEventHandler --
1019
* Public function provided to declare an event handler for
1020
* an event from a device on a window. The client can pass a
1021
* procedure to be called and a data pointer that will be passed
1022
* back to the procedure.
1024
* If it is not possible to bind the event the function return
1025
* 0 else it returns 1.
1027
*----------------------------------------------------------------------
1030
Tk_CreateXiEventHandler(Tk_Window w,
1034
ClientData client_data)
1036
int found, no_window;
1037
int event_index, event_type, event_atype;
1038
WindowInfoStruct *pw;
1039
EventHandlerStruct *handlers, **handlers_head;
1040
DeviceInfoStruct *device;
1041
DisplayInfoStruct *info;
1043
/*printf("Begin Tk_CreateXiEventHandler\n");*/
1045
device = GetDeviceInfo(w, device_spec);
1046
info = device->dpy_info;
1047
event_index = GetEventIndex(event_spec);
1049
if (event_index < 0) return 0;
1051
event_type = info->event_types[event_index];
1052
event_atype = info->event_atypes[event_type];
1053
if (((event_atype == KEY_EVENT) && !device->num_keys) ||
1054
((event_atype == BUTTON_EVENT) && !device->num_buttons) ||
1055
((event_atype == MOTION_EVENT) && !device->num_axes) ||
1056
((event_atype == FOCUS_EVENT) && !device->focusable) ||
1057
((event_atype == PROXIMITY_EVENT) && !device->proximity))
1063
* Special case for events that do not report a window.
1065
no_window = ((event_atype == CHANGE_DEVICE_EVENT) ||
1066
(event_atype == DEVICE_MAPPING_EVENT) ||
1067
(event_atype == DEVICE_STATE_EVENT));
1071
handlers_head = &info->other_handlers;
1075
pw = GetWindowInfo(w, 1);
1076
handlers_head = &pw->handlers;
1080
* Lookup if the proc is already installed with the same
1081
* client_data for the same event and device.
1084
for (handlers = *handlers_head ; handlers; handlers = handlers->next)
1086
if ((handlers->proc == proc) &&
1087
(handlers->client_data == client_data) &&
1088
(handlers->type == event_type) &&
1089
(handlers->device_id == device->id))
1098
handlers = (EventHandlerStruct *) ckalloc(sizeof(EventHandlerStruct));
1099
handlers->next = *handlers_head;
1100
*handlers_head = handlers;
1101
handlers->proc = proc;
1102
handlers->client_data = client_data;
1103
handlers->type = event_type;
1104
handlers->device_id = device->id;
1105
handlers->tkwin = w;
1107
if ((event_index == BUTTON_PRESS_GRAB) ||
1108
(event_index == BUTTON_PRESS_OWNER_GRAB))
1110
handlers->num_classes = 2;
1111
handlers->classes[0] = device->event_classes[BUTTON_PRESS];
1112
handlers->classes[1] = device->event_classes[BUTTON_PRESS_GRAB];
1113
if (event_index == BUTTON_PRESS_OWNER_GRAB)
1115
handlers->num_classes++;
1116
handlers->classes[2] =
1117
device->event_classes[BUTTON_PRESS_OWNER_GRAB];
1120
else if (event_index == MOTION_HINT)
1122
handlers->num_classes = 2;
1123
handlers->classes[0] = device->event_classes[MOTION];
1124
handlers->classes[1] = device->event_classes[MOTION_HINT];
1128
handlers->num_classes = 1;
1129
handlers->classes[0] = device->event_classes[event_index];
1134
* Now we need to check if the widget window is created and
1135
* if it is, select the right events.
1139
SelectEvents(w, -1);
1142
/*printf("End Tk_CreateXiEventHandler\n");*/
1147
*----------------------------------------------------------------------
1149
* Tk_DeleteXiEventHandler --
1150
* Public function provided to suppress an event handler for
1151
* an event from a device on a window. The client pass a
1152
* procedure and a data pointer to be matched. Only the handler
1153
* matching all criteria will be removed.
1155
*----------------------------------------------------------------------
1158
Tk_DeleteXiEventHandler(Tk_Window w,
1162
ClientData client_data)
1164
WindowInfoStruct *pw;
1165
int event_index, event_type, event_atype;
1166
DeviceInfoStruct *device;
1167
EventHandlerStruct *handlers, *prev, *next;
1168
EventHandlerStruct **handlers_head;
1171
int device_in_use = 0;
1173
/*printf("Begin Tk_DeleteXiEventHandler\n");*/
1174
device = GetDeviceInfo(w, device_spec);
1175
event_index = GetEventIndex(event_spec);
1176
event_type = device->dpy_info->event_types[event_index];
1177
event_atype = device->dpy_info->event_atypes[event_type];
1180
* Special case for events that do not report a window.
1182
no_window = ((event_atype == CHANGE_DEVICE_EVENT) ||
1183
(event_atype == DEVICE_MAPPING_EVENT) ||
1184
(event_atype == DEVICE_STATE_EVENT));
1188
handlers_head = &device->dpy_info->other_handlers;
1192
pw = GetWindowInfo(w, 0);
1196
handlers_head = &pw->handlers;
1199
for (handlers = *handlers_head, prev = NULL;
1200
handlers != NULL; handlers = next)
1202
if ((handlers->proc == proc) &&
1203
(handlers->client_data == client_data) &&
1204
(handlers->type == event_type) &&
1205
(handlers->device_id == device->id))
1207
/* Ok, found the handler we are looking for, but we need
1208
* to check if Tk_DispatchXiEvent is not about to
1209
* process the handler. If it is, skip to the next.
1211
next = handlers->next;
1213
for (ip = pending_handlers; ip != NULL; ip = ip->next)
1215
if (ip->next_handler == (ClientData) handlers)
1217
ip->next_handler = (ClientData) next;
1221
* Unlink and free the handler.
1223
if (handlers == *handlers_head)
1225
*handlers_head = next;
1231
ckfree((char *) handlers);
1237
* Record if the device will be still in use after the
1238
* removal of this handler.
1240
next = handlers->next;
1241
device_in_use = device_in_use || (handlers->device_id == device->id);
1245
* Now we need to check if the widget window is created and
1246
* if it is, select the right events.
1248
/*printf("device in use %s, %d, no_event=%d\n", device->name, device_in_use,
1249
device->no_event_class);*/
1252
SelectEvents(w, device_in_use ? -1 : device->no_event_class);
1254
/*printf("End Tk_DeleteXiEventHandler\n");*/
1258
*----------------------------------------------------------------------
1260
* WacomxiGenericEventHandler --
1261
* The generic event handler that is used to hook this extension
1262
* in Tk event machinery.
1263
* If checks if the event is from the xinput extension and
1264
* dispatchs it using Tk_DispatchXiEvent on the appropriate
1267
*----------------------------------------------------------------------
1270
WacomxiGenericEventHandler(ClientData client_data,
1273
DisplayInfoStruct *info;
1275
info = GetDisplayInfo(event->xany.display);
1276
if ((event->type >= info->event_base) &&
1277
(event->type < (info->event_base+IEVENTS)))
1279
return Tk_DispatchXiEvent(event);
1282
/* Not able to dispatch return and let the standard system have a try.
1288
*----------------------------------------------------------------------
1290
* Tk_DispatchXiEvent --
1291
* Public function provided to dispatch an xinput event to a
1292
* window. The event must be an xinput event.
1294
*----------------------------------------------------------------------
1297
Tk_DispatchXiEvent(XEvent *e)
1299
WindowInfoStruct *pw;
1302
EventHandlerStruct *handlers;
1303
DisplayInfoStruct *info;
1306
/*printf("Begin Tk_DispatchXiEvent : %d\n", e->type);*/
1309
* Special case needed for ChangeDeviceEvent, DeviceMappingEvent
1310
* and DeviceStateEvent because the window is not reported.
1314
tkwin = Tk_IdToWindow(e->xany.display, e->xany.window);
1316
if ( !tkwin ) return hit;
1318
pw = GetWindowInfo(tkwin, 0);
1320
if ( !pw ) return hit;
1322
handlers = pw->handlers;
1326
info = GetDisplayInfo(e->xany.display);
1327
handlers = info->other_handlers;
1330
ip.next_handler = NULL;
1331
ip.next = pending_handlers;
1332
pending_handlers = &ip;
1333
for ( ; handlers != NULL; )
1335
if ((handlers->type == e->type) &&
1336
(handlers->device_id == ((XDeviceKeyEvent *) e)->deviceid))
1339
ip.next_handler = (ClientData) handlers->next;
1340
(*(handlers->proc))(handlers->client_data, e);
1341
handlers = (EventHandlerStruct *) ip.next_handler;
1345
handlers = handlers->next;
1348
pending_handlers = pending_handlers->next;
1350
/*printf("End Tk_DispatchXiEvent\n");*/
1356
*----------------------------------------------------------------------
1358
* RemoveEventScript --
1359
* Delete a script associated with and event from a device. The
1360
* server is asked to stop reporting this event in the window.
1362
*----------------------------------------------------------------------
1365
RemoveEventScript(Tcl_Interp *interp,
1367
DeviceInfoStruct *device,
1370
WindowInfoStruct *pw = GetWindowInfo(tkwin, 0);
1371
EventScriptRecord *escripts, *prev_escript;
1373
/*printf("Begin RemoveEventScript\n");
1374
printf("for %s\n", event_spec);*/
1376
* No window info. The window has probably been destroyed.
1380
for (escripts = pw->scripts, prev_escript = NULL;
1382
prev_escript = escripts, escripts = escripts->next)
1384
if ((escripts->device == device) &&
1385
(escripts->event_spec == event_spec) &&
1386
(escripts->interp == interp))
1389
* Ok, found the script we are looking for.
1390
* Unlink the script from the list.
1392
if (escripts == pw->scripts)
1394
pw->scripts = escripts->next;
1398
prev_escript->next = escripts->next;
1400
Tk_DeleteXiEventHandler(tkwin, event_spec, device->name,
1401
InvokeEventScript, (ClientData) escripts);
1402
ckfree(escripts->script);
1403
ckfree((char *) escripts);
1407
/*printf("End RemoveEventScript\n");*/
1411
*----------------------------------------------------------------------
1414
* Do the actual work of expanding the percents in a script. The
1415
* code is an adaptation of the function of the same name in
1416
* tkBind.c To be completed
1418
*----------------------------------------------------------------------
1422
ExpandPercents(Tk_Window tkwin,
1423
DeviceInfoStruct *device,
1427
Tcl_DString *exp_script)
1430
char num_buffer[NUM_SIZE];
1431
int space_needed, cvt_flags;
1432
unsigned long number;
1433
int length, i, x, y, width, height;
1434
int k_b_v_p_flag = 0, k_b_flag = 0;
1435
unsigned int device_state = 0;
1436
int axes_count = 0, *axis_data = NULL;
1438
/*printf("Begin ExpandPercents\n");*/
1439
if ((event_atype == KEY_EVENT) || (event_atype == BUTTON_EVENT))
1441
k_b_flag = k_b_v_p_flag = 1;
1442
device_state = ((XDeviceKeyEvent *) e)->device_state;
1443
axes_count = ((XDeviceKeyEvent *) e)->axes_count;
1444
axis_data = ((XDeviceKeyEvent *) e)->axis_data;
1446
else if (event_atype == MOTION_EVENT)
1449
device_state = ((XDeviceMotionEvent *) e)->device_state;
1450
axes_count = ((XDeviceMotionEvent *) e)->axes_count;
1451
axis_data = ((XDeviceMotionEvent *) e)->axis_data;
1453
else if (event_atype == PROXIMITY_EVENT)
1456
device_state = ((XProximityNotifyEvent *) e)->device_state;
1457
axes_count = ((XProximityNotifyEvent *) e)->axes_count;
1458
axis_data = ((XProximityNotifyEvent *) e)->axis_data;
1464
* Find everything up to the next % character and append it
1465
* to the result string.
1467
for (scan = script; (*scan != 0) && (*scan != '%'); scan++)
1469
/* Empty loop body. */
1473
Tcl_DStringAppend(exp_script, script, scan-script);
1481
* Script is on a percent sequence. Process it.
1488
number = e->xany.serial;
1489
goto do_unsigned_number;
1502
int index = script[1]-'0';
1504
if (index < axes_count)
1508
number = device->valuator_cache[index];
1512
number = axis_data[index];
1518
if (event_atype == MOTION_EVENT)
1520
DeviceInfoStruct *devices = device->dpy_info->devices;
1521
int num_devices = device->dpy_info->num_dev;
1524
* Go through all known devices and look for a device
1525
* id equal to the valuator value. If not found return
1526
* the valuator value as an integer.
1528
for (i = 0; i < num_devices; i++)
1530
if (devices[i].id == axis_data[0])
1532
scan = (char *)devices[i].name;
1536
number = axis_data[0];
1540
if (event_atype == BUTTON_EVENT)
1542
number = ((XDeviceButtonEvent *) e)->button;
1544
goto do_unsigned_number;
1546
if (event_atype == MOTION_EVENT)
1548
number = ((XDeviceMotionEvent *) e)->is_hint;
1550
goto do_unsigned_number;
1552
if (event_atype == KEY_EVENT)
1554
number = ((XDeviceKeyEvent *) e)->keycode;
1556
goto do_unsigned_number;
1560
number = ((XDeviceButtonEvent *) e)->state;
1562
goto do_unsigned_number;
1566
number = ((XDeviceButtonEvent *) e)->time;
1568
else if (event_atype == FOCUS_EVENT)
1570
number = ((XDeviceFocusChangeEvent *) e)->time;
1574
/* The other 3 event types:
1575
* Mapping, State & Change are compatible.
1577
number = ((XChangeDeviceNotifyEvent *) e)->time;
1579
goto do_unsigned_number;
1583
number = ((XDeviceButtonEvent *) e)->x;
1585
goto do_unsigned_number;
1589
number = ((XDeviceButtonEvent *) e)->y;
1591
goto do_unsigned_number;
1593
if (event_atype == CHANGE_DEVICE_EVENT)
1595
XChangeDeviceNotifyEvent *cdne = (XChangeDeviceNotifyEvent *) e;
1596
if (cdne->request == NewKeyboard)
1598
scan = "NewKeyboard";
1600
else if (cdne->request == NewPointer)
1602
scan = "NewPointer";
1607
scan = (char *)device->name;
1610
number = e->xany.send_event;
1611
goto do_unsigned_number;
1615
number = device_state;
1617
goto do_unsigned_number;
1619
for (i = 0; i < NUM_XI_EVENTS; i++)
1621
if (device->dpy_info->event_types[i] == e->type)
1623
scan = (char *)xi_event_names[i];
1631
scan = Tk_PathName(tkwin);
1637
number = ((XDeviceButtonEvent *) e)->x_root;
1640
Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height);
1644
goto do_unsigned_number;
1648
number = ((XDeviceButtonEvent *) e)->y_root;
1651
Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height);
1655
goto do_unsigned_number;
1657
num_buffer[0] = script[1];
1658
num_buffer[1] = '\0';
1664
sprintf(num_buffer, "%lu", number);
1669
sprintf(num_buffer, "%ld", number);
1673
space_needed = Tcl_ScanElement(scan, &cvt_flags);
1674
length = Tcl_DStringLength(exp_script);
1675
Tcl_DStringSetLength(exp_script, length + space_needed);
1676
space_needed = Tcl_ConvertElement(scan,
1677
Tcl_DStringValue(exp_script) + length,
1678
cvt_flags | TCL_DONT_USE_BRACES);
1679
Tcl_DStringSetLength(exp_script, length + space_needed);
1682
/*printf("End ExpandPercents\n");*/
1686
*----------------------------------------------------------------------
1688
* InvokeEventScript --
1689
* Invoke a script that has been registered for an event form an
1690
* input device. Any % occuring in the script will be replaced by
1691
* a string depending on the characters following the percent.
1692
* The recognized % sequences are:
1694
* %# The number of the last request processed by the
1696
* %0-9 The value of valuator n (0-9).
1697
* %* The name of the device (as encoded in a valuator
1698
* by the switch virtual device).
1699
* %b The button number for events related to buttons.
1700
* %h The motion hint field from the event.
1701
* %k The keycode for events related to keys.
1702
* %s The state field from the event (the core that is).
1703
* %t The time field from the event.
1704
* %x The x coord of the core pointer.
1705
* %y The y coord of the core pointer.
1706
* %C The name of the core device that changed (only
1707
* for DeviceChange events).
1708
* %D The device name that has emitted the event.
1709
* %E The send_event field from the event.
1710
* %S The device state field from the event.
1711
* %T The type field from the event, as an event name.
1712
* %W The window receiving the event.
1713
* %X The root window x coord of the core pointer.
1714
* %Y The root window y coord of the core pointer.
1716
* An unrecognized sequence is replaced by the sequence with
1717
* the leading percent removed.
1719
*----------------------------------------------------------------------
1722
InvokeEventScript(ClientData client_data,
1725
EventScriptRecord *escripts = (EventScriptRecord *) client_data;
1726
DeviceInfoStruct *device;
1727
Tcl_Interp *interp = escripts->interp;
1730
Tcl_DString exp_script;
1731
int i, try_to_merge = 0;
1732
int first_axis = 0, axes_count = 0;
1733
int *axis_data = NULL;
1735
device = LookupDeviceById(((XDeviceKeyEvent *) e)->display,
1736
((XDeviceKeyEvent *) e)->deviceid);
1737
event_atype = device->dpy_info->event_atypes[e->type];
1739
* If the event is a key, button, motion or proximity event,
1740
* try to merge events emitted to report more than 6 valuators.
1741
* It is assumed that an event train can't be mixed with another
1742
* from the same device.
1744
if ((event_atype == BUTTON_EVENT) || (event_atype == KEY_EVENT))
1746
first_axis = ((XDeviceKeyEvent *) e)->first_axis;
1747
axes_count = ((XDeviceKeyEvent *) e)->axes_count;
1748
axis_data = ((XDeviceKeyEvent *) e)->axis_data;
1751
else if (event_atype == MOTION_EVENT)
1753
first_axis = ((XDeviceMotionEvent *) e)->first_axis;
1754
axes_count = ((XDeviceMotionEvent *) e)->axes_count;
1755
axis_data = ((XDeviceMotionEvent *) e)->axis_data;
1758
else if (event_atype == PROXIMITY_EVENT)
1760
first_axis = ((XProximityNotifyEvent *) e)->first_axis;
1761
axes_count = ((XProximityNotifyEvent *) e)->axes_count;
1762
axis_data = ((XProximityNotifyEvent *) e)->axis_data;
1771
* Cache the axes reported in this event.
1773
for (i = first_axis; i < axes_count; i++)
1775
device->valuator_cache[i] = axis_data[i-first_axis];
1778
* If this isn't the last event, wait for the others.
1780
if (axes_count > (first_axis+6)) return;
1784
Tcl_Preserve((ClientData) interp);
1785
Tcl_DStringInit(&exp_script);
1786
ExpandPercents(escripts->tkwin, device, e, event_atype,
1787
escripts->script, &exp_script);
1789
* Get the content of the escript before triggering
1790
* the script. It may destroy the binding before returning
1791
* and we might still need the info in case of error.
1793
result = Tcl_GlobalEval(interp, Tcl_DStringValue(&exp_script));
1794
Tcl_DStringFree(&exp_script);
1795
if (result != TCL_OK)
1797
Tcl_BackgroundError(interp);
1799
Tcl_Release((ClientData) interp);
1800
/*printf("End InvokeEventScript\n");*/
1804
*----------------------------------------------------------------------
1807
* Register a script to be invoked when an event is received in a
1808
* window from a device. The server is asked to report the event
1811
* If it is not possible to bind the event the function return
1812
* 0 else it returns 1.
1814
*----------------------------------------------------------------------
1817
AddEventScript(Tcl_Interp *interp,
1819
DeviceInfoStruct *device,
1823
WindowInfoStruct *pw = GetWindowInfo(tkwin, 1);
1824
EventScriptRecord *escripts = NULL;
1826
/*printf("Begin of AddEventScript\n");*/
1829
* Try to see if a script is already registered with the
1830
* same combination of device, event and interp.
1832
for (escripts = pw->scripts; escripts != NULL; escripts = escripts->next)
1834
if ((escripts->device == device) &&
1835
(escripts->event_spec == event_spec) &&
1836
(escripts->interp == interp))
1838
ckfree(escripts->script);
1839
escripts->script = NULL;
1844
* The event/device combo has no script already registered. Create
1845
* a new record and register with the server. The InvokeEventScript
1846
* function will be called with the script record as parameter when
1847
* an event of this type/device will be received on the window.
1849
if (escripts == NULL)
1851
escripts = (EventScriptRecord *) ckalloc(sizeof(EventScriptRecord));
1852
escripts->device = device;
1853
escripts->tkwin = tkwin;
1854
escripts->event_spec = event_spec;
1855
escripts->interp = interp;
1856
if (!Tk_CreateXiEventHandler(tkwin, event_spec, device->name,
1857
InvokeEventScript, (ClientData) escripts))
1859
ckfree((char *) escripts);
1862
escripts->next = pw->scripts;
1863
pw->scripts = escripts;
1866
* Setup the script in the record.
1868
escripts->script = ckalloc(strlen(script) + 1);
1869
strcpy(escripts->script, script);
1875
*----------------------------------------------------------------------
1877
* WacomxiBindEventCmd --
1878
* Implements the 'bindevent' tcl command.
1880
*----------------------------------------------------------------------
1883
WacomxiBindEventCmd(ClientData clientData,
1888
Tk_Window mainwin = (Tk_Window) clientData;
1890
DeviceInfoStruct *device;
1894
if ((argc != 4) && (argc != 5))
1896
Tcl_AppendResult(interp, "wrong # of arguments, should be \"",
1897
argv[0], "win device event ?script?\"", (char *) NULL);
1900
tkwin = Tk_NameToWindow(interp, argv[1], mainwin);
1902
if ( !tkwin ) return TCL_ERROR;
1904
device = GetDeviceInfo(tkwin, Tk_GetUid(argv[2]));
1907
Tcl_AppendResult(interp, "unknown device \"", argv[2],
1908
"\" or it is currently a core device", (char *) NULL);
1912
len = strlen(argv[3]);
1913
if ((argv[3][0] != '<') || (argv[3][len-1] != '>'))
1915
Tcl_AppendResult(interp,
1916
"invalid event specification, should perhaps be <",
1917
argv[3], ">", (char *) NULL);
1921
event_spec = Tk_GetUid(&argv[3][1]);
1922
argv[3][len-1] = '>';
1925
* Asked to return the script associated with the widget/event.
1926
* Lookup the scripts associated with window and in this list
1927
* the script associated with the given event.
1931
WindowInfoStruct *pw = GetWindowInfo(tkwin, 1);
1932
EventScriptRecord *escripts;
1934
for (escripts = pw->scripts; escripts != NULL; escripts = escripts->next)
1936
if ((escripts->device == device) &&
1937
(escripts->event_spec == event_spec) &&
1938
(escripts->interp == interp))
1940
Tcl_SetResult(interp, (char *)escripts->script, TCL_STATIC);
1947
* The script is the empty string, remove the event binding.
1951
RemoveEventScript(interp, tkwin, device, event_spec);
1955
* Add or override the event binding if the event can be
1956
* reported by the device. Else report an error.
1958
if (!AddEventScript(interp, tkwin, device, event_spec, argv[4]))
1960
Tcl_AppendResult(interp, "Event \"", argv[3],
1961
"\" can't be reported by device \"", argv[2],
1962
"\"", (char *) NULL);
1965
/*printf("Added event %s \n", argv[3] );*/
1972
Libwacomxi_Init(Tcl_Interp *interp)
1974
static int setup_done = 0;
1977
if (!Tk_MainWindow(interp)) {
1978
Tcl_AppendResult(interp,
1979
"... Xinput package need Tk to run.",
1986
Tk_CreateGenericHandler(WacomxiGenericEventHandler, NULL);
1989
Tcl_CreateCommand(interp,
1990
"wacomxi::bindevent",
1991
(Tcl_CmdProc *)WacomxiBindEventCmd,
1992
(ClientData) Tk_MainWindow(interp),
1993
(Tcl_CmdDeleteProc *) NULL);
1996
* Convert events names into uids for speed and ease of use.
1998
for (i = 0; i < NUM_XI_EVENTS; i++)
2000
xi_event_names[i] = Tk_GetUid(xi_event_names[i]);
2003
return Tcl_PkgProvide(interp, "LIBWACOMXI", "1.0");