Using USB HID Joystick with Debian Lenny

After purchasing a USB HID joystick for my Linux entertainment center, I quickly noticed that it did not work out-of-the-box. This is what I did.

Before reading any further, see the links in section 6 for a possibly more flexible ways of doing this.

1) Plug in the device

FIXME: kernel messages etc,
matti@telkkari:~$ ls -l /dev/input/by-id/
total 0
lrwxrwxrwx 1 root root 9 2010-09-24 14:44 usb-06b4_1c70-event-mouse -> ../event1
lrwxrwxrwx 1 root root 9 2010-09-24 14:44 usb-06b4_1c70-mouse -> ../mouse0
lrwxrwxrwx 1 root root 9 2010-09-24 14:44 usb-DragonRise_Inc._Generic_USB_Joystick-event-joystick -> ../event5
lrwxrwxrwx 1 root root 6 2010-09-24 14:44 usb-DragonRise_Inc._Generic_USB_Joystick-joystick -> ../js0

2) Install xorg driver

Xorg needs joystick driver which is not installed by default. Install "xserver-xorg-input-joystick", by root:

apt-get install xserver-xorg-input-joystick

3) Basic xorg configuration

The recent versions of Xorg X server run easily without configuration file /etc/X11/xorg.conf. If you don't have it, you should create it.

Browse through your configuration file. The joystick should have its own InputDevice section and if you don't find one, add it. Here is mine:
Section "InputDevice"
Identifier "Configured Joystick"
Driver "joystick"
Option "Device" "/dev/input/by-id/usb-DragonRise_Inc._Generic_USB_Joystick-joystick"
# Option "DebugLevel" "255"
EndSection

The Identifier defines the device name that is later referred in ServerLayout section. Here is mine:

Section "ServerLayout"
Identifier "Default Layout"
Screen "Default Screen"
InputDevice "Generic Keyboard"
InputDevice "Configured Mouse"
InputDevice "Configured Joystick"
EndSection

The Driver tells that the device uses joystick driver (which is packaged in "xserver-xorg-input-joystick"). Option Device specifies input device node. One of the event* nodes in the /dev/input belong to my joystick.

$ ls -l /dev/input/
total 0
drwxr-xr-x 2 root root 120 2010-09-24 21:46 by-id
drwxr-xr-x 2 root root 160 2010-09-24 21:46 by-path
crw-rw---- 1 root root 13, 64 2010-09-24 21:46 event0
crw-rw---- 1 root root 13, 65 2010-09-24 21:46 event1
crw-rw-r-- 1 root audio 13, 66 2010-09-24 21:46 event2
crw-rw---- 1 root root 13, 67 2010-09-24 21:46 event3
crw-rw---- 1 root root 13, 68 2010-09-24 21:46 event4
crw-rw---- 1 root root 13, 69 2010-09-24 21:46 event5
crw-rw-r-- 1 root root 13, 0 2010-09-24 21:46 js0
crw-rw---- 1 root root 13, 63 2010-09-24 21:46 mice
crw-rw---- 1 root root 13, 32 2010-09-24 21:46 mouse0
ba

The automatically created symlinks in /dev/input/by-id offer easy and constant node for the device:

$ ls -l /dev/input/by-id/
total 0
lrwxrwxrwx 1 root root 9 2010-09-24 21:46 usb-06b4_1c70-event-mouse -> ../event1
lrwxrwxrwx 1 root root 9 2010-09-24 21:46 usb-06b4_1c70-mouse -> ../mouse0
lrwxrwxrwx 1 root root 9 2010-09-24 21:46 usb-DragonRise_Inc._Generic_USB_Joystick-event-joystick -> ../event2
lrwxrwxrwx 1 root root 6 2010-09-24 21:46 usb-DragonRise_Inc._Generic_USB_Joystick-joystick -> ../js0

Wow! /dev/input/by-id/usb-DragonRise_Inc._Generic_USB_Joystick-joystick is my node and thus my Device path.

The commented Option DebugLevel row should be uncommented for the mapping phase.

4) Make your mappings

At this point your X pointer may react to your joystick. If the reactions are correct for your favourite game, you may stop here. In my case I wasn't (or my sons were not satisfied) with the actions on SuperTux, so I had to make some mappings.

By mappings we mean that some joystick actions (e.g. pressing a Select button) causes some activities in the X. The games I play do not know anything about joysticks so I configured the joystick to press some keys.

When the X is executed with DebugLevel 255 for Joystick device (uncomment the line Option "DebugLevel" "255" in my sample xorg.conf above) the device gives nice feedback about Joystick activities to the X server log. Here is a snippet:
$ tail -f /var/log/Xorg.0.log
Button 2 pressed. Mapping: 6
Generating key press event with keycode 11
Button 2 released. Mapping: 6
Generating key release event with keycode 11
Button 3 pressed. Mapping: 6
Generating key press event with keycode 12
Button 3 released. Mapping: 6
The log file tells you the joystick button and axis numbers that are referred in the mappings.

4.1) Mapping buttons

Each button can be programmed by the following procedure:
  1. While pressing the joystick buttons follow X log which tells you the button number.
  2. Get the keysym of your desired key activities. The joystick man page tells that keysyms can be found from /usr/include/X11/keysymdef.h. However, this file belongs to the x11proto-core-dev package, which is not installed by default. If you don't want to install one you'll find a file easily.
    #define XK_BackSpace		0xFF08	/* back space, back char */
    #define XK_Tab 0xFF09
    #define XK_Linefeed 0xFF0A /* Linefeed, LF */
    #define XK_Clear 0xFF0B
    #define XK_Return 0xFF0D /* Return, enter */
    #define XK_Pause 0xFF13 /* Pause, hold */
    #define XK_Scroll_Lock 0xFF14
    #define XK_Sys_Req 0xFF15
    #define XK_Escape 0xFF1B
    #define XK_Delete 0xFFFF /* Delete, rubout */
  3. The key mapping will be defined with Option MapButtonX in xorg.conf Joystick Device section. If you want Button 3 to correspond your Return, your Option line is:
    Option "MapButton4" "key=Return"
    or
    Option "MapButton4" "key=0xFF0D"
     
    Mouse buttons:
    Option "MapButton4" "button=1" # Left button
    Option "MapButton4" "button=2" # Right button
    Option "MapButton4" "button=3" # Middle button

4.2) Mapping axis

As I told above the games I needed a joystick for are controlled by the arrow keys. Therefore, I wanted to remap my movement buttons and joystick to arrow keys. The correct axis numbers can be detected from the X server log. You have to add 1 for axis numbers just like with the buttons.

The joystick driver man page gives you nice examples in defining axis keymappings. Here are my definitions:
        # Left joystick
Option "MapAxis1" "mode=accelerated keylow=Left keyhigh=Right axis=0.5key"
Option "MapAxis2" "mode=accelerated keylow=Up keyhigh=Down"

5) Complete xorg.conf

Here is my complete xorg.conf after the joystick hassle (see multiple joystick configurations that are selected in ServerLayout section) :
# /etc/X11/xorg.conf (xorg X Window System server configuration file
#
# This file was generated by dexconf, the Debian X Configuration tool, using
# values from the debconf database.
#
# Edit this file with caution, and see the /etc/X11/xorg.conf manual page.
# (Type "man /etc/X11/xorg.conf" at the shell prompt.)
#
# This file is automatically updated on xserver-xorg package upgrades *only*
# if it has not been modified since the last upgrade of the xserver-xorg
# package.
#
# If you have edited this file but would like it to be automatically updated
# again, run the following command:
# sudo dpkg-reconfigure -phigh xserver-xorg

Section "Files"
FontPath "/usr/share/fonts/X11/misc"
FontPath "/usr/X11R6/lib/X11/fonts/misc"
FontPath "/usr/share/fonts/X11/cyrillic"
FontPath "/usr/X11R6/lib/X11/fonts/cyrillic"
FontPath "/usr/share/fonts/X11/100dpi/:unscaled"
FontPath "/usr/X11R6/lib/X11/fonts/100dpi/:unscaled"
FontPath "/usr/share/fonts/X11/75dpi/:unscaled"
FontPath "/usr/X11R6/lib/X11/fonts/75dpi/:unscaled"
FontPath "/usr/share/fonts/X11/Type1"
FontPath "/usr/X11R6/lib/X11/fonts/Type1"
FontPath "/usr/share/fonts/X11/100dpi"
FontPath "/usr/X11R6/lib/X11/fonts/100dpi"
FontPath "/usr/share/fonts/X11/75dpi"
FontPath "/usr/X11R6/lib/X11/fonts/75dpi"
# path to defoma fonts
FontPath "/var/lib/defoma/x-ttcidfont-conf.d/dirs/TrueType"
EndSection

Section "Module"
Load "i2c"
Load "bitmap"
Load "ddc"
Load "dri"
Load "extmod"
Load "freetype"
Load "glx"
Load "int10"
Load "vbe"
# Load "theatre_detect"
EndSection

Section "InputDevice"
Identifier "Generic Keyboard"
Driver "kbd"
Option "CoreKeyboard"
Option "XkbRules" "xorg"
Option "XkbModel" "pc105"
Option "XkbLayout" "fi"
EndSection

Section "InputDevice"
Identifier "Configured Mouse"
Driver "mouse"
Option "CorePointer"
Option "Device" "/dev/input/mice"
Option "Protocol" "ImPS/2"
Option "Emulate3Buttons" "true"
EndSection

Section "InputDevice"
Identifier "SuperTUX Joystick"
Driver "joystick"
Option "Device" "/dev/input/by-id/usb-DragonRise_Inc._Generic_USB_Joystick-joystick"
Option "DebugLevel" "255"

# Buttons 1-2-3-4
Option "MapButton1" "key=Return"
Option "MapButton2" "key=Control_L"
Option "MapButton3" "key=space"
Option "MapButton4" "key=Escape"

# Small Fire Buttons
Option "MapButton5" "key=space"
Option "MapButton6" "key=space"

# Large Fire Buttons
Option "MapButton7" "key=Control_L"
Option "MapButton8" "key=Control_L"

# Select-button -> Super (MS Logo key)
Option "MapButton9" "key=space"
# Start-button -> Return
Option "MapButton10" "key=Return"

# Left joystick
Option "MapAxis1" "mode=accelerated keylow=Left keyhigh=Right axis=0.5key"
Option "MapAxis2" "mode=accelerated keylow=Up keyhigh=Down"
EndSection

Section "InputDevice"
Identifier "Minecraft Joystick"
Driver "joystick"
Option "Device" "/dev/input/by-id/usb-DragonRise_Inc._Generic_USB_Joystick-joystick"
Option "DebugLevel" "255"

# Buttons 1-2-3-4
# Forward
Option "MapButton1" "key=w"
# Right
Option "MapButton2" "key=d"
# Back
Option "MapButton3" "key=s"
# Left
Option "MapButton4" "key=a"

# Small Fire Buttons
# Left -> Mouse Right
Option "MapButton5" "button=3"
# Right -> Mouse Left
Option "MapButton6" "button=1"

# Large Fire Buttons
# Left -> Space bar (jump)
Option "MapButton7" "key=space"
# Right -> Mouse Left
Option "MapButton8" "button=1"

# Select-button -> e (inventory)
Option "MapButton9" "key=e"
# Start-button -> Escape (menu)
Option "MapButton10" "key=Escape"

# Left joystick
#Option "MapAxis1" "mode=accelerated keylow=Left keyhigh=Right axis=0.5key"
#Option "MapAxis2" "mode=accelerated keylow=Up keyhigh=Down"
EndSection

Section "Device"
Identifier "Generic Video Card"
Driver "vesa"
EndSection

Section "Device"
Identifier "ati card"
Driver "ati"
# Option "TVOutput" "PAL"
Option "TVStandard" "pal"
Option "ForceTVOut" "true"
EndSection

Section "Device"
Identifier "ati radeon"
Driver "radeon"
EndSection

Section "Monitor"
Identifier "Generic Monitor"
Option "DPMS"
HorizSync 30-50
VertRefresh 60-60
EndSection

Section "Monitor"
Identifier "PAL Monitor"
HorizSync 15.625
VertRefresh 50.0
ModeLine "720x576PAL" 15.125 720 770 842 968 576 579 607 625 interlace -hsync -vsync
EndSection

Section "Screen"
Identifier "Default Screen"
# Device "Generic Video Card"
# Device "ati radeon"
Device "ati card"
Monitor "Generic Monitor"
# Monitor "PAL Monitor"
DefaultDepth 24
SubSection "Display"
Depth 1
Modes "1280x1024" "1024x768" "800x600" "640x480"
EndSubSection
SubSection "Display"
Depth 4
Modes "1280x1024" "1024x768" "800x600" "640x480"
EndSubSection
SubSection "Display"
Depth 8
Modes "1280x1024" "1024x768" "800x600" "640x480"
EndSubSection
SubSection "Display"
Depth 15
Modes "1280x1024" "1024x768" "800x600" "640x480"
EndSubSection
SubSection "Display"
Depth 16
Modes "1280x1024" "1024x768" "800x600" "640x480"
Modes "800x600"
EndSubSection
SubSection "Display"
Depth 24
# Modes "1280x1024" "1024x768" "800x600" "640x480"
# Modes "1280x1024"
Modes "800x600"
# Modes "720x576PAL"
EndSubSection
EndSection

Section "ServerLayout"
Identifier "Default Layout"
Screen "Default Screen"
InputDevice "Generic Keyboard"
InputDevice "Configured Mouse"
# InputDevice "SuperTUX Joystick"
 InputDevice "Minecraft Joystick"
EndSection

Section "DRI"
Mode 0666
EndSection

6) Related stuff


Updated 28-JAN-2012 / Matti Lattu