-
Notifications
You must be signed in to change notification settings - Fork 4
/
inputkb-gdk.cpp
203 lines (177 loc) · 6.53 KB
/
inputkb-gdk.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#include "io.h"
#ifdef INPUT_GDK
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#ifdef WNDPROT_X11
#include <gdk/gdkx.h>
#endif
#include <stdlib.h>
#include <string.h>
namespace {
class inputkb_gdk : public inputkb {
public:
GdkDeviceManager* devicemanager;
GtkWidget* widget;//likely a GtkWindow, but we only use it as GtkWidget so let's keep it as that.
unsigned int numdevices;
//char padding[4];
GdkDevice* * devices;
public:
static const uint32_t feat = f_multi|f_delta|f_auto|f_public;
uint32_t features() { return feat; }
//void refresh(); // we cannot poll the device
//void poll(); // we do this through the gtk+ main loop
unsigned int find_or_allocate_id_for(GdkDevice* device)
{
unsigned int kb=0;
while (kb<this->numdevices && this->devices[kb]!=device) kb++;
if (kb==this->numdevices)
{
kb=0;
while (kb<this->numdevices && this->devices[kb]) kb++;
if (kb==this->numdevices)
{
this->devices=realloc(this->devices, sizeof(GdkDevice*)*(this->numdevices+1));
this->devices[this->numdevices]=device;
this->numdevices++;
}
else this->devices[kb]=device;
}
return kb;
}
//static void device_add(GdkDeviceManager* object, GdkDevice* device, gpointer user_data)
//{
//ignore everything, because there are a LOT of bogus entries in the device list
//If I plug in three keyboards, I get both duplicates and bogus devices:
//
// Virtual core keyboard id=3 [master keyboard (2)]
// Virtual core XTEST keyboard id=5 [slave keyboard (3)]
// Power Button id=6 [slave keyboard (3)]
// Power Button id=7 [slave keyboard (3)]
// CHESEN USB Keyboard id=10 [slave keyboard (3)]
// CHESEN USB Keyboard id=11 [slave keyboard (3)]
// LITEON Technology USB Multimedia Keyboard id=9 [slave keyboard (3)]
// DELL Dell USB Wired Multimedia Keyboard id=12 [slave keyboard (3)]
// DELL Dell USB Wired Multimedia Keyboard id=13 [slave keyboard (3)]
//where especially the duplicates seem irritating to get rid of.
//Instead, we give the lowest ID to the first device to send an event.
//
// struct inputkb_gdk * this=(struct inputkb_gdk*)user_data;
// if (gdk_device_get_source(device)!=GDK_SOURCE_KEYBOARD) return;
// //if (gdk_device_get_device_type(device)!=GDK_DEVICE_TYPE_SLAVE) return;//allow floating ones too - masters fall to the Virtual test
// if (!strcasecmp(gdk_device_get_name(device), "Power Button")) return;//Power Button
// if (!strncasecmp(gdk_device_get_name(device), "Virtual ", strlen("Virtual "))) return;//Virtual core XTEST keyboard
// //there are probably more things to ignore...
// for (unsigned int i=0;i<this->numdevices;i++)
// {
// if (!this->devices[i])
// {
// this->devices[i]=device;
// return;
// }
// }
// this->devices=realloc(this->devices, sizeof(GdkDevice*)*(this->numdevices+1));
// this->devices[this->numdevices]=device;
// this->numdevices++;
//}
void device_remove(GdkDeviceManager* object, GdkDevice* device)
{
for (unsigned int i=0;i<this->numdevices;i++)
{
for (unsigned int j=0;j<256;j++)
{
this->key_cb(i, j, inputkb::translate_scan(j), false);
}
if (this->devices[i]==device) this->devices[i]=NULL;
}
}
static void device_remove_s(GdkDeviceManager* object, GdkDevice* device, gpointer user_data)
{
inputkb_gdk* obj=(inputkb_gdk*)user_data;
obj->device_remove(object, device);
}
gboolean key_action(GtkWidget* widget, GdkEvent* event)
{
GdkDevice* device=gdk_event_get_source_device(event);
//for some reason, repeated keystrokes come from the master device, which screws up device ID assignments
//we don't want repeats all, let's just kill them.
if (gdk_device_get_device_type(device)==GDK_DEVICE_TYPE_MASTER) return FALSE;
unsigned int kb=find_or_allocate_id_for(device);
guint16 keycode;
gdk_event_get_keycode(event, &keycode);
//printf("%i: %.2X %.2X\n", kb, keycode, inputkb_translate_scan(keycode));
this->key_cb(kb+1, keycode, inputkb::translate_scan(keycode), (event->type==GDK_KEY_PRESS));
return FALSE;
}
static gboolean key_action_s(GtkWidget* widget, GdkEvent* event, gpointer user_data)
{
inputkb_gdk* obj=(struct inputkb_gdk*)user_data;
return obj->key_action(widget, event);
}
~inputkb_gdk()
{
g_signal_handlers_disconnect_by_data(this->widget, this);
g_signal_handlers_disconnect_by_data(this->devicemanager, this);
free(this->devices);
}
inputkb_gdk(uintptr_t windowhandle)
{
#ifdef WNDPROT_X11
GdkDisplay* display=gdk_x11_lookup_xdisplay(window_x11.display);
#else
#error Fill this in.
#endif
this->devicemanager=gdk_display_get_device_manager(display);
//g_signal_connect(this->devicemanager, "device-added", G_CALLBACK(device_add_s), this);
g_signal_connect(this->devicemanager, "device-removed", G_CALLBACK(device_remove_s), this);
gdk_window_get_user_data(gdk_x11_window_lookup_for_display(display, windowhandle), (void**)&this->widget);
//we probably have a GtkDrawingArea, and those can't have keyboard focus. Let's ask for the GtkWindow it is in instead.
this->widget=gtk_widget_get_toplevel(this->widget);
gtk_widget_add_events(this->widget, GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK);
g_signal_connect(this->widget, "key-press-event", G_CALLBACK(key_action_s), this);
g_signal_connect(this->widget, "key-release-event", G_CALLBACK(key_action_s), this);
this->numdevices=0;
this->devices=NULL;
//GdkDeviceType types[2]={ GDK_DEVICE_TYPE_SLAVE, GDK_DEVICE_TYPE_FLOATING };
//for (int i=0;i<2;i++)
//{
// GList* devices=gdk_device_manager_list_devices(this->devicemanager, types[i]);
// GList* list=devices;
// while (list)
// {
// device_add(NULL, GDK_DEVICE(list->data), this);
// list=list->next;
// }
// g_list_free(devices);
//}
//a GdkDevice* can be queried with:
//XDevice dev;
//dev.device_id=gdk_x11_device_get_id(device);
//XDeviceState * state=XQueryDeviceState(this->display, this->devices[kb_id]);
//if (state)
//{
// XInputClass * cls=state->data;
// for (int j=0;j<state->num_classes;j++)
// {
// if (cls->class==KeyClass)
// {
// XKeyState * key_state=(XKeyState*)cls;
// memset(keys+key_state->num_keys, 0, 256-key_state->num_keys);
// for (int k=0;k<key_state->num_keys;k++)
// {
// keys[k]=((key_state->keys[k / 8] & (1 << (k % 8))));
// }
// break;
// }
// cls=(XInputClass*)((char*)cls + cls->length);
// }
// XFreeDeviceState(state);
//}
}
static inputkb* create(uintptr_t windowhandle)
{
return new inputkb_gdk(windowhandle);
}
};
}
const inputkb::driver inputkb::driver_gdk={ "GDK", inputkb_gdk::create, inputkb_gdk::feat };
#endif