70 } |
83 } |
71 } |
84 } |
72 return L""; |
85 return L""; |
73 } |
86 } |
74 |
87 |
75 void listInputDevices(Display& display, Configuration& configuration, std::shared_ptr<writer::RelationalWriter> writer) { |
88 void listInputDevices(const Display& display, Configuration& configuration, std::shared_ptr<writer::RelationalWriter> writer, std::function<void() > relationalWriterFlush) { |
76 writer->startRelation(L"x11_input_device",{ |
89 writer->startRelation(L"x11_input_device",{ |
77 {L"id", relpipe::writer::TypeId::INTEGER}, |
90 {L"id", relpipe::writer::TypeId::INTEGER}, |
78 {L"name", relpipe::writer::TypeId::STRING}, |
91 {L"name", relpipe::writer::TypeId::STRING}, |
79 {L"type", relpipe::writer::TypeId::STRING}, |
92 {L"type", relpipe::writer::TypeId::STRING}, |
80 }, true); |
93 }, true); |
81 |
94 |
82 DeviceList devices; |
95 DeviceInfoList devices; |
83 devices.items = XListInputDevices(display.display, &devices.count); |
96 devices.items = XListInputDevices(display.display, &devices.size); |
84 |
97 |
85 for (int i = 0; i < devices.count; i++) { |
98 for (int i = 0; i < devices.size; i++) { |
86 relpipe::common::type::Integer id = (devices.items + i)->id; |
99 relpipe::common::type::Integer id = devices[i]->id; |
87 relpipe::common::type::StringX name = convertor.from_bytes((devices.items + i)->name); |
100 relpipe::common::type::StringX name = convertor.from_bytes(devices[i]->name); |
88 relpipe::common::type::StringX type = getDeviceType(display, devices.items + i); |
101 relpipe::common::type::StringX type = getDeviceType(display, devices[i]); |
89 |
102 |
90 writer->writeAttribute(&id, typeid (id)); |
103 writer->writeAttribute(&id, typeid (id)); |
91 writer->writeAttribute(&name, typeid (name)); |
104 writer->writeAttribute(&name, typeid (name)); |
92 writer->writeAttribute(&type, typeid (type)); |
105 writer->writeAttribute(&type, typeid (type)); |
93 } |
106 } |
94 } |
107 |
95 |
108 relationalWriterFlush(); |
96 void listInputEvents(Display& display, Configuration& configuration, std::shared_ptr<writer::RelationalWriter> writer) { |
109 } |
|
110 |
|
111 /** |
|
112 * Fields of this structure are filled in DeviceKeyPress(), DeviceButtonPress() … macros. |
|
113 */ |
|
114 class EventType { |
|
115 private: |
|
116 const static int UNUSED = -1; |
|
117 public: |
|
118 int motion = UNUSED; |
|
119 int buttonPress = UNUSED; |
|
120 int buttonRelease = UNUSED; |
|
121 int keyPress = UNUSED; |
|
122 int keyRelease = UNUSED; |
|
123 int proximityIn = UNUSED; |
|
124 int proximityOut = UNUSED; |
|
125 } eventType; |
|
126 |
|
127 void registerEvents(const Display& display, const XDeviceInfo* deviceInfo) { |
|
128 bool registerProximityEvents = false; // TODO: proximity? |
|
129 |
|
130 Device device; |
|
131 Window window; |
|
132 int screen; |
|
133 |
|
134 int eventCount = 0; |
|
135 XEventClass events[7]; // TODO: check array size |
|
136 XInputClassInfo* classInfo; |
|
137 int classIndex; |
|
138 |
|
139 screen = DefaultScreen(display.display); |
|
140 window = RootWindow(display.display, screen); |
|
141 // TODO: configurable window from which we capture the events or optionally open our own window (can also provide some visual feedback/info) |
|
142 // Currently we can do something like: |
|
143 // Xephyr :5 -screen 1920x1080 |
|
144 // DISPLAY=:5 relpipe-in-x11 --list-input-devices false --list-input-events true | … |
|
145 |
|
146 device.device = XOpenDevice(display.display, deviceInfo->id); |
|
147 |
|
148 if (device.device) { |
|
149 if (device.device->num_classes > 0) { |
|
150 for (classInfo = device.device->classes, classIndex = 0; classIndex < deviceInfo->num_classes; classInfo++, classIndex++) { |
|
151 if (classInfo->input_class == KeyClass) { |
|
152 DeviceKeyPress(device.device, eventType.keyPress, events[eventCount]); |
|
153 eventCount++; |
|
154 DeviceKeyRelease(device.device, eventType.keyRelease, events[eventCount]); |
|
155 eventCount++; |
|
156 } else if (classInfo->input_class == ButtonClass) { |
|
157 DeviceButtonPress(device.device, eventType.buttonPress, events[eventCount]); |
|
158 eventCount++; |
|
159 DeviceButtonRelease(device.device, eventType.buttonRelease, events[eventCount]); |
|
160 eventCount++; |
|
161 } else if (classInfo->input_class == ValuatorClass) { |
|
162 DeviceMotionNotify(device.device, eventType.motion, events[eventCount]); |
|
163 eventCount++; |
|
164 if (registerProximityEvents) { |
|
165 ProximityIn(device.device, eventType.proximityIn, events[eventCount]); |
|
166 eventCount++; |
|
167 ProximityOut(device.device, eventType.proximityOut, events[eventCount]); |
|
168 eventCount++; |
|
169 } |
|
170 } |
|
171 } |
|
172 |
|
173 int result = XSelectExtensionEvent(display.display, window, events, eventCount); |
|
174 if (result != Success) throw std::logic_error("Unable to register events from device: " + std::to_string(deviceInfo->id) + " Result: " + std::to_string(result)); |
|
175 } |
|
176 } else { |
|
177 throw std::invalid_argument("Unable to open the device: " + std::to_string(deviceInfo->id)); |
|
178 } |
|
179 } |
|
180 |
|
181 void listInputEvents(Display& display, Configuration& configuration, std::shared_ptr<writer::RelationalWriter> writer, std::function<void() > relationalWriterFlush) { |
97 writer->startRelation(L"x11_input_event",{ |
182 writer->startRelation(L"x11_input_event",{ |
98 {L"device_id", relpipe::writer::TypeId::INTEGER}, |
183 {L"device", relpipe::writer::TypeId::INTEGER}, |
|
184 {L"type", relpipe::writer::TypeId::STRING}, |
|
185 {L"state", relpipe::writer::TypeId::STRING}, |
|
186 {L"key", relpipe::writer::TypeId::INTEGER}, |
|
187 {L"button", relpipe::writer::TypeId::INTEGER}, |
|
188 {L"x", relpipe::writer::TypeId::INTEGER}, |
|
189 {L"y", relpipe::writer::TypeId::INTEGER}, |
|
190 // {L"x_root", relpipe::writer::TypeId::INTEGER}, |
|
191 // {L"y_root", relpipe::writer::TypeId::INTEGER}, |
99 }, true); |
192 }, true); |
100 |
193 |
101 // TODO: list events |
194 |
102 } |
195 { |
|
196 DeviceInfoList devices; |
|
197 devices.items = XListInputDevices(display.display, &devices.size); |
|
198 for (int i = 0; i < devices.size; i++) { |
|
199 try { |
|
200 registerEvents(display, devices[i]); |
|
201 } catch (...) { |
|
202 // exception "Unable to open device: …" |
|
203 // TODO: do not call registerEvents() for some devices, skip them |
|
204 } |
|
205 } |
|
206 } |
|
207 |
|
208 for (XEvent event; true;) { |
|
209 XNextEvent(display.display, &event); |
|
210 |
|
211 relpipe::common::type::Integer device = -1; // TODO: null |
|
212 relpipe::common::type::StringX type; |
|
213 relpipe::common::type::StringX state; |
|
214 relpipe::common::type::Integer button = -1; // TODO: null |
|
215 relpipe::common::type::Integer key = -1; // TODO: null |
|
216 relpipe::common::type::Integer x = -1; // TODO: null |
|
217 relpipe::common::type::Integer y = -1; // TODO: null |
|
218 // relpipe::common::type::Integer xRoot = -1; // TODO: null |
|
219 // relpipe::common::type::Integer yRoot = -1; // TODO: null |
|
220 |
|
221 if (event.type == eventType.motion) { |
|
222 XDeviceMotionEvent* e = (XDeviceMotionEvent*) & event; |
|
223 device = e->deviceid; |
|
224 type = L"motion"; |
|
225 x = e->x; |
|
226 y = e->y; |
|
227 // xRoot = e->x_root; |
|
228 // yRoot = e->y_root; |
|
229 } else if (event.type == eventType.buttonPress || event.type == eventType.buttonRelease) { |
|
230 XDeviceButtonEvent* e = (XDeviceButtonEvent*) & event; |
|
231 device = e->deviceid; |
|
232 type = L"button"; |
|
233 state = event.type == eventType.buttonPress ? L"pressed" : L"released"; |
|
234 button = e->button; |
|
235 x = e->x; |
|
236 y = e->y; |
|
237 // xRoot = e->x_root; |
|
238 // yRoot = e->y_root; |
|
239 } else if (event.type == eventType.keyPress || event.type == eventType.keyRelease) { |
|
240 XDeviceKeyEvent* e = (XDeviceKeyEvent*) & event; |
|
241 device = e->deviceid; |
|
242 type = L"key"; |
|
243 state = event.type == eventType.keyPress ? L"pressed" : L"released"; |
|
244 key = e->keycode; |
|
245 x = e->x; |
|
246 y = e->y; |
|
247 // xRoot = e->x_root; |
|
248 // yRoot = e->y_root; |
|
249 } else if (event.type == eventType.proximityIn || event.type == eventType.proximityOut) { |
|
250 XProximityNotifyEvent* e = (XProximityNotifyEvent*) & event; |
|
251 device = e->deviceid; |
|
252 type = L"proximity"; |
|
253 } |
|
254 |
|
255 writer->writeAttribute(&device, typeid (device)); |
|
256 writer->writeAttribute(type); |
|
257 writer->writeAttribute(state); |
|
258 writer->writeAttribute(&key, typeid (key)); |
|
259 writer->writeAttribute(&button, typeid (button)); |
|
260 writer->writeAttribute(&x, typeid (x)); |
|
261 writer->writeAttribute(&y, typeid (y)); |
|
262 // writer->writeAttribute(&xRoot, typeid (xRoot)); |
|
263 // writer->writeAttribute(&yRoot, typeid (yRoot)); |
|
264 relationalWriterFlush(); |
|
265 } |
|
266 } |
|
267 |
|
268 static int handleXError(::Display* display, XErrorEvent* errorEvent) { |
|
269 // FIXME: print error |
|
270 return 0; |
|
271 } |
|
272 |
103 |
273 |
104 public: |
274 public: |
105 |
275 |
106 void process(Configuration& configuration, std::shared_ptr<writer::RelationalWriter> writer) { |
276 void process(Configuration& configuration, std::shared_ptr<writer::RelationalWriter> writer, std::function<void() > relationalWriterFlush) { |
|
277 XSetErrorHandler(handleXError); |
|
278 |
107 Display display; |
279 Display display; |
108 display.display = XOpenDisplay(nullptr); |
280 display.display = XOpenDisplay(nullptr); |
109 |
281 |
110 if (display.display) { |
282 if (display.display) { |
111 if (configuration.listInputDevices) listInputDevices(display, configuration, writer); |
283 if (configuration.listInputDevices) listInputDevices(display, configuration, writer, relationalWriterFlush); |
112 if (configuration.listInputEvents) listInputEvents(display, configuration, writer); |
284 if (configuration.listInputEvents) listInputEvents(display, configuration, writer, relationalWriterFlush); |
113 } else { |
285 } else { |
114 throw std::invalid_argument("Unable to open display. Please check the $DISPLAY variable."); |
286 throw std::invalid_argument("Unable to open display. Please check the $DISPLAY variable."); |
115 } |
287 } |
116 } |
288 } |
117 }; |
289 }; |