11 #include "keymapper.hpp"
17 #include <linux/input.h>
22 const char* axisnames
[ABS_MAX
+ 1] = {0};
23 const char* buttonnames
[KEY_MAX
+ 1] = {0};
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
];
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;
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();
114 grp
= new keygroup(name
, keygroup::KT_AXIS_PAIR
);
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;
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;
146 evmap1
.current_status
= 0;
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;
155 evmap2
.current_status
= 0;
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
];
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
];
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
);
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
;
198 v
= (e
.current_status
!= 0);
201 v
= -32768 + 65535 * (static_cast<double>(e
.current_status
) - e
.axis_min
) /
202 (static_cast<double>(e
.axis_max
) - e
.axis_min
);
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
;
211 yaxis
= get_ev_id(e
.joystick
, e
.tevcode
);
212 xaxis
= e
.paired_mapping
;
214 if(event_map
[yaxis
].current_status
< 0)
216 if(event_map
[xaxis
].current_status
> 0)
218 if(event_map
[yaxis
].current_status
> 0)
220 if(event_map
[xaxis
].current_status
< 0)
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
))
235 window::out() << "Error reading from joystick (fd=" << fd
<< "): " << strerror(errno
)
239 update_mapping_for_fd(fd
, ev
.type
, ev
.code
, ev
.value
);
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) {
255 window::out() << "Error probing joystick (evmap; " << filename
<< "): " << strerror(merrno
)
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
;
263 if(ioctl(fd
, EVIOCGBIT(EV_KEY
, sizeof(keys
)), keys
) < 0) {
265 window::out() << "Error probing joystick (keymap; " <<filename
<< "): " << strerror(merrno
)
269 if(ioctl(fd
, EVIOCGBIT(EV_ABS
, sizeof(axes
)), axes
) < 0) {
271 window::out() << "Error probing joystick (axismap; " << filename
<< "): " << strerror(merrno
)
275 if(ioctl(fd
, EVIOCGNAME(sizeof(namebuffer
)), namebuffer
) <= 0) {
277 window::out() << "Error probing joystick (name; " << filename
<< "): " << strerror(merrno
)
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
) {
292 if(ioctl(fd
, EVIOCGABS(i
), V
) < 0) {
294 window::out() << "Error getting parameters for axis " << i
<< " (fd="
295 << fd
<< "): " << strerror(merrno
) << std::endl
;
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
);
314 void open_and_probe(const std::string
& filename
)
316 int r
= open(filename
.c_str(), O_RDONLY
| O_NONBLOCK
);
320 if(!probe_joystick(r
, filename
)) {
326 void probe_all_joysticks()
328 DIR* d
= opendir("/dev/input");
329 struct dirent
* dentry
;
332 window::out() << "Can't list /dev/input: " << strerror(merrno
) << std::endl
;
335 while((dentry
= readdir(d
)) != NULL
) {
336 if(strlen(dentry
->d_name
) < 6)
338 if(strncmp(dentry
->d_name
, "event", 5))
340 for(size_t i
= 5; dentry
->d_name
[i
]; i
++)
341 if(!isdigit(static_cast<uint8_t>(dentry
->d_name
[i
])))
343 open_and_probe(std::string("/dev/input/") + dentry
->d_name
);
348 std::string
get_button_name(uint16_t code
)
350 if(code
<= KEY_MAX
&& buttonnames
[code
])
351 return buttonnames
[code
];
353 std::ostringstream str
;
354 str
<< "Unknown button #" << code
<< std::endl
;
359 std::string
get_axis_name(uint16_t code
)
361 if(code
<= ABS_MAX
&& axisnames
[code
])
362 return axisnames
[code
];
364 std::ostringstream str
;
365 str
<< "Unknown axis #" << code
<< std::endl
;
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
)
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
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
);
406 probe_all_joysticks();
407 evdev_init_buttons(buttonnames
);
408 evdev_init_axes(axisnames
);
413 for(int fd
: joysticks
)
415 for(auto i
: keygroups
)
418 joystick_map
.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";