[mythtv] [PATCH] Add joysticks as an input device to MythtTV

Jeremy White jwhite at codeweavers.com
Tue Sep 28 08:23:24 EDT 2004


If regular spammers don't give up, and simply escalate
their attacks, I figure that approach should work for
me as well <grin>.

Attached patch resolves all of my issues
to my satisfaction, save one; before applying,
please review the event number assignment in
jsmenuevent.h (there is an obvious FIXME at the top).

Changelog:
   Provide a facility to allow joystick devices to
   be used as input to MythTV.

-------------- next part --------------
Index: settings.pro
===================================================================
RCS file: /var/lib/mythcvs/mythtv/settings.pro,v
retrieving revision 1.68
diff -u -r1.68 settings.pro
--- settings.pro	13 Sep 2004 06:09:22 -0000	1.68
+++ settings.pro	28 Sep 2004 12:18:25 -0000
@@ -73,6 +73,9 @@
 #   'linux/dvb/frontend.h', not the directory with frontend.h
 #INCLUDEPATH += /usr/src/linuxtv-dvb-1.0.1/include
 
+# Joystick menu support
+CONFIG += using_joystick_menu
+
 # Native lirc support
 #CONFIG += using_lirc
 #LIRC_LIBS = -llirc_client
? libs/libmyth/jsmenu.cpp
? libs/libmyth/jsmenu.h
? libs/libmyth/jsmenuevent.cpp
? libs/libmyth/jsmenuevent.h
Index: libs/libmyth/libmyth.pro
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmyth/libmyth.pro,v
retrieving revision 1.52
diff -u -r1.52 libmyth.pro
--- libs/libmyth/libmyth.pro	7 Sep 2004 21:20:19 -0000	1.52
+++ libs/libmyth/libmyth.pro	28 Sep 2004 12:18:26 -0000
@@ -75,6 +75,12 @@
     LIBS += $$ALSA_LIBS
 }
 
+using_joystick_menu {
+    DEFINES += USE_JOYSTICK_MENU
+    HEADERS += jsmenu.h jsmenuevent.h
+    SOURCES += jsmenu.cpp jsmenuevent.cpp
+}
+
 using_lirc {
     DEFINES += USE_LIRC
     HEADERS += lirc.h lircevent.h
Index: libs/libmyth/mythdialogs.cpp
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmyth/mythdialogs.cpp,v
retrieving revision 1.86
diff -u -r1.86 mythdialogs.cpp
--- libs/libmyth/mythdialogs.cpp	10 Sep 2004 05:56:56 -0000	1.86
+++ libs/libmyth/mythdialogs.cpp	28 Sep 2004 12:18:29 -0000
@@ -28,6 +28,11 @@
 #include "lircevent.h"
 #endif
 
+#ifdef USE_JOYSTICK_MENU
+#include "jsmenu.h"
+#include "jsmenuevent.h"
+#endif
+
 #include "uitypes.h"
 #include "uilistbtntype.h"
 #include "xmlparse.h"
@@ -50,6 +55,19 @@
 }
 #endif
 
+#ifdef USE_JOYSTICK_MENU
+static void *SpawnJoystickMenu(void *param)
+{
+    MythMainWindow *main_window = (MythMainWindow *)param;
+    QString config_file = QDir::homeDirPath() + "/.mythtv/joystickmenurc";
+    JoystickMenuClient *js = new JoystickMenuClient(main_window);
+    if (!js->Init(config_file))
+        js->Process();
+
+    return NULL;
+}
+#endif
+
 class KeyContext
 {
   public:
@@ -102,7 +120,13 @@
 
     vector<QWidget *> widgetList;
 
+#ifdef USE_JOYSTICK_MENU
+    bool ignore_joystick_keys;
+#endif
+
+#ifdef USE_LIRC
     bool ignore_lirc_keys;
+#endif
 
     bool exitingtomain;
 
@@ -151,7 +175,6 @@
     d = new MythMainWindowPrivate;
 
     Init();
-    d->ignore_lirc_keys = false;
     d->exitingtomain = false;
     d->exitmenucallback = false;
     d->exitmenumediadevicecallback = false;
@@ -159,6 +182,7 @@
     d->escapekey = Key_Escape;
 
 #ifdef USE_LIRC
+    d->ignore_lirc_keys = false;
     pthread_t lirc_tid;
     pthread_attr_t attr;
     pthread_attr_init(&attr);
@@ -167,6 +191,16 @@
     pthread_create(&lirc_tid, &attr, SpawnLirc, this);
 #endif
 
+#ifdef USE_JOYSTICK_MENU
+    d->ignore_joystick_keys = false;
+    pthread_t js_tid;
+
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+    pthread_create(&js_tid, &attr, SpawnJoystickMenu, this);
+#endif
+
     d->keyContexts.setAutoDelete(true);
 
     RegisterKey("Global", "UP", "Up Arrow", "Up");
@@ -686,6 +720,48 @@
         d->ignore_lirc_keys = lme->eventsMuted();
     }
 #endif
+#ifdef USE_JOYSTICK_MENU
+    else if (ce->type() == kJoystickKeycodeEventType && !d->ignore_joystick_keys) 
+    {
+        JoystickKeycodeEvent *jke = (JoystickKeycodeEvent *)ce;
+        int keycode = jke->getKeycode();
+
+        if (keycode) 
+        {
+            gContext->ResetScreensaver();
+
+            int mod = keycode & MODIFIER_MASK;
+            int k = keycode & ~MODIFIER_MASK; /* trim off the mod */
+            int ascii = 0;
+            QString text;
+
+            if (k & UNICODE_ACCEL)
+            {
+                QChar c(k & ~UNICODE_ACCEL);
+                ascii = c.latin1();
+                text = QString(c);
+            }
+
+            QKeyEvent key(jke->isKeyDown() ? QEvent::KeyPress :
+                          QEvent::KeyRelease, k, ascii, mod, text);
+
+            QObject *key_target = getTarget(key);
+
+            QApplication::sendEvent(key_target, &key);
+        }
+        else
+        {
+            cerr << "JoystickMenuClient warning: attempt to convert '"
+                 << jke->getJoystickMenuText() << "' to a key sequence failed. Fix"
+                                           " your key mappings.\n";
+        }
+    }
+    else if (ce->type() == kJoystickMuteEventType)
+    {
+        JoystickMenuMuteEvent *jme = (JoystickMenuMuteEvent *)ce;
+        d->ignore_joystick_keys = jme->eventsMuted();
+    }
+#endif
     else if (ce->type() == ScreenSaverEvent::kScreenSaverEventType)
     {
         ScreenSaverEvent *sse = (ScreenSaverEvent *)ce;
Index: libs/libmyth/util.cpp
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmyth/util.cpp,v
retrieving revision 1.36
diff -u -r1.36 util.cpp
--- libs/libmyth/util.cpp	7 Aug 2004 13:08:33 -0000	1.36
+++ libs/libmyth/util.cpp	28 Sep 2004 12:18:30 -0000
@@ -24,6 +24,10 @@
 #include "lircevent.h"
 #endif
 
+#ifdef USE_JOYSTICK_MENU
+#include "jsmenuevent.h"
+#endif
+
 #define SOCKET_BUF_SIZE  128000
 
 bool connectSocket(QSocketDevice *socket, const QString &host, int port)
@@ -615,7 +619,14 @@
 {
 #ifdef USE_LIRC
     LircEventLock lirc_lock(!(flags & MYTH_SYSTEM_DONT_BLOCK_LIRC));
-#else
+#endif
+
+#ifdef USE_JOYSTICK_MENU
+    JoystickMenuEventLock joystick_lock(!(flags & MYTH_SYSTEM_DONT_BLOCK_JOYSTICK_MENU));
+#endif
+
+    /* Kill warning, I presume */
+#if ! defined(USE_LIRC) && ! defined(USE_JOYSTICK_MENU)
     (void)flags;
 #endif
 
Index: libs/libmyth/util.h
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmyth/util.h,v
retrieving revision 1.15
diff -u -r1.15 util.h
--- libs/libmyth/util.h	8 Jul 2004 23:26:21 -0000	1.15
+++ libs/libmyth/util.h	28 Sep 2004 12:18:30 -0000
@@ -39,6 +39,7 @@
 QRgb blendColors(QRgb source, QRgb add, int alpha);
 
 #define MYTH_SYSTEM_DONT_BLOCK_LIRC (1)
+#define MYTH_SYSTEM_DONT_BLOCK_JOYSTICK_MENU (2)
 int myth_system(const QString &command, int flags = 0);
 
 QString cutDownString(QString text, QFont *testFont, int maxwidth);
--- /dev/null	2004-06-09 21:35:19.000000000 -0500
+++ libs/libmyth/jsmenu.cpp	2004-09-28 07:18:19.000000000 -0500
@@ -0,0 +1,362 @@
+/*----------------------------------------------------------------------------
+**  jsmenu.cpp
+**
+**  Description:
+**      Set of functions to generate key events based on
+**  input from a Joystick.
+**
+**  Original Copyright 2004 by Jeremy White <jwhite at whitesen.org>
+**
+**  License:
+**      This program is free software; you can redistribute it
+**  and/or modify it under the terms of the GNU General
+**  Public License as published bythe Free Software Foundation;
+**  either version 2, or (at your option)
+**  any later version.
+** 
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+** 
+**--------------------------------------------------------------------------*/
+
+#include <qapplication.h>
+#include <qevent.h>
+#include <qkeysequence.h>
+#include <cstdio>
+#include <cerrno>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "mythcontext.h"
+
+#include <iostream>
+using namespace std;
+
+#include <linux/joystick.h>
+
+#include "jsmenu.h"
+#include "jsmenuevent.h"
+
+#if (QT_VERSION < 0x030100)
+#error Native LIRC support requires Qt 3.1 or greater.
+#endif
+
+
+
+/*----------------------------------------------------------------------------
+** JoystickMenuClient Constructor
+**--------------------------------------------------------------------------*/
+JoystickMenuClient::JoystickMenuClient(QObject *main_window)
+{
+    mainWindow = main_window;
+
+    fd = -1;
+    axes = NULL;
+    buttons = NULL;
+
+}
+
+/*----------------------------------------------------------------------------
+** JoystickMenuClient Destructor
+**--------------------------------------------------------------------------*/
+JoystickMenuClient::~JoystickMenuClient()
+{
+    if (fd != -1)
+    {
+        close(fd);
+        fd = -1;
+    }
+
+    if (axes)
+    {
+        free(axes);
+        buttons = NULL;
+    }
+
+    if (buttons)
+    {
+        free(buttons);
+        buttons = NULL;
+    }
+}
+
+/*----------------------------------------------------------------------------
+** Init
+**--------------------------------------------------------------------------*/
+int JoystickMenuClient::Init(QString &config_file)
+{
+    int rc;
+
+    /*------------------------------------------------------------------------
+    ** Read the config file
+    **----------------------------------------------------------------------*/
+    rc = ReadConfig(config_file);
+    if (rc)
+    {
+        cerr << config_file << " not found; menu keys from joystick disabled.\n";
+        return(rc);
+    }
+
+    /*------------------------------------------------------------------------
+    ** Open the joystick device, retrieve basic info
+    **----------------------------------------------------------------------*/
+    fd = open((const char *) devicename, O_RDONLY);
+    if (fd == -1)
+    {
+        cerr << "Could not initialize " << devicename << "\n";
+        perror("open");
+    }
+    
+    rc = ioctl(fd, JSIOCGAXES, &axes_count);
+    if (rc == -1)
+    {
+        perror("ioctl JSIOCGAXES");
+        return(rc);
+    }
+
+    ioctl(fd, JSIOCGBUTTONS, &button_count);
+    if (rc == -1)
+    {
+        perror("ioctl JSIOCGBUTTONS");
+        return(rc);
+    }
+
+    /*------------------------------------------------------------------------
+    ** Allocate the arrays in which we track button and axis status
+    **----------------------------------------------------------------------*/
+    buttons = new int[button_count];
+    memset(buttons, '\0', sizeof(*buttons * button_count));
+
+    axes = new int[axes_count];
+    memset(axes, '\0', sizeof(*axes * axes_count));
+
+
+    return 0;
+}
+
+/*----------------------------------------------------------------------------
+** ReadConfig
+**  Read from a flat file config file, with a format of:
+**    # Starts a comment
+**    devicename devname            - Name of physical joystick device
+**    button num keystring          - Represents a button
+**    chord cnum bnum keystring     - A chorded button sequence; hold down cnum
+**                                    and press bnum to generate a key
+**    axis num from to keystring    - Represents an axis range to trigger a key
+**                                    move that axis into the range and the
+**                                    keystring is sent
+**--------------------------------------------------------------------------*/
+int JoystickMenuClient::ReadConfig(QString config_file)
+{
+    FILE *fp;
+
+    fp = fopen((const char *) config_file, "r");
+    if (!fp)
+        return(-1);
+
+    QTextIStream istream(fp);
+    for (int line = 1; ! istream.atEnd(); line++)
+    {
+        QString rawline = istream.readLine();
+        QString simple_line = rawline.simplifyWhiteSpace(); 
+        if (simple_line.isEmpty() || simple_line.startsWith("#"))
+            continue;
+
+        QStringList tokens = QStringList::split(" ", simple_line);
+        if (tokens.count() < 1)
+            continue;
+
+        if (tokens[0].startsWith("devicename", FALSE) && tokens.count() == 2)
+            devicename = tokens[1];
+        else if (tokens[0].startsWith("button", FALSE) && tokens.count() == 3)
+            map.AddButton(tokens[1].toInt(), tokens[2]);
+        else if (tokens[0].startsWith("axis", FALSE) && tokens.count() == 5)
+            map.AddAxis(tokens[1].toInt(), tokens[2].toInt(), tokens[3].toInt(), tokens[4]);
+        else if (tokens[0].startsWith("chord", FALSE) && tokens.count() == 4)
+            map.AddButton(tokens[2].toInt(), tokens[3], tokens[1].toInt());
+        else
+            cerr << config_file << "(" << line << "): unrecognized or malformed line: '" << rawline << "'\n";
+
+    }
+
+    fclose(fp);
+    return(0);
+}
+
+
+/*----------------------------------------------------------------------------
+** Process
+**  This function is intended to run as the mainline of a thread which
+** looks for Joystick input and translates it into key stroke events
+** for MythTv.
+**--------------------------------------------------------------------------*/
+void JoystickMenuClient::Process(void)
+{
+    int rc;
+
+    fd_set readfds;
+    struct js_event js;
+
+    while (1)
+    {
+
+        /*--------------------------------------------------------------------
+        ** Wait for activity from the joy stick (we wait a configurable
+        **      poll time)
+        **------------------------------------------------------------------*/
+        FD_ZERO(&readfds);
+        FD_SET(fd, &readfds);
+
+        rc = select(fd + 1, &readfds, NULL, NULL, NULL);
+        if (rc == -1)
+        {
+            /*----------------------------------------------------------------
+            ** TODO:  In theory, we could recover from file errors
+            **        (what happens when we unplug a joystick?)
+            **--------------------------------------------------------------*/
+            perror("select");
+            return;
+        }
+
+        if (rc == 1)
+        {	
+            /*----------------------------------------------------------------
+            ** Read a joystick event
+            **--------------------------------------------------------------*/
+            rc = read(fd, &js, sizeof(js));
+            if (rc != sizeof(js))
+            {
+                    perror("error reading js");
+                    return;
+            }
+
+            /*----------------------------------------------------------------
+            ** Events sent with the JS_EVENT_INIT flag are always sent
+            **  right after you open the joy stick; they are useful
+            **  for learning the initial state of buttons and axes
+            **--------------------------------------------------------------*/
+            if (js.type & JS_EVENT_INIT)
+            {
+                if (js.type & JS_EVENT_BUTTON && js.number < button_count)
+                    buttons[js.number] = js.value;
+
+                if (js.type & JS_EVENT_AXIS && js.number < axes_count)
+                    axes[js.number] = js.value;
+            }
+            else
+            {
+                /*------------------------------------------------------------
+                ** Record new button states and look for triggers
+                **  that would make us send a key.
+                ** Things are a little tricky here; for buttons, we
+                **  only act on button up events, not button down
+                **  (this lets us implement the chord function).
+                ** For axes, we only register a change if the
+                **  Joystick moves into the specified range
+                **  (that way, we only get one event per joystick
+                **  motion).
+                **----------------------------------------------------------*/
+                if (js.type & JS_EVENT_BUTTON && js.number < button_count)
+                {
+                    if (js.value == 0 && buttons[js.number] == 1)
+                        ButtonUp(js.number);
+
+                    buttons[js.number] = js.value;
+                }
+
+                if (js.type & JS_EVENT_AXIS && js.number < button_count)
+                {
+                    AxisChange(js.number, js.value);
+                    axes[js.number] = js.value;
+                }
+
+            }
+
+        }
+
+    }
+
+}
+
+/*----------------------------------------------------------------------------
+** EmitKey
+**  Send an event to the main UI loop with the appropriate keycode
+**  (looking up the string using QT)
+**--------------------------------------------------------------------------*/
+void JoystickMenuClient::EmitKey(QString code)
+{
+    QKeySequence a(code);
+
+    int keycode = 0;
+
+    // Send a dummy keycode if we couldn't convert the key sequence.
+    // This is done so the main code can output a warning for bad
+    // mappings.
+    if (!a.count())
+        QApplication::postEvent(mainWindow, new JoystickKeycodeEvent(code, 
+                                keycode, true));
+
+    for (unsigned int i = 0; i < a.count(); i++)
+    {
+        keycode = a[i];
+
+        QApplication::postEvent(mainWindow, new JoystickKeycodeEvent(code, 
+                                keycode, true));
+        QApplication::postEvent(mainWindow, new JoystickKeycodeEvent(code, 
+                                keycode, false));
+
+    }
+}
+
+
+/*----------------------------------------------------------------------------
+** ButtonUp
+**  Handle a button up event; this is mildly complicated by
+** the support for 'chords'; holding down a button and pushing down
+** another can create one type of event.
+**--------------------------------------------------------------------------*/
+void JoystickMenuClient::ButtonUp(int button)
+{
+    vector<button_map_type>::iterator bmap;
+
+    /*------------------------------------------------------------------------
+    ** Process chords first
+    **----------------------------------------------------------------------*/
+    for (bmap = map.button_map.begin(); bmap < map.button_map.end(); bmap++)
+        if (button == bmap->button && bmap->chord != -1 && buttons[bmap->chord] == 1)
+        {
+            EmitKey(bmap->keystring);
+            buttons[bmap->chord] = 0;
+            return;
+        }
+
+    /*------------------------------------------------------------------------
+    ** Process everything else
+    **----------------------------------------------------------------------*/
+    for (bmap = map.button_map.begin(); bmap < map.button_map.end(); bmap++)
+        if (button == bmap->button && bmap->chord == -1)
+            EmitKey(bmap->keystring);
+}
+
+/*----------------------------------------------------------------------------
+** AxisChange
+**  Handle a registerd change in a joystick axis
+**--------------------------------------------------------------------------*/
+void JoystickMenuClient::AxisChange(int axis, int value)
+{
+    vector<axis_map_type>::iterator amap;
+    for (amap = map.axis_map.begin(); amap < map.axis_map.end(); amap++)
+        if (axis == amap->axis)
+        {
+            /* If we're currently outside the range, and the move is
+            **   into the range, then we trigger                        */
+            if (axes[axis] < amap->from || axes[axis] > amap->to)
+                if (value >= amap->from && value <= amap->to)
+                    EmitKey(amap->keystring);
+        }
+}
+
--- /dev/null	2004-06-09 21:35:19.000000000 -0500
+++ libs/libmyth/jsmenu.h	2004-09-27 23:15:33.000000000 -0500
@@ -0,0 +1,103 @@
+/*----------------------------------------------------------------------------
+** jsmenu.h
+**  GPL license; Original copyright 2004 Jeremy White <jwhite at whitesen.org>
+**--------------------------------------------------------------------------*/
+
+#ifndef JSMENU_H_
+#define JSMENU_H_
+
+#include <qobject.h>
+#include <qsocket.h>
+#include <qstring.h>
+
+#include "mythdialogs.h"
+
+/*----------------------------------------------------------------------------
+** JoystickMap related information
+**  We build a map of how joystick buttons and axes (axes are for sticks
+** and thumb controllers) are mapped into keystrokes.
+**  For buttons, it's mostly very simple:  joystick button number 
+** corresponds to a key sequence that is sent to MythTV.
+**  We complicate it a little by allowing for 'chords', which
+** means that if you hold down the 'chord' button while pressing
+** the other button, we use the alternate mapping
+**  For axes, it's not very complicated.  For each axis (ie up/down or
+** left/right), we define a range; the first time the joystick moves
+** into that range, we send the assigned keystring.  
+**--------------------------------------------------------------------------*/
+struct button_map_type
+{
+    int button;
+    QString keystring;
+    int chord;
+};
+
+typedef struct
+{
+    int axis;
+    int from;
+    int to;
+    QString keystring;
+} axis_map_type;
+
+class JoystickMap
+{
+    public:
+        void AddButton(int in_button, QString in_keystr, int in_chord = -1)
+        {
+            button_map_type new_button = { in_button, in_keystr, in_chord };
+            button_map.push_back(new_button);
+        }
+
+        void AddAxis(int in_axis, int in_from, int in_to, QString in_keystr)
+        {
+            axis_map_type new_axis = { in_axis, in_from, in_to, in_keystr};
+            axis_map.push_back(new_axis);
+        }
+
+
+        vector<button_map_type> button_map;
+        vector<axis_map_type> axis_map;
+};
+
+/*----------------------------------------------------------------------------
+** JoystickMenuClient
+**  Main object for injecting key strokes based on joystick movements
+**--------------------------------------------------------------------------*/
+class JoystickMenuClient : public QObject
+{
+    Q_OBJECT
+  public:
+    JoystickMenuClient(QObject *main_window);
+    ~JoystickMenuClient();
+    int Init(QString &config_file);
+
+    void Process(void);
+    
+    void ButtonUp(int button);
+    void AxisChange(int axis, int value);
+    void JoystickMenuClient::EmitKey(QString code);
+    int  ReadConfig(QString config_file);
+
+  private:
+    QObject *mainWindow;
+    
+    QString devicename;
+
+    int fd;
+
+    JoystickMap map;
+
+    /*------------------------------------------------------------------------
+    ** These two arrays and their related counts track the status of the
+    **   joystick buttons and axes, as we do depend slightly on state
+    **----------------------------------------------------------------------*/
+    unsigned char button_count;
+    unsigned char axes_count;
+
+    int *buttons;
+    int *axes;
+
+};
+
+#endif
--- /dev/null	2004-06-09 21:35:19.000000000 -0500
+++ libs/libmyth/jsmenuevent.cpp	2004-09-26 20:08:58.000000000 -0500
@@ -0,0 +1,45 @@
+/*----------------------------------------------------------------------------
+** jsmenuevent.cpp
+**  GPL license; Original copyright 2004 Jeremy White <jwhite at whitesen.org>
+**     although this is largely a derivative of lircevent.cpp
+**--------------------------------------------------------------------------*/
+#include <qapplication.h>
+#include <qstring.h>
+#include "mythcontext.h"
+
+#include "jsmenuevent.h"
+
+JoystickMenuEventLock::JoystickMenuEventLock(bool lock_events) 
+             : events_locked(false)
+{
+    if (lock_events)
+        lock();
+}
+
+JoystickMenuEventLock::~JoystickMenuEventLock()
+{
+    if (events_locked)
+        unlock();
+}
+
+void JoystickMenuEventLock::lock()
+{
+    MythMainWindow *mw = gContext->GetMainWindow();
+    if (mw)
+    {
+        events_locked = true;
+        QApplication::postEvent((QObject *)mw,
+			new JoystickMenuMuteEvent(events_locked));
+    }
+}
+
+void JoystickMenuEventLock::unlock()
+{
+    MythMainWindow *mw = gContext->GetMainWindow();
+    if (mw)
+    {
+        events_locked = false;
+        QApplication::postEvent((QObject *)mw,
+			new JoystickMenuMuteEvent(events_locked));
+    }
+}
--- /dev/null	2004-06-09 21:35:19.000000000 -0500
+++ libs/libmyth/jsmenuevent.h	2004-09-26 20:08:48.000000000 -0500
@@ -0,0 +1,69 @@
+/*----------------------------------------------------------------------------
+** jsmenuevent.h
+**  GPL license; Original copyright 2004 Jeremy White <jwhite at whitesen.org>
+**     although this is largely a derivative of lircevent.h
+**--------------------------------------------------------------------------*/
+#ifndef JSMENUEVENT_H_
+#define JSMENUEVENT_H_
+
+/* FIXME:  Learn how to assign a real event type */
+const int kJoystickKeycodeEventType = 24425;  /*LA LA WHERE THE HECK IS THIS FROM */
+const int kJoystickMuteEventType = 24426;
+
+class JoystickKeycodeEvent : public QCustomEvent 
+{
+  public:
+    JoystickKeycodeEvent(const QString &jsmenuevent_text, int key_code, bool key_down) :
+            QCustomEvent(kJoystickKeycodeEventType), jsmenueventtext(jsmenuevent_text), 
+            keycode(key_code), keydown(key_down) {}
+
+    QString getJoystickMenuText()
+    {
+        return jsmenueventtext;
+    }
+
+    int getKeycode()
+    {
+        return keycode;
+    }
+
+    bool isKeyDown()
+    {
+        return keydown;
+    }
+
+  private:
+    QString jsmenueventtext;
+    int keycode;
+    bool keydown;
+};
+
+class JoystickMenuMuteEvent : public QCustomEvent
+{
+  public:
+    JoystickMenuMuteEvent(bool mute_events) : QCustomEvent(kJoystickMuteEventType),
+            mute_jsmenu_events(mute_events) {}
+
+    bool eventsMuted()
+    {
+        return mute_jsmenu_events;
+    }
+
+  private:
+    bool mute_jsmenu_events;
+};
+
+class JoystickMenuEventLock
+{
+  public:
+    JoystickMenuEventLock(bool lock_events = true);
+    ~JoystickMenuEventLock();
+    void lock();
+    void unlock();
+
+  private:
+    bool events_locked;
+};
+
+#endif
+
--- /dev/null	2004-06-09 21:35:19.000000000 -0500
+++ configfiles/joystickmenurc.example	2004-09-27 23:46:56.000000000 -0500
@@ -0,0 +1,30 @@
+#
+# Joystick menu config file
+#  Place in ~/.mythtv/
+#
+#   Format:
+#       devicename <devname>        Specify name of joystick device to use
+#                                   (e.g. /dev/js0)
+#       button num keystring        Send 'keystring' when button 'num' is released
+#       chord cnum bnum keystring   If button cnum is down, and button 'bnum'
+#                                   is released, send keystring
+#       axis num from to keystring  If axis num goes into the range of from-to
+#                                   send keystring
+
+devicename /dev/js0
+
+button 0                    Enter
+button 1                    Escape
+chord  2    5               Escape
+
+axis   0    -32767  -15000  Left
+axis   0     15000   32767  Right
+axis   1    -32767  -15000  Up
+axis   1     15000   32767  Down
+
+axis   5    -32767  -15000  Left
+axis   5     15000   32767  Right
+axis   6    -32767  -15000  Up
+axis   6     15000   32767  Down
+
+


More information about the mythtv-dev mailing list