Reading input from game controllers / joy devices (e.g. USB game pads, joysticks, etc) is pretty straightforward in Linux. You can do it fairly easily without extra libraries, by just opening the appropriate device file for reading.
Aside from the obvious use of controlling computer games, game controllers can come in handy for all kinds of projects - anything where you have a need for buttons and/or control sticks. Depending on your needs, it might be more convenient than alternatives such as wiring up your own buttons to GPIO pins. So this is a pretty useful feature.
Here is an example in pure Tcl, with Tk for a graphical demonstration. I made an effort to make the code adaptable, so you can cut bits out and make it do whatever you need.
# ------------------------------------------------------------------------------- # -- Simple joy device input in Tcl using an input file channel and 'filevent' -- # ------------------------------------------------------------------------------- # These procedures are called to handle the various kinds of joy device events. # First, re-define these procedures to do whatever you need, and then call 'openJoyDevice' with the path of your joy device. # Note that 'axisValue' is a value from -32767 to +32767, and 'eventTime' is a millisecond clock time (thousandths of a second) proc joyButtonInitHandler {buttonNumber eventTime} {} proc joyAxisInitHandler {axisNumber axisValue eventTime} {} proc joyButtonPressHandler {buttonNumber eventTime} {} proc joyButtonReleaseHandler {buttonNumber eventTime} {} proc joyAxisMovedHandler {axisNumber axisValue eventTime} {} # This opens the joy device file and registers a 'fileevent' to respond to joy device state changes. proc openJoyDevice {joyDevicePath} { if [catch {set ::joyDevice [open $joyDevicePath {RDONLY BINARY}]}] { error "Couldn't open joy device '$joyDevicePath'" } fileevent $::joyDevice readable joyEventHandler } # This handles joy input events, reading the data from the joypad device file, and calling the appropriate handler procedure for the event. proc joyEventHandler {} { # Read the data from the joy device (look up linux 'joystick.h' online for more info) binary scan [read $::joyDevice 8] {i s c c} joy_time joy_value joy_type joy_number set joy_time [expr {$joy_time & 0xffffffff}] set joy_type [expr {$joy_type & 0xff}] set joy_number [expr {$joy_number & 0xff}] # Interpret the data switch -- $joy_type { 1 { # 1 : Joy button state change if {$joy_value} { joyButtonPressHandler $joy_number $joy_time } else { joyButtonReleaseHandler $joy_number $joy_time } } 2 { # 2 : Joy axis state change joyAxisMovedHandler $joy_number $joy_value $joy_time } 129 { # 129 (128 | 1) : Joy button init joyButtonInitHandler $joy_number $joy_time } 130 { # 130 (128 | 2) : Joy axis init joyAxisInitHandler $joy_number $joy_value $joy_time } default { puts stderr "Unknown joy event, type $joy_type" } } } # ------------------------------------ # --------- Demonstration ------------ # ------------------------------------ package require Tk tk appname "Joy device tester" pack [frame .f] -fill both -expand 1 pack [frame .f.buttons ] -side left -fill both -expand 1 pack [frame .f.axes ] -side right -fill both -expand 1 pack [label .l -anchor w -relief sunken -borderwidth 1] -side bottom -fill x # Keep track of last event time, for the timer info label set lastEventTime 0 proc updateTimer {t} { global lastEventTime .l configure -text "Last event: [expr { ($t - $lastEventTime) / 1000.0 }] seconds ago" set lastEventTime $t } # Create buttons proc joyButtonInitHandler {buttonNumber eventTime} { pack [button .f.buttons.b$buttonNumber -text "Button $buttonNumber" -background black -disabledforeground white -state disabled] updateTimer $eventTime } # Create axis sliders proc joyAxisInitHandler {axisNumber axisValue eventTime} { pack [scale .f.axes.a$axisNumber -label "Axis $axisNumber" -orient h -from -32768 -to 32767 -resolution 1 -state disabled -length 150] updateTimer $eventTime } # Update the visual state of buttons proc joyButtonPressHandler {buttonNumber eventTime} { .f.buttons.b$buttonNumber configure -disabledforeground black -background white updateTimer $eventTime } proc joyButtonReleaseHandler {buttonNumber eventTime} { .f.buttons.b$buttonNumber configure -disabledforeground white -background black updateTimer $eventTime } # Update the visual state of axis sliders proc joyAxisMovedHandler {axisNumber axisValue eventTime} { .f.axes.a$axisNumber configure -state normal .f.axes.a$axisNumber set $axisValue .f.axes.a$axisNumber configure -state disabled updateTimer $eventTime } # Open the joy device if {[llength $argv]} { set joyDevicePath [lindex $argv 0] } else { set joyDevicePath "/dev/input/js0" } openJoyDevice $joyDevicePath # We don't want the window size to keep changing to fit the width of the timer info label after 17 { wm geometry . [winfo reqwidth .]x[winfo reqheight .] }