1 /*
2 * Clutter.
3 *
4 * An OpenGL based 'interactive canvas' library.
5 *
6 * Copyright © 2011 Intel Corp.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20 *
21 * Author: Emmanuele Bassi <ebassi@linux.intel.com>
22 */
23
24 #include "config.h"
25
26 #include "clutter-input-device-xi2.h"
27
28 #include "clutter-debug.h"
29 #include "clutter-device-manager-private.h"
30 #include "clutter-event-private.h"
31 #include "clutter-private.h"
32 #include "clutter-stage-private.h"
33
34 #include "clutter-backend-x11.h"
35 #include "clutter-stage-x11.h"
36
37 #include <X11/extensions/XInput2.h>
38
39 typedef struct _ClutterInputDeviceClass ClutterInputDeviceXI2Class;
40
41 /* a specific XI2 input device */
42 struct _ClutterInputDeviceXI2
43 {
44 ClutterInputDevice device;
45
46 gint device_id;
47 };
48
49 #define N_BUTTONS 5
50
51 #define clutter_input_device_xi2_get_type _clutter_input_device_xi2_get_type
52
53 G_DEFINE_TYPE (ClutterInputDeviceXI2,
54 clutter_input_device_xi2,
55 CLUTTER_TYPE_INPUT_DEVICE);
56
57 static void
clutter_input_device_xi2_constructed(GObject * gobject)58 clutter_input_device_xi2_constructed (GObject *gobject)
59 {
60 ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (gobject);
61
62 g_object_get (gobject, "id", &device_xi2->device_id, NULL);
63
64 if (G_OBJECT_CLASS (clutter_input_device_xi2_parent_class)->constructed)
65 G_OBJECT_CLASS (clutter_input_device_xi2_parent_class)->constructed (gobject);
66 }
67
68 static gboolean
clutter_input_device_xi2_keycode_to_evdev(ClutterInputDevice * device,guint hardware_keycode,guint * evdev_keycode)69 clutter_input_device_xi2_keycode_to_evdev (ClutterInputDevice *device,
70 guint hardware_keycode,
71 guint *evdev_keycode)
72 {
73 /* When using evdev under X11 the hardware keycodes are the evdev
74 keycodes plus 8. I haven't been able to find any documentation to
75 know what the +8 is for. FIXME: This should probably verify that
76 X server is using evdev. */
77 *evdev_keycode = hardware_keycode - 8;
78
79 return TRUE;
80 }
81
82 static void
clutter_input_device_xi2_class_init(ClutterInputDeviceXI2Class * klass)83 clutter_input_device_xi2_class_init (ClutterInputDeviceXI2Class *klass)
84 {
85 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
86 ClutterInputDeviceClass *device_class = CLUTTER_INPUT_DEVICE_CLASS (klass);
87
88 gobject_class->constructed = clutter_input_device_xi2_constructed;
89
90 device_class->keycode_to_evdev = clutter_input_device_xi2_keycode_to_evdev;
91 }
92
93 static void
clutter_input_device_xi2_init(ClutterInputDeviceXI2 * self)94 clutter_input_device_xi2_init (ClutterInputDeviceXI2 *self)
95 {
96 }
97
98 static ClutterModifierType
get_modifier_for_button(int i)99 get_modifier_for_button (int i)
100 {
101 switch (i)
102 {
103 case 1:
104 return CLUTTER_BUTTON1_MASK;
105 case 2:
106 return CLUTTER_BUTTON2_MASK;
107 case 3:
108 return CLUTTER_BUTTON3_MASK;
109 case 4:
110 return CLUTTER_BUTTON4_MASK;
111 case 5:
112 return CLUTTER_BUTTON5_MASK;
113 default:
114 return 0;
115 }
116 }
117
118 void
_clutter_input_device_xi2_translate_state(ClutterEvent * event,XIModifierState * modifiers_state,XIButtonState * buttons_state,XIGroupState * group_state)119 _clutter_input_device_xi2_translate_state (ClutterEvent *event,
120 XIModifierState *modifiers_state,
121 XIButtonState *buttons_state,
122 XIGroupState *group_state)
123 {
124 guint button = 0;
125 guint base = 0;
126 guint latched = 0;
127 guint locked = 0;
128 guint effective;
129
130 if (modifiers_state)
131 {
132 base = (guint) modifiers_state->base;
133 latched = (guint) modifiers_state->latched;
134 locked = (guint) modifiers_state->locked;
135 }
136
137 if (buttons_state)
138 {
139 int len, i;
140
141 len = MIN (N_BUTTONS, buttons_state->mask_len * 8);
142
143 for (i = 0; i < len; i++)
144 {
145 if (!XIMaskIsSet (buttons_state->mask, i))
146 continue;
147
148 button |= get_modifier_for_button (i);
149 }
150 }
151
152 /* The XIButtonState sent in the event specifies the
153 * state of the buttons before the event. In order to
154 * get the current state of the buttons, we need to
155 * filter out the current button.
156 */
157 switch (event->type)
158 {
159 case CLUTTER_BUTTON_PRESS:
160 button |= (get_modifier_for_button (event->button.button));
161 break;
162 case CLUTTER_BUTTON_RELEASE:
163 button &= ~(get_modifier_for_button (event->button.button));
164 break;
165 default:
166 break;
167 }
168
169 effective = button | base | latched | locked;
170 if (group_state)
171 effective |= (group_state->effective) << 13;
172
173 _clutter_event_set_state_full (event, button, base, latched, locked, effective);
174 }
175