Move the wxwidgets stuff to one directory
[lsnes.git] / platform / evdev / joystick-evdev.cpp
blobb3b45df9b4c4a844568deb57e5aa0d224ee97386
1 #include <unistd.h>
2 #include <map>
3 #include "command.hpp"
4 #include <dirent.h>
5 #include <set>
6 #include <string>
7 #include <cstring>
8 #include <cctype>
9 #include <sstream>
10 #include "window.hpp"
11 #include "keymapper.hpp"
12 #include <cerrno>
13 #include <fcntl.h>
14 #include <cstdint>
15 extern "C"
17 #include <linux/input.h>
20 namespace
22 const char* axisnames[ABS_MAX + 1] = {0};
23 const char* buttonnames[KEY_MAX + 1] = {0};
25 enum event_type
27 ET_BUTTON,
28 ET_AXIS,
29 ET_HAT_X,
30 ET_HAT_Y
33 struct event_mapping
35 uint16_t joystick;
36 uint32_t tevcode;
37 enum event_type type;
38 uint16_t controlnum;
39 int32_t axis_min;
40 int32_t axis_max;
41 int32_t current_status;
42 uint32_t paired_mapping; //Only hats.
43 class keygroup* group;
46 struct event_mapping dummy_event_mapping = {
47 9999, //Joystick (don't care).
48 99999, //Tyep&Event code (don't care).
49 ET_BUTTON, //Not really.
50 9999, //Control num (don't care).
51 0, //Axis minimum (don't care).
52 0, //Axis maximum (don't care).
53 0, //Current status (don't care).
54 0, //This is not a hat, so don't care about paired mapping.
55 NULL //No associated key group.
58 std::set<keygroup*> keygroups;
59 std::map<uint64_t, struct event_mapping> event_map;
60 std::map<int, uint16_t> joystick_map;
61 std::set<int> joysticks;
62 std::map<uint16_t, std::string> joystick_names;
63 uint16_t connected_joysticks = 0;
65 uint16_t get_joystick_number(int fd)
67 if(joystick_map.count(fd))
68 return joystick_map[fd];
69 else
70 return (joystick_map[fd] = connected_joysticks++);
73 uint64_t get_ev_id(uint16_t joystick, uint16_t type, uint16_t evcode)
75 return (static_cast<uint64_t>(joystick) << 32) |
76 (static_cast<uint64_t>(type) << 16) |
77 static_cast<uint64_t>(evcode);
80 uint64_t get_ev_id(uint16_t joystick, uint32_t tevcode)
82 return (static_cast<uint64_t>(joystick) << 32) |
83 static_cast<uint64_t>(tevcode);
86 void create_button(int fd, uint16_t type, uint16_t evcode, uint16_t buttonnum)
88 uint16_t joynum = get_joystick_number(fd);
89 std::ostringstream _name;
90 _name << "joystick" << joynum << "button" << buttonnum;
91 std::string name = _name.str();
92 keygroup* grp = new keygroup(name, keygroup::KT_KEY);
93 keygroups.insert(grp);
94 struct event_mapping evmap;
95 evmap.joystick = joynum;
96 evmap.tevcode = (static_cast<uint32_t>(type) << 16) | static_cast<uint32_t>(evcode);
97 evmap.type = ET_BUTTON;
98 evmap.controlnum = buttonnum;
99 evmap.axis_min = evmap.axis_max = 0;
100 evmap.current_status = 0;
101 evmap.paired_mapping = 0;
102 evmap.group = grp;
103 event_map[get_ev_id(joynum, evmap.tevcode)] = evmap;
106 void create_axis(int fd, uint16_t type, uint16_t evcode, uint16_t axisnum, int32_t min, int32_t max)
108 uint16_t joynum = get_joystick_number(fd);
109 std::ostringstream _name;
110 _name << "joystick" << joynum << "axis" << axisnum;
111 std::string name = _name.str();
112 keygroup* grp;
113 if(min < 0)
114 grp = new keygroup(name, keygroup::KT_AXIS_PAIR);
115 else
116 grp = new keygroup(name, keygroup::KT_PRESSURE_MP);
117 keygroups.insert(grp);
118 struct event_mapping evmap;
119 evmap.joystick = joynum;
120 evmap.tevcode = (static_cast<uint32_t>(type) << 16) | static_cast<uint32_t>(evcode);
121 evmap.type = ET_AXIS;
122 evmap.controlnum = axisnum;
123 evmap.axis_min = min;
124 evmap.axis_max = max;
125 evmap.current_status = 0;
126 evmap.paired_mapping = 0;
127 evmap.group = grp;
128 event_map[get_ev_id(joynum, evmap.tevcode)] = evmap;
131 void create_hat(int fd, uint16_t type, uint16_t evcodeX, uint16_t evcodeY, uint16_t hatnum)
133 uint16_t joynum = get_joystick_number(fd);
134 std::ostringstream _name;
135 _name << "joystick" << joynum << "hat" << hatnum;
136 std::string name = _name.str();
137 keygroup* grp = new keygroup(name, keygroup::KT_HAT);
138 keygroups.insert(grp);
139 struct event_mapping evmap1;
140 evmap1.joystick = joynum;
141 evmap1.tevcode = (static_cast<uint32_t>(type) << 16) | static_cast<uint32_t>(evcodeX);
142 evmap1.type = ET_HAT_X;
143 evmap1.controlnum = hatnum;
144 evmap1.axis_min = -1;
145 evmap1.axis_max = 1;
146 evmap1.current_status = 0;
147 evmap1.group = grp;
148 struct event_mapping evmap2;
149 evmap2.joystick = joynum;
150 evmap2.tevcode = (static_cast<uint32_t>(type) << 16) | static_cast<uint32_t>(evcodeY);
151 evmap2.type = ET_HAT_Y;
152 evmap2.controlnum = hatnum;
153 evmap2.axis_min = -1;
154 evmap1.axis_max = 1;
155 evmap2.current_status = 0;
156 evmap2.group = grp;
157 evmap1.paired_mapping = get_ev_id(joynum, evmap2.tevcode);
158 evmap2.paired_mapping = get_ev_id(joynum, evmap1.tevcode);
159 event_map[get_ev_id(joynum, evmap1.tevcode)] = evmap1;
160 event_map[get_ev_id(joynum, evmap2.tevcode)] = evmap2;
163 struct event_mapping& get_mapping_for(uint16_t joystick, uint16_t type, uint16_t evcode)
165 uint64_t evid = get_ev_id(joystick, type, evcode);
166 if(event_map.count(evid))
167 return event_map[evid];
168 else
169 return dummy_event_mapping;
172 struct event_mapping& get_mapping_for(uint16_t joystick, uint32_t tevcode)
174 uint64_t evid = get_ev_id(joystick, tevcode);
175 if(event_map.count(evid))
176 return event_map[evid];
177 else
178 return dummy_event_mapping;
181 struct event_mapping& get_mapping_for_fd(int fd, uint16_t type, uint16_t evcode)
183 if(joystick_map.count(fd))
184 return get_mapping_for(joystick_map[fd], type, evcode);
185 else
186 return dummy_event_mapping;
189 void update_mapping_for_fd(int fd, uint16_t type, uint16_t evcode, int32_t value)
191 struct event_mapping& e = get_mapping_for_fd(fd, type, evcode);
192 e.current_status = value;
193 if(!e.group)
194 return; //Dummy.
195 int16_t v = 0;
196 switch(e.type) {
197 case ET_BUTTON:
198 v = (e.current_status != 0);
199 break;
200 case ET_AXIS:
201 v = -32768 + 65535 * (static_cast<double>(e.current_status) - e.axis_min) /
202 (static_cast<double>(e.axis_max) - e.axis_min);
203 break;
204 case ET_HAT_X:
205 case ET_HAT_Y: {
206 uint32_t xaxis, yaxis;
207 if(e.type == ET_HAT_X) {
208 xaxis = get_ev_id(e.joystick, e.tevcode);
209 yaxis = e.paired_mapping;
210 } else {
211 yaxis = get_ev_id(e.joystick, e.tevcode);
212 xaxis = e.paired_mapping;
214 if(event_map[yaxis].current_status < 0)
215 v |= 1;
216 if(event_map[xaxis].current_status > 0)
217 v |= 2;
218 if(event_map[yaxis].current_status > 0)
219 v |= 4;
220 if(event_map[xaxis].current_status < 0)
221 v |= 8;
222 break;
225 e.group->set_position(v, modifier_set());
228 bool read_one_input_event(int fd)
230 struct input_event ev;
231 int r = read(fd, &ev, sizeof(ev));
232 if(r < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
233 return false;
234 if(r < 0) {
235 window::out() << "Error reading from joystick (fd=" << fd << "): " << strerror(errno)
236 << std::endl;
237 return false;
239 update_mapping_for_fd(fd, ev.type, ev.code, ev.value);
240 return true;
243 bool probe_joystick(int fd, const std::string& filename)
245 const size_t div = 8 * sizeof(unsigned long);
246 unsigned long keys[(KEY_MAX + div) / div] = {0};
247 unsigned long axes[(ABS_MAX + div) / div] = {0};
248 unsigned long evtypes[(EV_MAX + div) / div] = {0};
249 char namebuffer[256];
250 unsigned button_count = 0;
251 unsigned axis_count = 0;
252 unsigned hat_count = 0;
253 if(ioctl(fd, EVIOCGBIT(0, sizeof(evtypes)), evtypes) < 0) {
254 int merrno = errno;
255 window::out() << "Error probing joystick (evmap; " << filename << "): " << strerror(merrno)
256 << std::endl;
257 return false;
259 if(!(evtypes[EV_KEY / div] & (1 << EV_KEY % div)) || !(evtypes[EV_ABS / div] & (1 << EV_ABS % div))) {
260 window::out() << "Input (" << filename << ") doesn't look like joystick" << std::endl;
261 return false;
263 if(ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keys)), keys) < 0) {
264 int merrno = errno;
265 window::out() << "Error probing joystick (keymap; " <<filename << "): " << strerror(merrno)
266 << std::endl;
267 return false;
269 if(ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(axes)), axes) < 0) {
270 int merrno = errno;
271 window::out() << "Error probing joystick (axismap; " << filename << "): " << strerror(merrno)
272 << std::endl;
273 return false;
275 if(ioctl(fd, EVIOCGNAME(sizeof(namebuffer)), namebuffer) <= 0) {
276 int merrno = errno;
277 window::out() << "Error probing joystick (name; " << filename << "): " << strerror(merrno)
278 << std::endl;
279 return false;
281 for(unsigned i = 0; i <= KEY_MAX; i++) {
282 if(keys[i / div] & (1ULL << (i % div))) {
283 create_button(fd, EV_KEY, i, button_count++);
286 for(unsigned i = 0; i <= ABS_MAX; i++) {
287 if(axes[i / div] & (1ULL << (i % div))) {
288 if(i < ABS_HAT0X || i > ABS_HAT3Y) {
289 int32_t min;
290 int32_t max;
291 int32_t V[5];
292 if(ioctl(fd, EVIOCGABS(i), V) < 0) {
293 int merrno = errno;
294 window::out() << "Error getting parameters for axis " << i << " (fd="
295 << fd << "): " << strerror(merrno) << std::endl;
296 continue;
298 min = V[1];
299 max = V[2];
300 create_axis(fd, EV_ABS, i, axis_count++, min, max);
301 } else if(i % 2 == 0) {
302 create_hat(fd, EV_ABS, i, i + 1, hat_count++);
306 uint16_t joynum = get_joystick_number(fd);
307 joystick_names[joynum] = namebuffer;
308 window::out() << "Found '" << namebuffer << "' (" << button_count << " buttons, " << axis_count
309 << " axes, " << hat_count << " hats)" << std::endl;
310 joysticks.insert(fd);
311 return true;
314 void open_and_probe(const std::string& filename)
316 int r = open(filename.c_str(), O_RDONLY | O_NONBLOCK);
317 if(r < 0) {
318 return;
320 if(!probe_joystick(r, filename)) {
321 close(r);
323 return;
326 void probe_all_joysticks()
328 DIR* d = opendir("/dev/input");
329 struct dirent* dentry;
330 if(!d) {
331 int merrno = errno;
332 window::out() << "Can't list /dev/input: " << strerror(merrno) << std::endl;
333 return;
335 while((dentry = readdir(d)) != NULL) {
336 if(strlen(dentry->d_name) < 6)
337 continue;
338 if(strncmp(dentry->d_name, "event", 5))
339 continue;
340 for(size_t i = 5; dentry->d_name[i]; i++)
341 if(!isdigit(static_cast<uint8_t>(dentry->d_name[i])))
342 continue;
343 open_and_probe(std::string("/dev/input/") + dentry->d_name);
345 closedir(d);
348 std::string get_button_name(uint16_t code)
350 if(code <= KEY_MAX && buttonnames[code])
351 return buttonnames[code];
352 else {
353 std::ostringstream str;
354 str << "Unknown button #" << code << std::endl;
355 return str.str();
359 std::string get_axis_name(uint16_t code)
361 if(code <= ABS_MAX && axisnames[code])
362 return axisnames[code];
363 else {
364 std::ostringstream str;
365 str << "Unknown axis #" << code << std::endl;
366 return str.str();
370 function_ptr_command<> show_joysticks("show-joysticks", "Show joysticks",
371 "Syntax: show-joysticks\nShow joystick data.\n",
372 []() throw(std::bad_alloc, std::runtime_error) {
373 for(auto i : joystick_names) {
374 window::out() << "Joystick #" << i.first << ": " << i.second << std::endl;
375 for(auto j : event_map) {
376 if(j.second.joystick != i.first)
377 continue;
378 if(j.second.type == ET_BUTTON)
379 window::out() << j.second.group->name() << ": "
380 << get_button_name(j.second.tevcode & 0xFFFF) << std::endl;
381 if(j.second.type == ET_AXIS)
382 window::out() << j.second.group->name() << ": "
383 << get_axis_name(j.second.tevcode & 0xFFFF)
384 << "[" << j.second.axis_min << "," << j.second.axis_max
385 << "]" << std::endl;
386 if(j.second.type == ET_HAT_X || j.second.type == ET_HAT_Y)
387 window::out() << j.second.group->name() << ": "
388 << get_axis_name(j.second.tevcode & 0xFFFF) << std::endl;
394 void window::poll_joysticks()
396 for(int fd : joysticks) {
397 while(read_one_input_event(fd));
401 extern void evdev_init_buttons(const char** x);
402 extern void evdev_init_axes(const char** x);
404 void joystick_init()
406 probe_all_joysticks();
407 evdev_init_buttons(buttonnames);
408 evdev_init_axes(axisnames);
411 void joystick_quit()
413 for(int fd : joysticks)
414 close(fd);
415 for(auto i : keygroups)
416 delete i;
417 keygroups.clear();
418 joystick_map.clear();
419 joysticks.clear();
420 joystick_names.clear();
421 std::map<uint64_t, struct event_mapping> event_map;
422 std::map<int, uint16_t> joystick_map;
423 std::set<int> joysticks;
424 std::map<uint16_t, std::string> joystick_names;
428 const char* joystick_plugin_name = "Evdev joystick plugin";