A ruby library for observing HID game controllers. Currently supports
- Ubuntu Linux
Currently this only handles one controller at a time.
Warning: in the event of any rights issues, ruby_hid may have to change some rights down in the /sys and /dev folders. If you have a rights issue run:
RubyHid::Device.force_rights
Then provide a sudo-able password.
$ ruby scripts/devices.rb
This lists the devices known to ruby_hid. e.g.:
$ ruby scripts/devices.rb
/dev/input/by-id/usb-Saitek_ST200_Stick-event-joystick
/dev/input/by-id/usb-MY-POWER_CO._LTD._2In1_USB_Joystick-event-joystick
All of the other example scripts take part the device names as an argument. For instance:
$ ruby scripts/read.rb Saitek
$ ruby scripts/read.rb MY-POWER
But they can all be called without an argument, in this case they'll use the first one on the list.
$ ruby scripts/read.rb
This outputs the raw information from each event sent by the controller. e.g.:
$ ruby scripts/read.rb
2015-10-07T20:01:03+01:00 type: 1 code: 288 value: 1
2015-10-07T20:01:03+01:00 type: 1 code: 288 value: 0
2015-10-07T20:01:04+01:00 type: 1 code: 289 value: 1
2015-10-07T20:01:04+01:00 type: 1 code: 289 value: 0
2015-10-07T20:01:05+01:00 type: 3 code: 16 value: -1
2015-10-07T20:01:05+01:00 type: 3 code: 16 value: 0
2015-10-07T20:01:07+01:00 type: 3 code: 1 value: 99
2015-10-07T20:01:07+01:00 type: 3 code: 1 value: 85
2015-10-07T20:01:07+01:00 type: 3 code: 1 value: 73
2015-10-07T20:01:07+01:00 type: 3 code: 1 value: 61
$ ruby scripts/buttons.rb
This reads the button-type events, outputting them as names and values. e.g.:
$ ruby scripts/buttons.rb
btn_1 pushed: 1
btn_1 pushed: 0
l1 pushed: 1
l1 pushed: 0
select pushed: 1
select pushed: 0
$ ruby scripts/axes.rb
This reads the axis-type events, outputting them as names and values. e.g.:
$ ruby scripts/axes.rb
left_x changed: 125
left_x changed: 110
left_x changed: 101
left_x changed: 90
left_x changed: 74
left_x changed: 56
left_x changed: 38
left_x changed: 20
left_x changed: 1
left_x changed: 0
left_x changed: 10
left_x changed: 128
A very simple movement script with ASCII output. It reads the left hand stick of a joypad.
$ ruby scripts/axes.rb
+----------------------------------------+
| |
| |
| |
| |
| |
| |
| |
| |
| # |
| |
| |
| |
| |
| |
| |
+----------------------------------------+
x: 14 - y: 8
Include the ruby_hid library
require 'ruby_hid'
Buttons are binary controls, events on button changes can have one of two values:
- 1 - button down
- 0 - button up
You can find buttons with the RubyHid::Button class. Find the names or codeds in the EVENTS hash.
RubyHid::Button.find(297)
RubyHid::Button.find_by_name(:l1)
And define an event to be run
button = RubyHid::Button.find_by_name(:l1)
button.add_event(
lambda {|value|
if value == 1
puts "You pushed L1"
else
puts "Lou released L1"
end
}
)
You can debug the actions you've added to a button with trigger_events
# test button down event
button.trigger_events(1)
# test button up event
button.trigger_events(0)
How about getting it to run when you press the button?
The RubyHid::Device class is responsible for reading the raw input from the Buzz controllers via the linux terminal. Because it's reading a data stream, it needs to start a background process to allow it to work while other ruby code is operating.
You can start background process, which executes the events you added to the buttons, with start_watching.
device = RubyHid::Device.new
button = RubyHid::Button.find_by_name(:l1)
button.add_event(
lambda {|value|
if value == 1
puts "You pushed L1"
else
puts "You released L1"
end
}
)
device.start_watching
Note: This process will end when your ruby process ends, but if you
want to stop it before that stage, you can call device.stop_watching
If you want to do nothing other than watch the buttons, you may want to follow start_watching with an empty loop in order to keep your ruby process, and the the forked process which watches the controller alive.
device = RubyHid::Device.new(RubyHid::Device.list[0])
button = RubyHid::Button.find_by_name(:l1)
button.add_event(
lambda {|value|
if value == 1
puts "You pushed L1"
else
puts "You released L1"
end
}
)
device.start_watching20
loop do
sleep 1
end
Axes are continuous control events coming from a controller. Usually these are joysticks or throttles.
They differ from buttons in that they have a wider range of values, often the event is triggered a large number of times as the event is triggered.
They work in the same ways as buttons, only they are accessed via the RubyHid::Axis class.
Note: as the observers work on a separate process, and because axes send a large number of messages it is wise to keep the events on your axes as small as possible, and modify a shared object.
require 'ostruct'
@cursor = OpenStruct.new(
:x => 50.0, :y => 50.0,
:x_speed => 0, :y_speed => 0
)
axis = RubyHid::Axis.find_by_name(:left_y)
axis.add_event(
lambda do |value|
# value / 255 is from 0 to 1
@cursor.y_speed = ((value.to_f / 255.0) - 0.5)
end
)
axis = RubyHid::Axis.find_by_name(:left_x)
axis.add_event(
lambda do |value|
# value / 255 is from 0 to 1
@cursor.x_speed = ((value.to_f / 255.0) - 0.5)
end
)
device = RubyHid::Device.new(RubyHid::Device.list[0])
device.start_watching
loop do
# Observers have set x_speed and y_speed
# each step increments both dimensions by it's own speed
@cursor.x += @cursor.x_speed
@cursor.y += @cursor.y_speed
puts "x: #{@cursor.x.to_i.to_s.ljust(4)} - y: #{@cursor.y.to_i}"
sleep 0.1
end
Don't want to worry about setting up all those observers? The ruby_hid store is an object which, once initialised, holds all of the values from the first controller found.
This is ruby_hid with all the difficulty taken out.
require 'ruby_hid'
store = RubyHid::Store.new
loop do
puts store.to_h
sleep 0.1
end
You can access specific named attribute of the store like so:
store.left_x
store.left_y
store.dpad_x
store.dpad_y
store.btn_1
This returns raw values, as they are returned by the controller.
You can also access the controller values in a normalised form, where all values range from 0 to 1.
require 'ruby_hid'
store = RubyHid::Store.new
loop do
puts store.normalised_hash
sleep 0.1
end
You can access specific normalised attribute of the store like so:
store.normalise(:left_x)
store.normalise(:left_y)
store.normalise(:dpad_x)
store.normalise(:dpad_y)
store.normalise(:btn_1)
ruby_hid is currently in a very early beta, it has only been tested on Ubuntu Linux with a small number of game controllers. I'd love to hear if you managed to use it, what devices you've got to work and if you had any difficulty using the library.
Contact me on @MarmiteJunction or [email protected]
I'd love to have any complete improvements, these could include:
- Support for other Linux distros, or Max OS
- Bug fixes
- Mappings for buttons or axes on other devices
To contribute:
- Fork www.github.com/ajfaraday/ruby-hid
- Make your changes (preferably on a named fix or feature branch)
- Create a pull request back to the base repo
This repo includes a modified version of the devinput class from https://github.com/kamaradclimber/libdevinput which was forked from https://github.com/prullmann/libdevinput
Without that clone of libdev, written in ruby, I would not have been able to