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 int 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
))
180 return -1; //Disconnected.
181 messages
<< "Error reading from joystick (fd=" << fd
<< "): " << strerror(errno
)
185 if(ev
.type
== EV_KEY
)
186 lsnes_gamepads
[gamepad_map
[fd
]].report_button(ev
.code
, ev
.value
!= 0);
187 if(ev
.type
== EV_ABS
)
188 lsnes_gamepads
[gamepad_map
[fd
]].report_axis(ev
.code
, ev
.value
);
192 bool probe_joystick(int fd
, const std::string
& filename
)
194 const size_t div
= 8 * sizeof(unsigned long);
195 unsigned long keys
[(KEY_MAX
+ div
) / div
] = {0};
196 unsigned long axes
[(ABS_MAX
+ div
) / div
] = {0};
197 unsigned long evtypes
[(EV_MAX
+ div
) / div
] = {0};
198 char namebuffer
[256];
199 if(ioctl(fd
, EVIOCGBIT(0, sizeof(evtypes
)), evtypes
) < 0) {
201 messages
<< "Error probing joystick (evmap; " << filename
<< "): " << strerror(merrno
)
205 if(!(evtypes
[EV_KEY
/ div
] & (1 << EV_KEY
% div
)) || !(evtypes
[EV_ABS
/ div
] & (1 << EV_ABS
% div
))) {
206 messages
<< "Input (" << filename
<< ") doesn't look like joystick" << std::endl
;
209 if(ioctl(fd
, EVIOCGBIT(EV_KEY
, sizeof(keys
)), keys
) < 0) {
211 messages
<< "Error probing joystick (keymap; " <<filename
<< "): " << strerror(merrno
)
215 if(ioctl(fd
, EVIOCGBIT(EV_ABS
, sizeof(axes
)), axes
) < 0) {
217 messages
<< "Error probing joystick (axismap; " << filename
<< "): " << strerror(merrno
)
221 if(ioctl(fd
, EVIOCGNAME(sizeof(namebuffer
)), namebuffer
) <= 0) {
223 messages
<< "Error probing joystick (name; " << filename
<< "): " << strerror(merrno
)
227 unsigned jid
= gamepad_map
[fd
] = lsnes_gamepads
.add(namebuffer
);
228 gamepad::pad
& ngp
= lsnes_gamepads
[jid
];
229 for(unsigned i
= 0; i
<= KEY_MAX
; i
++)
230 if(keys
[i
/ div
] & (1ULL << (i
% div
)))
231 ngp
.add_button(i
, buttonnames
[i
]);
232 for(unsigned i
= 0; i
<= ABS_MAX
; i
++)
233 if(axes
[i
/ div
] & (1ULL << (i
% div
))) {
234 if(i
< ABS_HAT0X
|| i
> ABS_HAT3Y
) {
236 if(ioctl(fd
, EVIOCGABS(i
), V
) < 0) {
238 messages
<< "Error getting parameters for axis " << i
<< " (fd="
239 << fd
<< "): " << strerror(merrno
) << std::endl
;
242 ngp
.add_axis(i
, V
[1], V
[2], V
[1] == 0, axisnames
[i
]);
243 } else if(i
% 2 == 0)
244 ngp
.add_hat(i
, i
+ 1, 1, axisnames
[i
], axisnames
[i
+ 1]);
246 messages
<< "Joystick #" << jid
<< " online: " << namebuffer
<< std::endl
;
250 void probe_all_joysticks()
252 DIR* d
= opendir("/dev/input");
253 struct dirent
* dentry
;
256 messages
<< "Can't list /dev/input: " << strerror(merrno
) << std::endl
;
259 while((dentry
= readdir(d
)) != NULL
) {
260 if(strlen(dentry
->d_name
) < 6)
262 if(strncmp(dentry
->d_name
, "event", 5))
264 for(size_t i
= 5; dentry
->d_name
[i
]; i
++)
265 if(!isdigit(static_cast<uint8_t>(dentry
->d_name
[i
])))
267 std::string filename
= std::string("/dev/input/") + dentry
->d_name
;
268 int r
= open(filename
.c_str(), O_RDONLY
| O_NONBLOCK
);
271 if(!probe_joystick(r
, filename
))
276 volatile bool quit_signaled
= false;
277 volatile bool quit_ack
= false;
279 #define POLL_WAIT 50000
281 void do_fd_zero(fd_set
& s
)
286 struct _joystick_driver drv
= {
287 .init
= []() -> void {
288 quit_signaled
= false;
290 probe_all_joysticks();
291 quit_ack
= quit_signaled
= false;
293 .quit
= []() -> void {
294 quit_signaled
= true;
297 .thread_fn
= []() -> void {
298 while(!quit_signaled
) {
302 for(auto fd
: gamepad_map
) {
303 limit
= max(limit
, fd
.first
+ 1);
304 FD_SET(fd
.first
, &rfds
);
312 tv
.tv_usec
= POLL_WAIT
;
313 int r
= select(limit
, &rfds
, NULL
, NULL
, &tv
);
316 std::set
<int> cleanup
;
317 for(auto fd
: gamepad_map
)
318 if(FD_ISSET(fd
.first
, &rfds
)) {
320 int r
= read_one_input_event(fd
.first
);
324 cleanup
.insert(fd
.first
);
329 for(auto i
: cleanup
) {
330 unsigned jid
= gamepad_map
[i
];
332 gamepad_map
.erase(i
);
333 lsnes_gamepads
[jid
].set_online(false);
334 messages
<< "Gamepad #" << jid
<< "[" << lsnes_gamepads
[jid
].name()
335 << "] disconnected." << std::endl
;
338 //Get rid of joystick handles.
339 for(auto fd
: gamepad_map
) {
341 lsnes_gamepads
[fd
.second
].set_online(false);
347 .signal
= []() -> void {
348 quit_signaled
= true;
351 .name
= []() -> const char* { return "Evdev joystick plugin"; }
353 struct joystick_driver
_drv(drv
);