00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "jsmenu.h"
00026
00027
00028 #include <QCoreApplication>
00029 #include <QEvent>
00030 #include <QKeySequence>
00031 #include <QTextStream>
00032 #include <QStringList>
00033
00034
00035 #include <cstdio>
00036 #include <cerrno>
00037 #include <sys/wait.h>
00038 #include <sys/types.h>
00039 #include <unistd.h>
00040 #include <fcntl.h>
00041
00042
00043 #include <linux/joystick.h>
00044
00045
00046 #include "mythlogging.h"
00047
00048
00049 #include "jsmenuevent.h"
00050
00051 #define LOC QString("JoystickMenuThread: ")
00052
00053 JoystickMenuThread::JoystickMenuThread(QObject *main_window)
00054 : MThread("JoystickMenu"),
00055 m_mainWindow(main_window), m_devicename(""),
00056 m_fd(-1), m_buttonCount(0),
00057 m_axesCount(0), m_buttons(NULL),
00058 m_axes(NULL), m_bStop(false)
00059 {
00060 }
00061
00062 JoystickMenuThread::~JoystickMenuThread()
00063 {
00064 if (m_fd != -1)
00065 {
00066 close(m_fd);
00067 m_fd = -1;
00068 }
00069
00070 delete [] m_axes;
00071 m_axes = NULL;
00072
00073 delete [] m_buttons;
00074 m_buttons = NULL;
00075 }
00076
00080 int JoystickMenuThread::Init(QString &config_file)
00081 {
00082 int rc;
00083
00084
00085
00086
00087 rc = ReadConfig(config_file);
00088 if (rc)
00089 {
00090 LOG(VB_GENERAL, LOG_ERR, LOC +
00091 QString("Joystick disabled - Failed to read %1") .arg(config_file));
00092 return(rc);
00093 }
00094
00095
00096
00097
00098 m_fd = open(qPrintable(m_devicename), O_RDONLY);
00099 if (m_fd == -1)
00100 {
00101 LOG(VB_GENERAL, LOG_ERR, LOC +
00102 QString("Joystick disabled - Failed to open device %1")
00103 .arg(m_devicename));
00104 return -1;
00105 }
00106
00107 rc = ioctl(m_fd, JSIOCGAXES, &m_axesCount);
00108 if (rc == -1)
00109 {
00110 LOG(VB_GENERAL, LOG_ERR, LOC +
00111 "Joystick disabled - ioctl JSIOCGAXES failed");
00112 return(rc);
00113 }
00114
00115 rc = ioctl(m_fd, JSIOCGBUTTONS, &m_buttonCount);
00116 if (rc == -1)
00117 {
00118 LOG(VB_GENERAL, LOG_ERR, LOC +
00119 "Joystick disabled - ioctl JSIOCGBUTTONS failed");
00120 return(rc);
00121 }
00122
00123
00124
00125
00126 m_buttons = new int[m_buttonCount];
00127 memset(m_buttons, '\0', m_buttonCount * sizeof(*m_buttons));
00128
00129 m_axes = new int[m_axesCount];
00130 memset(m_axes, '\0', m_axesCount * sizeof(*m_axes));
00131
00132 LOG(VB_GENERAL, LOG_INFO, LOC +
00133 QString("Initialization of %1 succeeded using config file %2")
00134 .arg(m_devicename) .arg(config_file));
00135 return 0;
00136 }
00137
00151 int JoystickMenuThread::ReadConfig(QString config_file)
00152 {
00153 FILE *fp;
00154
00155 fp = fopen(qPrintable(config_file), "r");
00156 if (!fp)
00157 return(-1);
00158
00159 QTextStream istream(fp);
00160 for (int line = 1; ! istream.atEnd(); line++)
00161 {
00162 QString rawline = istream.readLine();
00163 QString simple_line = rawline.simplified();
00164 if (simple_line.isEmpty() || simple_line.startsWith('#'))
00165 continue;
00166
00167 QStringList tokens = simple_line.split(" ");
00168 if (tokens.count() < 1)
00169 continue;
00170
00171 QString firstTok = tokens[0].toLower();
00172
00173 if (firstTok.startsWith("devicename") && tokens.count() == 2)
00174 m_devicename = tokens[1];
00175 else if (firstTok.startsWith("button") && tokens.count() == 3)
00176 m_map.AddButton(tokens[1].toInt(), tokens[2]);
00177 else if (firstTok.startsWith("axis") && tokens.count() == 5)
00178 m_map.AddAxis(tokens[1].toInt(), tokens[2].toInt(),
00179 tokens[3].toInt(), tokens[4]);
00180 else if (firstTok.startsWith("chord") && tokens.count() == 4)
00181 m_map.AddButton(tokens[2].toInt(), tokens[3], tokens[1].toInt());
00182 else
00183 LOG(VB_GENERAL, LOG_ERR, LOC +
00184 QString("ReadConfig(%1) unrecognized or malformed line \"%2\" ")
00185 .arg(line) .arg(rawline));
00186 }
00187
00188 fclose(fp);
00189 return(0);
00190 }
00191
00192
00197 void JoystickMenuThread::run(void)
00198 {
00199 RunProlog();
00200
00201 int rc;
00202
00203 fd_set readfds;
00204 struct js_event js;
00205 struct timeval timeout;
00206
00207 while (!m_bStop)
00208 {
00209
00210
00211
00212
00213
00214 FD_ZERO(&readfds);
00215 FD_SET(m_fd, &readfds);
00216
00217
00218 timeout.tv_sec = 0;
00219 timeout.tv_usec = 100000;
00220
00221 rc = select(m_fd + 1, &readfds, NULL, NULL, &timeout);
00222 if (rc == -1)
00223 {
00224
00225
00226
00227
00228 LOG(VB_GENERAL, LOG_ERR, "select: " + ENO);
00229 return;
00230 }
00231
00232 if (rc == 1)
00233 {
00234
00235
00236
00237 rc = read(m_fd, &js, sizeof(js));
00238 if (rc != sizeof(js))
00239 {
00240 LOG(VB_GENERAL, LOG_ERR, "error reading js:" + ENO);
00241 return;
00242 }
00243
00244
00245
00246
00247
00248
00249 if (js.type & JS_EVENT_INIT)
00250 {
00251 if (js.type & JS_EVENT_BUTTON && js.number < m_buttonCount)
00252 m_buttons[js.number] = js.value;
00253
00254 if (js.type & JS_EVENT_AXIS && js.number < m_axesCount)
00255 m_axes[js.number] = js.value;
00256 }
00257 else
00258 {
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270 if (js.type & JS_EVENT_BUTTON && js.number < m_buttonCount)
00271 {
00272 if (js.value == 0 && m_buttons[js.number] == 1)
00273 ButtonUp(js.number);
00274
00275 m_buttons[js.number] = js.value;
00276 }
00277
00278 if (js.type & JS_EVENT_AXIS && js.number < m_axesCount)
00279 {
00280 AxisChange(js.number, js.value);
00281 m_axes[js.number] = js.value;
00282 }
00283
00284 }
00285
00286 }
00287
00288 }
00289
00290 RunEpilog();
00291 }
00292
00296 void JoystickMenuThread::EmitKey(QString code)
00297 {
00298 QKeySequence a(code);
00299
00300 int keycode = 0;
00301
00302
00303
00304
00305 if (!a.count())
00306 QCoreApplication::postEvent(m_mainWindow, new JoystickKeycodeEvent(code,
00307 keycode, true));
00308
00309 for (unsigned int i = 0; i < a.count(); i++)
00310 {
00311 keycode = a[i];
00312
00313 QCoreApplication::postEvent(m_mainWindow, new JoystickKeycodeEvent(code,
00314 keycode, true));
00315 QCoreApplication::postEvent(m_mainWindow, new JoystickKeycodeEvent(code,
00316 keycode, false));
00317 }
00318 }
00319
00320
00327 void JoystickMenuThread::ButtonUp(int button)
00328 {
00329
00330
00331
00332 JoystickMap::button_map_t::const_iterator bmap;
00333 for (bmap = m_map.buttonMap().begin(); bmap != m_map.buttonMap().end();
00334 ++bmap)
00335 {
00336 if (button == bmap->button && bmap->chord != -1
00337 && m_buttons[bmap->chord] == 1)
00338 {
00339 EmitKey(bmap->keystring);
00340 m_buttons[bmap->chord] = 0;
00341 return;
00342 }
00343 }
00344
00345
00346
00347
00348 for (bmap = m_map.buttonMap().begin(); bmap != m_map.buttonMap().end();
00349 ++bmap)
00350 {
00351 if (button == bmap->button && bmap->chord == -1)
00352 EmitKey(bmap->keystring);
00353 }
00354 }
00355
00359 void JoystickMenuThread::AxisChange(int axis, int value)
00360 {
00361 JoystickMap::axis_map_t::const_iterator amap;
00362 for (amap = m_map.axisMap().begin(); amap < m_map.axisMap().end(); ++amap)
00363 {
00364 if (axis == amap->axis)
00365 {
00366
00367
00368 if (m_axes[axis] < amap->from || m_axes[axis] > amap->to)
00369 if (value >= amap->from && value <= amap->to)
00370 EmitKey(amap->keystring);
00371 }
00372 }
00373 }