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