2
* Copyright © 2012 Matt Pharoah (mr.exuberant@gmail.com)
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation, either version 3 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program. If not, see <http://www.gnu.org/licenses/>.
27
#include <linux/joystick.h>
28
#include <sys/ioctl.h>
29
#include <sys/select.h>
38
unsigned int timestamp;
53
volatile bool connected;
57
static void start(void (*listener)(const JSEvent&, void *), void (*onDisconnect)(void *), Joystick *me, void *userdata) {
59
const struct timespec DECISECOND = { 0, 100000000 };
60
chrono::milliseconds deciSecond(100);
63
while (!me->connected) {
64
if (!me->alive) return;
65
this_thread::sleep_for(deciSecond);
71
while (status == 0 && me->device >= 0) {
73
FD_SET(me->device, &dset);
74
status = pselect(me->device + 1, &dset, NULL, NULL, &DECISECOND, NULL);
75
if (!me->alive) return;
78
if (status > 0 && errno == 0 && me->device >= 0) {
79
if (read(me->device, (void *) &ev, sizeof(JSEvent)) == sizeof(JSEvent)) listener(ev, userdata);
80
} else if (onDisconnect != NULL) {
81
onDisconnect(userdata);
83
//default implementation of disconnect: wait a decisecond and try to reconnect
84
this_thread::sleep_for(deciSecond);
92
static const char BUTTON_EVENT = 1;
93
static const char AXIS_EVENT = 2;
95
static const short PRESSED = 1;
96
static const short RELEASED = 0;
98
Joystick(unsigned char num, void (*listener)(const JSEvent&, void *), void (*onDisconnect)(void *) = NULL, void *userdata = NULL) {
99
if (num > 9) throw invalid_argument("Invalid joystick number. Valid range is [0,9]\n");
102
strcpy(filename, "/dev/input/js?");
103
filename[13] = (char) (48 + num);
104
device = open(filename, O_RDONLY);
105
driver = new thread(start, listener, onDisconnect, this, userdata);
109
* NOTE: it is expected that reconnect() will be called from the same
110
* thread that onDisconnect() is called from (the joystick thread).
111
* Otherwise, errno will not be cleared since it is thread-specific
116
device = open(filename, O_RDONLY);
120
inline unsigned char getPort() {
121
return ((unsigned char) filename[13] - 48);
131
static void getNameAndButtons(unsigned char num, char *str, unsigned int string_size, unsigned char *buttons = NULL) {
132
if (num > 9) throw invalid_argument("Invalid joystick number. Valid range is [0,9]\n");
135
strcpy(fileName, "/dev/input/js?");
136
fileName[13] = (char) (48 + num);
137
int fd = open(fileName, O_RDONLY);
138
if (fd == -1) throw invalid_argument("Joystick not connected on this port.\n");
140
if (ioctl(fd, JSIOCGNAME(string_size), str) < 0) strcpy(str, "Unknown Device");
142
if (buttons != NULL) {
143
if (ioctl(fd, JSIOCGBUTTONS, buttons) < 0) *buttons = 8; //if the number of buttons can't be read for whatever reason, default to 8
151
#endif /* JOYSTICK_HH_ */