1 #include "core/command.hpp"
2 #include "core/joystickapi.hpp"
3 #include "core/keymapper.hpp"
4 #include "core/messages.hpp"
5 #include "library/minmax.hpp"
6 #include "library/string.hpp"
21 #include <linux/input.h>
26 const char* axisnames
[64] = {
27 "X", "Y", "Z", "RX", "RY", "RZ", "THROTTLE", "RUDDER", "WHEEL", "GAS", "BRAKE", "Unknown axis #11",
28 "Unknown axis #12", "Unknown axis #13", "Unknown axis #14", "Unknown axis #15", "HAT0X", "HAT0Y",
29 "HAT1X", "HAT1Y", "HAT2X", "HAT2Y", "HAT3X", "HAT3Y", "PRESSURE", "DISTANCE", "TILT_X", "TILT_Y",
30 "TOOL_WIDTH", "Unknown axis #29", "Unknown axis #30", "Unknown axis #31", "VOLUME", "Unknown axis #33",
31 "Unknown axis #34", "Unknown axis #35", "Unknown axis #36", "Unknown axis #37", "Unknown axis #38",
32 "Unknown axis #39", "MISC", "Unknown axis #41", "Unknown axis #42", "Unknown axis #43",
33 "Unknown axis #44", "Unknown axis #45", "Unknown axis #46", "MT_SLOT", "MT_TOUCH_MAJOR",
34 "MT_TOUCH_MINOR", "MT_WIDTH_MAJOR", "MT_WIDTH_MINOR", "MT_ORIENTATION", "MT_POSITION_X",
35 "MT_POSITION_Y", "MT_TOOL_TYPE", "MT_BLOB_ID", "MT_TRACKING_ID", "MT_PRESSURE", "MT_DISTANCE",
36 "Unknown axis #60", "Unknown axis #61", "Unknown axis #62", "Unknown axis #63"
38 const char* buttonnames
[768] = {
39 "RESERVED", "ESC", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "MINUS", "EQUAL", "BACKSPACE",
40 "TAB", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "LEFTBRACE", "RIGHTBRACE", "ENTER",
41 "LEFTCTRL", "A", "S", "D", "F", "G", "H", "J", "K", "L", "SEMICOLON", "APOSTROPHE", "GRAVE",
42 "LEFTSHIFT", "BACKSLASH", "Z", "X", "C", "V", "B", "N", "M", "COMMA", "DOT", "SLASH", "RIGHTSHIFT",
43 "KPASTERISK", "LEFTALT", "SPACE", "CAPSLOCK", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9",
44 "F10", "NUMLOCK", "SCROLLLOCK", "KP7", "KP8", "KP9", "KPMINUS", "KP4", "KP5", "KP6", "KPPLUS", "KP1",
45 "KP2", "KP3", "KP0", "KPDOT", "Unknown button #84", "ZENKAKUHANKAKU", "102ND", "F11", "F12", "RO",
46 "KATAKANA", "HIRAGANA", "HENKAN", "KATAKANAHIRAGANA", "MUHENKAN", "KPJPCOMMA", "KPENTER", "RIGHTCTRL",
47 "KPSLASH", "SYSRQ", "RIGHTALT", "LINEFEED", "HOME", "UP", "PAGEUP", "LEFT", "RIGHT", "END", "DOWN",
48 "PAGEDOWN", "INSERT", "DELETE", "MACRO", "MUTE", "VOLUMEDOWN", "VOLUMEUP", "POWER", "KPEQUAL",
49 "KPPLUSMINUS", "PAUSE", "SCALE", "KPCOMMA", "HANGUEL", "HANJA", "YEN", "LEFTMETA", "RIGHTMETA",
50 "COMPOSE", "STOP", "AGAIN", "PROPS", "UNDO", "FRONT", "COPY", "OPEN", "PASTE", "FIND", "CUT", "HELP",
51 "MENU", "CALC", "SETUP", "SLEEP", "WAKEUP", "FILE", "SENDFILE", "DELETEFILE", "XFER", "PROG1", "PROG2",
52 "WWW", "MSDOS", "SCREENLOCK", "DIRECTION", "CYCLEWINDOWS", "MAIL", "BOOKMARKS", "COMPUTER", "BACK",
53 "FORWARD", "CLOSECD", "EJECTCD", "EJECTCLOSECD", "NEXTSONG", "PLAYPAUSE", "PREVIOUSSONG", "STOPCD",
54 "RECORD", "REWIND", "PHONE", "ISO", "CONFIG", "HOMEPAGE", "REFRESH", "EXIT", "MOVE", "EDIT",
55 "SCROLLUP", "SCROLLDOWN", "KPLEFTPAREN", "KPRIGHTPAREN", "NEW", "REDO", "F13", "F14", "F15", "F16",
56 "F17", "F18", "F19", "F20", "F21", "F22", "F23", "F24", "Unknown button #195", "Unknown button #196",
57 "Unknown button #197", "Unknown button #198", "Unknown button #199", "PLAYCD", "PAUSECD", "PROG3",
58 "PROG4", "DASHBOARD", "SUSPEND", "CLOSE", "PLAY", "FASTFORWARD", "BASSBOOST", "PRINT", "HP", "CAMERA",
59 "SOUND", "QUESTION", "EMAIL", "CHAT", "SEARCH", "CONNECT", "FINANCE", "SPORT", "SHOP", "ALTERASE",
60 "CANCEL", "BRIGHTNESSDOWN", "BRIGHTNESSUP", "MEDIA", "SWITCHVIDEOMODE", "KBDILLUMTOGGLE",
61 "KBDILLUMDOWN", "KBDILLUMUP", "SEND", "REPLY", "FORWARDMAIL", "SAVE", "DOCUMENTS", "BATTERY",
62 "BLUETOOTH", "WLAN", "UWB", "UNKNOWN", "VIDEO_NEXT", "VIDEO_PREV", "BRIGHTNESS_CYCLE",
63 "BRIGHTNESS_ZERO", "DISPLAY_OFF", "WIMAX", "RFKILL", "MICMUTE", "Unknown button #249",
64 "Unknown button #250", "Unknown button #251", "Unknown button #252", "Unknown button #253",
65 "Unknown button #254", "Unknown button #255", "Button 0", "Button 1", "Button 2", "Button 3",
66 "Button 4", "Button 5", "Button 6", "Button 7", "Button 8", "Button 9", "Unknown button #266",
67 "Unknown button #267", "Unknown button #268", "Unknown button #269", "Unknown button #270",
68 "Unknown button #271", "Button LEFT", "Button RIGHT", "Button MIDDLE", "Button SIDE", "Button EXTRA",
69 "Button FORWARD", "Button BACK", "Button TASK", "Unknown button #280", "Unknown button #281",
70 "Unknown button #282", "Unknown button #283", "Unknown button #284", "Unknown button #285",
71 "Unknown button #286", "Unknown button #287", "Button TRIGGER", "Button THUMB", "Button THUMB2",
72 "Button TOP", "Button TOP2", "Button PINKIE", "Button BASE", "Button BASE2", "Button BASE3",
73 "Button BASE4", "Button BASE5", "Button BASE6", "Unknown button #300", "Unknown button #301",
74 "Unknown button #302", "Button DEAD", "Button A", "Button B", "Button C", "Button X", "Button Y",
75 "Button Z", "Button TL", "Button TR", "Button TL2", "Button TR2", "Button SELECT", "Button START",
76 "Button MODE", "Button THUMBL", "Button THUMBR", "Unknown button #319", "Button TOOL_PEN",
77 "Button TOOL_RUBBER", "Button TOOL_BRUSH", "Button TOOL_PENCIL", "Button TOOL_AIRBRUSH",
78 "Button TOOL_FINGER", "Button TOOL_MOUSE", "Button TOOL_LENS", "Button TOOL_QUINTTAP",
79 "Unknown button #329", "Button TOUCH", "Button STYLUS", "Button STYLUS2", "Button TOOL_DOUBLETAP",
80 "Button TOOL_TRIPLETAP", "Button TOOL_QUADTAP", "Button GEAR_DOWN", "Button GEAR_UP",
81 "Unknown button #338", "Unknown button #339", "Unknown button #340", "Unknown button #341",
82 "Unknown button #342", "Unknown button #343", "Unknown button #344", "Unknown button #345",
83 "Unknown button #346", "Unknown button #347", "Unknown button #348", "Unknown button #349",
84 "Unknown button #350", "Unknown button #351", "OK", "SELECT", "GOTO", "CLEAR", "POWER2", "OPTION",
85 "INFO", "TIME", "VENDOR", "ARCHIVE", "PROGRAM", "CHANNEL", "FAVORITES", "EPG", "PVR", "MHP",
86 "LANGUAGE", "TITLE", "SUBTITLE", "ANGLE", "ZOOM", "MODE", "KEYBOARD", "SCREEN", "PC", "TV", "TV2",
87 "VCR", "VCR2", "SAT", "SAT2", "CD", "TAPE", "RADIO", "TUNER", "PLAYER", "TEXT", "DVD", "AUX", "MP3",
88 "AUDIO", "VIDEO", "DIRECTORY", "LIST", "MEMO", "CALENDAR", "RED", "GREEN", "YELLOW", "BLUE",
89 "CHANNELUP", "CHANNELDOWN", "FIRST", "LAST", "AB", "NEXT", "RESTART", "SLOW", "SHUFFLE", "BREAK",
90 "PREVIOUS", "DIGITS", "TEEN", "TWEN", "VIDEOPHONE", "GAMES", "ZOOMIN", "ZOOMOUT", "ZOOMRESET",
91 "WORDPROCESSOR", "EDITOR", "SPREADSHEET", "GRAPHICSEDITOR", "PRESENTATION", "DATABASE", "NEWS",
92 "VOICEMAIL", "ADDRESSBOOK", "MESSENGER", "DISPLAYTOGGLE", "SPELLCHECK", "LOGOFF", "DOLLAR", "EURO",
93 "FRAMEBACK", "FRAMEFORWARD", "CONTEXT_MENU", "MEDIA_REPEAT", "10CHANNELSUP", "10CHANNELSDOWN",
94 "IMAGES", "Unknown button #443", "Unknown button #444", "Unknown button #445", "Unknown button #446",
95 "Unknown button #447", "DEL_EOL", "DEL_EOS", "INS_LINE", "DEL_LINE", "Unknown button #452",
96 "Unknown button #453", "Unknown button #454", "Unknown button #455", "Unknown button #456",
97 "Unknown button #457", "Unknown button #458", "Unknown button #459", "Unknown button #460",
98 "Unknown button #461", "Unknown button #462", "Unknown button #463", "FN", "FN_ESC", "FN_F1", "FN_F2",
99 "FN_F3", "FN_F4", "FN_F5", "FN_F6", "FN_F7", "FN_F8", "FN_F9", "FN_F10", "FN_F11", "FN_F12", "FN_1",
100 "FN_2", "FN_D", "FN_E", "FN_F", "FN_S", "FN_B", "Unknown button #485", "Unknown button #486",
101 "Unknown button #487", "Unknown button #488", "Unknown button #489", "Unknown button #490",
102 "Unknown button #491", "Unknown button #492", "Unknown button #493", "Unknown button #494",
103 "Unknown button #495", "Unknown button #496", "BRL_DOT1", "BRL_DOT2", "BRL_DOT3", "BRL_DOT4",
104 "BRL_DOT5", "BRL_DOT6", "BRL_DOT7", "BRL_DOT8", "BRL_DOT9", "BRL_DOT10", "Unknown button #507",
105 "Unknown button #508", "Unknown button #509", "Unknown button #510", "Unknown button #511",
106 "NUMERIC_0", "NUMERIC_1", "NUMERIC_2", "NUMERIC_3", "NUMERIC_4", "NUMERIC_5", "NUMERIC_6", "NUMERIC_7",
107 "NUMERIC_8", "NUMERIC_9", "NUMERIC_STAR", "NUMERIC_POUND", "Unknown button #524",
108 "Unknown button #525", "Unknown button #526", "Unknown button #527", "CAMERA_FOCUS", "WPS_BUTTON",
109 "TOUCHPAD_TOGGLE", "TOUCHPAD_ON", "TOUCHPAD_OFF", "CAMERA_ZOOMIN", "CAMERA_ZOOMOUT", "CAMERA_UP",
110 "CAMERA_DOWN", "CAMERA_LEFT", "CAMERA_RIGHT", "Unknown button #539", "Unknown button #540",
111 "Unknown button #541", "Unknown button #542", "Unknown button #543", "Unknown button #544",
112 "Unknown button #545", "Unknown button #546", "Unknown button #547", "Unknown button #548",
113 "Unknown button #549", "Unknown button #550", "Unknown button #551", "Unknown button #552",
114 "Unknown button #553", "Unknown button #554", "Unknown button #555", "Unknown button #556",
115 "Unknown button #557", "Unknown button #558", "Unknown button #559", "Unknown button #560",
116 "Unknown button #561", "Unknown button #562", "Unknown button #563", "Unknown button #564",
117 "Unknown button #565", "Unknown button #566", "Unknown button #567", "Unknown button #568",
118 "Unknown button #569", "Unknown button #570", "Unknown button #571", "Unknown button #572",
119 "Unknown button #573", "Unknown button #574", "Unknown button #575", "Unknown button #576",
120 "Unknown button #577", "Unknown button #578", "Unknown button #579", "Unknown button #580",
121 "Unknown button #581", "Unknown button #582", "Unknown button #583", "Unknown button #584",
122 "Unknown button #585", "Unknown button #586", "Unknown button #587", "Unknown button #588",
123 "Unknown button #589", "Unknown button #590", "Unknown button #591", "Unknown button #592",
124 "Unknown button #593", "Unknown button #594", "Unknown button #595", "Unknown button #596",
125 "Unknown button #597", "Unknown button #598", "Unknown button #599", "Unknown button #600",
126 "Unknown button #601", "Unknown button #602", "Unknown button #603", "Unknown button #604",
127 "Unknown button #605", "Unknown button #606", "Unknown button #607", "Unknown button #608",
128 "Unknown button #609", "Unknown button #610", "Unknown button #611", "Unknown button #612",
129 "Unknown button #613", "Unknown button #614", "Unknown button #615", "Unknown button #616",
130 "Unknown button #617", "Unknown button #618", "Unknown button #619", "Unknown button #620",
131 "Unknown button #621", "Unknown button #622", "Unknown button #623", "Unknown button #624",
132 "Unknown button #625", "Unknown button #626", "Unknown button #627", "Unknown button #628",
133 "Unknown button #629", "Unknown button #630", "Unknown button #631", "Unknown button #632",
134 "Unknown button #633", "Unknown button #634", "Unknown button #635", "Unknown button #636",
135 "Unknown button #637", "Unknown button #638", "Unknown button #639", "Unknown button #640",
136 "Unknown button #641", "Unknown button #642", "Unknown button #643", "Unknown button #644",
137 "Unknown button #645", "Unknown button #646", "Unknown button #647", "Unknown button #648",
138 "Unknown button #649", "Unknown button #650", "Unknown button #651", "Unknown button #652",
139 "Unknown button #653", "Unknown button #654", "Unknown button #655", "Unknown button #656",
140 "Unknown button #657", "Unknown button #658", "Unknown button #659", "Unknown button #660",
141 "Unknown button #661", "Unknown button #662", "Unknown button #663", "Unknown button #664",
142 "Unknown button #665", "Unknown button #666", "Unknown button #667", "Unknown button #668",
143 "Unknown button #669", "Unknown button #670", "Unknown button #671", "Unknown button #672",
144 "Unknown button #673", "Unknown button #674", "Unknown button #675", "Unknown button #676",
145 "Unknown button #677", "Unknown button #678", "Unknown button #679", "Unknown button #680",
146 "Unknown button #681", "Unknown button #682", "Unknown button #683", "Unknown button #684",
147 "Unknown button #685", "Unknown button #686", "Unknown button #687", "Unknown button #688",
148 "Unknown button #689", "Unknown button #690", "Unknown button #691", "Unknown button #692",
149 "Unknown button #693", "Unknown button #694", "Unknown button #695", "Unknown button #696",
150 "Unknown button #697", "Unknown button #698", "Unknown button #699", "Unknown button #700",
151 "Unknown button #701", "Unknown button #702", "Unknown button #703", "Button TRIGGER_HAPPY1",
152 "Button TRIGGER_HAPPY2", "Button TRIGGER_HAPPY3", "Button TRIGGER_HAPPY4", "Button TRIGGER_HAPPY5",
153 "Button TRIGGER_HAPPY6", "Button TRIGGER_HAPPY7", "Button TRIGGER_HAPPY8", "Button TRIGGER_HAPPY9",
154 "Button TRIGGER_HAPPY10", "Button TRIGGER_HAPPY11", "Button TRIGGER_HAPPY12", "Button TRIGGER_HAPPY13",
155 "Button TRIGGER_HAPPY14", "Button TRIGGER_HAPPY15", "Button TRIGGER_HAPPY16", "Button TRIGGER_HAPPY17",
156 "Button TRIGGER_HAPPY18", "Button TRIGGER_HAPPY19", "Button TRIGGER_HAPPY20", "Button TRIGGER_HAPPY21",
157 "Button TRIGGER_HAPPY22", "Button TRIGGER_HAPPY23", "Button TRIGGER_HAPPY24", "Button TRIGGER_HAPPY25",
158 "Button TRIGGER_HAPPY26", "Button TRIGGER_HAPPY27", "Button TRIGGER_HAPPY28", "Button TRIGGER_HAPPY29",
159 "Button TRIGGER_HAPPY30", "Button TRIGGER_HAPPY31", "Button TRIGGER_HAPPY32", "Button TRIGGER_HAPPY33",
160 "Button TRIGGER_HAPPY34", "Button TRIGGER_HAPPY35", "Button TRIGGER_HAPPY36", "Button TRIGGER_HAPPY37",
161 "Button TRIGGER_HAPPY38", "Button TRIGGER_HAPPY39", "Button TRIGGER_HAPPY40", "Unknown button #744",
162 "Unknown button #745", "Unknown button #746", "Unknown button #747", "Unknown button #748",
163 "Unknown button #749", "Unknown button #750", "Unknown button #751", "Unknown button #752",
164 "Unknown button #753", "Unknown button #754", "Unknown button #755", "Unknown button #756",
165 "Unknown button #757", "Unknown button #758", "Unknown button #759", "Unknown button #760",
166 "Unknown button #761", "Unknown button #762", "Unknown button #763", "Unknown button #764",
167 "Unknown button #765", "Unknown button #766", "Unknown button #767"
170 std::map
<int, unsigned> gamepad_map
;
172 bool read_one_input_event(int fd
)
174 struct input_event ev
;
175 int r
= read(fd
, &ev
, sizeof(ev
));
176 if(r
< 0 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
))
179 messages
<< "Error reading from joystick (fd=" << fd
<< "): " << strerror(errno
)
183 if(ev
.type
== EV_KEY
)
184 lsnes_gamepads
[gamepad_map
[fd
]].report_button(ev
.code
, ev
.value
!= 0);
185 if(ev
.type
== EV_ABS
)
186 lsnes_gamepads
[gamepad_map
[fd
]].report_axis(ev
.code
, ev
.value
);
190 bool probe_joystick(int fd
, const std::string
& filename
)
192 const size_t div
= 8 * sizeof(unsigned long);
193 unsigned long keys
[(KEY_MAX
+ div
) / div
] = {0};
194 unsigned long axes
[(ABS_MAX
+ div
) / div
] = {0};
195 unsigned long evtypes
[(EV_MAX
+ div
) / div
] = {0};
196 char namebuffer
[256];
197 if(ioctl(fd
, EVIOCGBIT(0, sizeof(evtypes
)), evtypes
) < 0) {
199 messages
<< "Error probing joystick (evmap; " << filename
<< "): " << strerror(merrno
)
203 if(!(evtypes
[EV_KEY
/ div
] & (1 << EV_KEY
% div
)) || !(evtypes
[EV_ABS
/ div
] & (1 << EV_ABS
% div
))) {
204 messages
<< "Input (" << filename
<< ") doesn't look like joystick" << std::endl
;
207 if(ioctl(fd
, EVIOCGBIT(EV_KEY
, sizeof(keys
)), keys
) < 0) {
209 messages
<< "Error probing joystick (keymap; " <<filename
<< "): " << strerror(merrno
)
213 if(ioctl(fd
, EVIOCGBIT(EV_ABS
, sizeof(axes
)), axes
) < 0) {
215 messages
<< "Error probing joystick (axismap; " << filename
<< "): " << strerror(merrno
)
219 if(ioctl(fd
, EVIOCGNAME(sizeof(namebuffer
)), namebuffer
) <= 0) {
221 messages
<< "Error probing joystick (name; " << filename
<< "): " << strerror(merrno
)
225 unsigned jid
= gamepad_map
[fd
] = lsnes_gamepads
.add(namebuffer
);
226 gamepad::pad
& ngp
= lsnes_gamepads
[jid
];
227 for(unsigned i
= 0; i
<= KEY_MAX
; i
++)
228 if(keys
[i
/ div
] & (1ULL << (i
% div
)))
229 ngp
.add_button(i
, buttonnames
[i
]);
230 for(unsigned i
= 0; i
<= ABS_MAX
; i
++)
231 if(axes
[i
/ div
] & (1ULL << (i
% div
))) {
232 if(i
< ABS_HAT0X
|| i
> ABS_HAT3Y
) {
234 if(ioctl(fd
, EVIOCGABS(i
), V
) < 0) {
236 messages
<< "Error getting parameters for axis " << i
<< " (fd="
237 << fd
<< "): " << strerror(merrno
) << std::endl
;
240 ngp
.add_axis(i
, V
[1], V
[2], V
[1] == 0, axisnames
[i
]);
241 } else if(i
% 2 == 0)
242 ngp
.add_hat(i
, i
+ 1, 1, axisnames
[i
], axisnames
[i
+ 1]);
244 messages
<< "Joystick #" << jid
<< " online: " << namebuffer
<< std::endl
;
248 void probe_all_joysticks()
250 DIR* d
= opendir("/dev/input");
251 struct dirent
* dentry
;
254 messages
<< "Can't list /dev/input: " << strerror(merrno
) << std::endl
;
257 while((dentry
= readdir(d
)) != NULL
) {
258 if(strlen(dentry
->d_name
) < 6)
260 if(strncmp(dentry
->d_name
, "event", 5))
262 for(size_t i
= 5; dentry
->d_name
[i
]; i
++)
263 if(!isdigit(static_cast<uint8_t>(dentry
->d_name
[i
])))
265 std::string filename
= std::string("/dev/input/") + dentry
->d_name
;
266 int r
= open(filename
.c_str(), O_RDONLY
| O_NONBLOCK
);
269 if(!probe_joystick(r
, filename
))
274 volatile bool quit_signaled
= false;
275 volatile bool quit_ack
= false;
277 #define POLL_WAIT 50000
279 void do_fd_zero(fd_set
& s
)
284 struct _joystick_driver drv
= {
285 .init
= []() -> void {
286 probe_all_joysticks();
287 quit_ack
= quit_signaled
= false;
289 .quit
= []() -> void {
290 quit_signaled
= true;
293 .thread_fn
= []() -> void {
294 while(!quit_signaled
) {
298 for(auto fd
: gamepad_map
) {
299 limit
= max(limit
, fd
.first
+ 1);
300 FD_SET(fd
.first
, &rfds
);
308 tv
.tv_usec
= POLL_WAIT
;
309 int r
= select(limit
, &rfds
, NULL
, NULL
, &tv
);
312 for(auto fd
: gamepad_map
)
313 if(FD_ISSET(fd
.first
, &rfds
))
314 while(read_one_input_event(fd
.first
));
318 .signal
= []() -> void {
319 quit_signaled
= true;
322 .name
= []() -> const char* { return "Evdev joystick plugin"; }
324 struct joystick_driver
_drv(drv
);