28#include <QCoreApplication>
30#include <QKeySequence>
46#include <linux/joystick.h>
49#include "libmythbase/mythconfig.h"
59#define LOC QString("JoystickMenuThread: ")
97 LOG(VB_GENERAL, LOG_ERR,
LOC +
98 QString(
"Joystick disabled - Failed to open device %1")
112 LOG(VB_GENERAL, LOG_ERR,
LOC +
113 "Joystick disabled - ioctl JSIOCGAXES failed");
120 LOG(VB_GENERAL, LOG_ERR,
LOC +
121 "Joystick disabled - ioctl JSIOCGBUTTONS failed");
125 LOG(VB_GENERAL, LOG_INFO,
LOC +
126 QString(
"Controller has %1 axes and %2 buttons")
138 LOG(VB_GENERAL, LOG_INFO,
LOC +
139 QString(
"Initialization of %1 succeeded using config file %2")
162 LOG(VB_GENERAL, LOG_INFO,
"No joystick configuration found, not enabling joystick control");
166 FILE *fp = fopen(qPrintable(config_file),
"r");
169 LOG(VB_GENERAL, LOG_ERR,
LOC +
170 QString(
"Joystick disabled - Failed to open %1") .arg(config_file));
176 QTextStream istream(fp);
177 for (
int line = 1; ! istream.atEnd(); line++)
179 QString rawline = istream.readLine();
180 QString simple_line = rawline.simplified();
181 if (simple_line.isEmpty() || simple_line.startsWith(
'#'))
184 QStringList tokens = simple_line.split(
" ");
185 if (tokens.count() < 1)
188 QString firstTok = tokens[0].toLower();
190 if (firstTok.startsWith(
"devicename") && tokens.count() == 2)
194 else if (firstTok.startsWith(
"button") && tokens.count() == 3)
198 else if (firstTok.startsWith(
"axis") && tokens.count() == 5)
201 tokens[3].toInt(), tokens[4]);
203 else if (firstTok.startsWith(
"chord") && tokens.count() == 4)
209 LOG(VB_GENERAL, LOG_WARNING,
LOC +
210 QString(
"ReadConfig(%1) unrecognized or malformed line \"%2\" ")
211 .arg(line) .arg(rawline));
229 struct js_event js {};
237 LOG(VB_GENERAL, LOG_INFO,
LOC +
238 QString(
"Joystick error, Awaiting Reconnection"));
239 struct udev *udev = udev_new();
241 struct udev_monitor *mon =
242 udev_monitor_new_from_netlink(udev,
"udev");
243 udev_monitor_filter_add_match_subsystem_devtype(mon,
"input",
nullptr);
244 udev_monitor_enable_receiving(mon);
247 int fd = udev_monitor_get_fd(mon);
263 struct timeval tv {};
268 int ret = select(fd+1, &fds,
nullptr,
nullptr, &tv);
270 if (ret > 0 && FD_ISSET(fd, &fds))
272 struct udev_device *dev = udev_monitor_receive_device(mon);
276 udev_device_unref(dev);
279 std::this_thread::sleep_for(250ms);
282 udev_monitor_unref(mon);
292 FD_SET(
m_fd, &readfds);
298 int rc = select(
m_fd + 1, &readfds,
nullptr,
nullptr, &
timeout);
305 LOG(VB_GENERAL, LOG_ERR,
"select: " +
ENO);
320 if (rc !=
sizeof(js))
322 LOG(VB_GENERAL, LOG_ERR,
"error reading js:" +
ENO);
336 if (js.type & JS_EVENT_INIT)
341 if (js.type & JS_EVENT_AXIS && js.number <
m_axesCount)
342 m_axes[js.number] = js.value;
359 if (js.value == 0 &&
m_buttons[js.number] == 1)
365 if (js.type & JS_EVENT_AXIS && js.number <
m_axesCount)
368 m_axes[js.number] = js.value;
385 QKeySequence a(code);
387 int key { QKeySequence::UnknownKey };
388 Qt::KeyboardModifiers modifiers { Qt::NoModifier };
395 key, Qt::NoModifier, QEvent::KeyPress));
397 for (
int i = 0; i < a.count(); i++)
399#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
400 key = a[i] & ~(Qt::MODIFIER_MASK);
401 modifiers =
static_cast<Qt::KeyboardModifiers
>(a[i] & Qt::MODIFIER_MASK);
404 modifiers = a[i].keyboardModifiers();
408 key, modifiers, QEvent::KeyPress));
410 key, modifiers, QEvent::KeyRelease));
426 JoystickMap::button_map_t::const_iterator bmap;
430 if (button == bmap->button && bmap->chord != -1
445 if (button == bmap->button && bmap->chord == -1)
455 JoystickMap::axis_map_t::const_iterator amap;
458 if (axis == amap->axis)
462 if (
m_axes[axis] < amap->from ||
m_axes[axis] > amap->to)
463 if (value >= amap->from && value <= amap->to)
const axis_map_t & axisMap() const
void AddButton(int in_button, QString in_keystr, int in_chord=-1)
const button_map_t & buttonMap() const
void AddAxis(int in_axis, int in_from, int in_to, QString in_keystr)
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
#define ENO
This can be appended to the LOG args with "+".
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
def read(device=None, features=[])