28 #include <QCoreApplication>
30 #include <QKeySequence>
31 #include <QTextStream>
32 #include <QStringList>
39 #include <sys/types.h>
44 #include <linux/joystick.h>
47 #include "libmythbase/mythconfig.h"
57 #define LOC QString("JoystickMenuThread: ")
95 LOG(VB_GENERAL, LOG_ERR,
LOC +
96 QString(
"Joystick disabled - Failed to open device %1")
110 LOG(VB_GENERAL, LOG_ERR,
LOC +
111 "Joystick disabled - ioctl JSIOCGAXES failed");
118 LOG(VB_GENERAL, LOG_ERR,
LOC +
119 "Joystick disabled - ioctl JSIOCGBUTTONS failed");
123 LOG(VB_GENERAL, LOG_INFO,
LOC +
124 QString(
"Controller has %1 axes and %2 buttons")
136 LOG(VB_GENERAL, LOG_INFO,
LOC +
137 QString(
"Initialization of %1 succeeded using config file %2")
160 LOG(VB_GENERAL, LOG_INFO,
"No joystick configuration found, not enabling joystick control");
164 FILE *fp = fopen(qPrintable(config_file),
"r");
167 LOG(VB_GENERAL, LOG_ERR,
LOC +
168 QString(
"Joystick disabled - Failed to open %1") .arg(config_file));
174 QTextStream istream(fp);
175 for (
int line = 1; ! istream.atEnd(); line++)
177 QString rawline = istream.readLine();
178 QString simple_line = rawline.simplified();
179 if (simple_line.isEmpty() || simple_line.startsWith(
'#'))
182 QStringList tokens = simple_line.split(
" ");
183 if (tokens.count() < 1)
186 QString firstTok = tokens[0].toLower();
188 if (firstTok.startsWith(
"devicename") && tokens.count() == 2)
192 else if (firstTok.startsWith(
"button") && tokens.count() == 3)
196 else if (firstTok.startsWith(
"axis") && tokens.count() == 5)
199 tokens[3].toInt(), tokens[4]);
201 else if (firstTok.startsWith(
"chord") && tokens.count() == 4)
207 LOG(VB_GENERAL, LOG_WARNING,
LOC +
208 QString(
"ReadConfig(%1) unrecognized or malformed line \"%2\" ")
209 .arg(line) .arg(rawline));
227 struct js_event js {};
235 LOG(VB_GENERAL, LOG_INFO,
LOC +
236 QString(
"Joystick error, Awaiting Reconnection"));
237 struct udev *udev = udev_new();
239 struct udev_monitor *mon =
240 udev_monitor_new_from_netlink(udev,
"udev");
241 udev_monitor_filter_add_match_subsystem_devtype(mon,
"input",
nullptr);
242 udev_monitor_enable_receiving(mon);
245 int fd = udev_monitor_get_fd(mon);
261 struct timeval tv {};
266 int ret = select(fd+1, &fds,
nullptr,
nullptr, &tv);
268 if (ret > 0 && FD_ISSET(fd, &fds))
270 struct udev_device *dev = udev_monitor_receive_device(mon);
274 udev_device_unref(dev);
280 udev_monitor_unref(mon);
290 FD_SET(
m_fd, &readfds);
296 int rc = select(
m_fd + 1, &readfds,
nullptr,
nullptr, &
timeout);
303 LOG(VB_GENERAL, LOG_ERR,
"select: " +
ENO);
318 if (rc !=
sizeof(js))
320 LOG(VB_GENERAL, LOG_ERR,
"error reading js:" +
ENO);
334 if (js.type & JS_EVENT_INIT)
339 if (js.type & JS_EVENT_AXIS && js.number <
m_axesCount)
340 m_axes[js.number] = js.value;
357 if (js.value == 0 &&
m_buttons[js.number] == 1)
363 if (js.type & JS_EVENT_AXIS && js.number <
m_axesCount)
366 m_axes[js.number] = js.value;
383 QKeySequence a(code);
385 int key { QKeySequence::UnknownKey };
386 Qt::KeyboardModifiers modifiers { Qt::NoModifier };
393 key, Qt::NoModifier, QEvent::KeyPress));
395 for (
int i = 0; i < a.count(); i++)
397 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
398 key = a[i] & ~(Qt::MODIFIER_MASK);
399 modifiers =
static_cast<Qt::KeyboardModifiers
>(a[i] & Qt::MODIFIER_MASK);
402 modifiers = a[i].keyboardModifiers();
406 key, modifiers, QEvent::KeyPress));
408 key, modifiers, QEvent::KeyRelease));
424 JoystickMap::button_map_t::const_iterator bmap;
428 if (button == bmap->button && bmap->chord != -1
443 if (button == bmap->button && bmap->chord == -1)
453 JoystickMap::axis_map_t::const_iterator amap;
456 if (axis == amap->axis)
460 if (
m_axes[axis] < amap->from ||
m_axes[axis] > amap->to)
461 if (value >= amap->from && value <= amap->to)