ruby_hid 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENCE +22 -0
- data/README.md +340 -0
- data/lib/ruby_hid/axis.rb +44 -0
- data/lib/ruby_hid/button.rb +48 -0
- data/lib/ruby_hid/device.rb +149 -0
- data/lib/ruby_hid/observer.rb +174 -0
- data/lib/ruby_hid.rb +10 -0
- metadata +51 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: aa992e562d3a8c3cf63778551f1343426ffddf5b
|
4
|
+
data.tar.gz: 3f95ab6dc3e1af2b4eb455011efe18c19d45dae2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bfcb6375e83f35e706e75d9e681182d78e934ca5885a9891a3bf569014d8d63cfbcc2516e606b21638f4b90faca6080ec5fb7189fdf69ddd066d09ff33f22d01
|
7
|
+
data.tar.gz: fbc72ad1244eaff5e9d56b4c599b8c820137d0355fe694a52acf9ac230cc71399d1be1ab9030c1c712d21afc206e3c659e34019c349dc9b2a0f22f91becfcd7d
|
data/LICENCE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Andrew Faraday
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
22
|
+
|
data/README.md
ADDED
@@ -0,0 +1,340 @@
|
|
1
|
+
ruby-hid
|
2
|
+
==========
|
3
|
+
|
4
|
+
A ruby library for observing HID game controllers. Currently supports
|
5
|
+
|
6
|
+
* Ubuntu Linux
|
7
|
+
|
8
|
+
Currently this only handles one controller at a time.
|
9
|
+
|
10
|
+
*Warning:* ruby_hid has to change some rights down in the /sys and /dev
|
11
|
+
folders of Linux in order to access the kernel. You will be asked for
|
12
|
+
your password in order to use ruby_hid.
|
13
|
+
|
14
|
+
Example Scripts
|
15
|
+
===============
|
16
|
+
|
17
|
+
devices.rb
|
18
|
+
----------
|
19
|
+
|
20
|
+
```bash
|
21
|
+
$ ruby scripts/devices.rb
|
22
|
+
```
|
23
|
+
|
24
|
+
This lists the devices known to ruby_hid. e.g.:
|
25
|
+
|
26
|
+
```bash
|
27
|
+
$ ruby scripts/devices.rb
|
28
|
+
/dev/input/by-id/usb-Saitek_ST200_Stick-event-joystick
|
29
|
+
/dev/input/by-id/usb-MY-POWER_CO._LTD._2In1_USB_Joystick-event-joystick
|
30
|
+
```
|
31
|
+
|
32
|
+
All of the other example scripts take part the device names as
|
33
|
+
an argument. For instance:
|
34
|
+
|
35
|
+
```bash
|
36
|
+
$ ruby scripts/read.rb Saitek
|
37
|
+
$ ruby scripts/read.rb MY-POWER
|
38
|
+
```
|
39
|
+
|
40
|
+
But they can all be called without an argument, in
|
41
|
+
this case they'll use the first one on the list.
|
42
|
+
|
43
|
+
-----------------------
|
44
|
+
|
45
|
+
read.rb
|
46
|
+
-------
|
47
|
+
|
48
|
+
```bash
|
49
|
+
$ ruby scripts/read.rb
|
50
|
+
```
|
51
|
+
|
52
|
+
This outputs the raw information from each event sent
|
53
|
+
by the controller. e.g.:
|
54
|
+
|
55
|
+
```bash
|
56
|
+
$ ruby scripts/read.rb
|
57
|
+
2015-10-07T20:01:03+01:00 type: 1 code: 288 value: 1
|
58
|
+
2015-10-07T20:01:03+01:00 type: 1 code: 288 value: 0
|
59
|
+
2015-10-07T20:01:04+01:00 type: 1 code: 289 value: 1
|
60
|
+
2015-10-07T20:01:04+01:00 type: 1 code: 289 value: 0
|
61
|
+
2015-10-07T20:01:05+01:00 type: 3 code: 16 value: -1
|
62
|
+
2015-10-07T20:01:05+01:00 type: 3 code: 16 value: 0
|
63
|
+
2015-10-07T20:01:07+01:00 type: 3 code: 1 value: 99
|
64
|
+
2015-10-07T20:01:07+01:00 type: 3 code: 1 value: 85
|
65
|
+
2015-10-07T20:01:07+01:00 type: 3 code: 1 value: 73
|
66
|
+
2015-10-07T20:01:07+01:00 type: 3 code: 1 value: 61
|
67
|
+
```
|
68
|
+
|
69
|
+
buttons.rb
|
70
|
+
----------
|
71
|
+
|
72
|
+
```bash
|
73
|
+
$ ruby scripts/buttons.rb
|
74
|
+
```
|
75
|
+
|
76
|
+
This reads the button-type events, outputting them as
|
77
|
+
names and values. e.g.:
|
78
|
+
|
79
|
+
```bash
|
80
|
+
$ ruby scripts/buttons.rb
|
81
|
+
btn_1 pushed: 1
|
82
|
+
btn_1 pushed: 0
|
83
|
+
l1 pushed: 1
|
84
|
+
l1 pushed: 0
|
85
|
+
select pushed: 1
|
86
|
+
select pushed: 0
|
87
|
+
```
|
88
|
+
|
89
|
+
axes.rb
|
90
|
+
----------
|
91
|
+
|
92
|
+
```bash
|
93
|
+
$ ruby scripts/axes.rb
|
94
|
+
```
|
95
|
+
|
96
|
+
This reads the axis-type events, outputting them as
|
97
|
+
names and values. e.g.:
|
98
|
+
|
99
|
+
```bash
|
100
|
+
$ ruby scripts/axes.rb
|
101
|
+
left_x changed: 125
|
102
|
+
left_x changed: 110
|
103
|
+
left_x changed: 101
|
104
|
+
left_x changed: 90
|
105
|
+
left_x changed: 74
|
106
|
+
left_x changed: 56
|
107
|
+
left_x changed: 38
|
108
|
+
left_x changed: 20
|
109
|
+
left_x changed: 1
|
110
|
+
left_x changed: 0
|
111
|
+
left_x changed: 10
|
112
|
+
left_x changed: 128
|
113
|
+
```
|
114
|
+
|
115
|
+
move_cursor.rb
|
116
|
+
--------------
|
117
|
+
|
118
|
+
A very simple movement script with ASCII output.
|
119
|
+
It reads the left hand stick of a joypad.
|
120
|
+
|
121
|
+
```bash
|
122
|
+
$ ruby scripts/axes.rb
|
123
|
+
+----------------------------------------+
|
124
|
+
| |
|
125
|
+
| |
|
126
|
+
| |
|
127
|
+
| |
|
128
|
+
| |
|
129
|
+
| |
|
130
|
+
| |
|
131
|
+
| |
|
132
|
+
| # |
|
133
|
+
| |
|
134
|
+
| |
|
135
|
+
| |
|
136
|
+
| |
|
137
|
+
| |
|
138
|
+
| |
|
139
|
+
+----------------------------------------+
|
140
|
+
x: 14 - y: 8
|
141
|
+
```
|
142
|
+
|
143
|
+
Using it in your code
|
144
|
+
=====================
|
145
|
+
|
146
|
+
Button Events
|
147
|
+
-------------
|
148
|
+
|
149
|
+
Include the ruby_hid library
|
150
|
+
|
151
|
+
`require 'ruby_hid'`
|
152
|
+
|
153
|
+
Buttons are binary controls, events on button changes can
|
154
|
+
have one of two values:
|
155
|
+
|
156
|
+
* 1 - button down
|
157
|
+
* 0 - button up
|
158
|
+
|
159
|
+
You can find buttons with the RubyHid::Button class. Find
|
160
|
+
the names or codeds in the EVENTS hash.
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
RubyHid::Button.find(297)
|
164
|
+
RubyHid::Button.find_by_name(:l1)
|
165
|
+
```
|
166
|
+
|
167
|
+
And define an event to be run
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
button = RubyHid::Button.find_by_name(:l1)
|
171
|
+
button.add_event(
|
172
|
+
lambda {|value|
|
173
|
+
if value == 1
|
174
|
+
puts "You pushed L1"
|
175
|
+
else
|
176
|
+
puts "Lou released L1"
|
177
|
+
end
|
178
|
+
}
|
179
|
+
)
|
180
|
+
```
|
181
|
+
|
182
|
+
You can debug the actions you've added to a button with trigger_events
|
183
|
+
|
184
|
+
```ruby
|
185
|
+
# test button down event
|
186
|
+
button.trigger_events(1)
|
187
|
+
# test button up event
|
188
|
+
button.trigger_events(0)
|
189
|
+
```
|
190
|
+
|
191
|
+
How about getting it to run when you press the button?
|
192
|
+
|
193
|
+
The RubyHid::Device class is responsible for reading the raw input
|
194
|
+
from the Buzz controllers via the linux terminal. Because it's reading
|
195
|
+
a data stream, it needs to start a background process to allow it to
|
196
|
+
work while other ruby code is operating.
|
197
|
+
|
198
|
+
You can start background process, which executes the events you added
|
199
|
+
to the buttons, with start_watching.
|
200
|
+
|
201
|
+
```ruby
|
202
|
+
device = RubyHid::Device.new
|
203
|
+
|
204
|
+
button = RubyHid::Button.find_by_name(:l1)
|
205
|
+
button.add_event(
|
206
|
+
lambda {|value|
|
207
|
+
if value == 1
|
208
|
+
puts "You pushed L1"
|
209
|
+
else
|
210
|
+
puts "You released L1"
|
211
|
+
end
|
212
|
+
}
|
213
|
+
)
|
214
|
+
|
215
|
+
device.start_watching
|
216
|
+
```
|
217
|
+
|
218
|
+
Note: This process will end when your ruby process ends, but if you
|
219
|
+
want to stop it before that stage, you can call `device.stop_watching`
|
220
|
+
|
221
|
+
If you want to do nothing other than watch the buttons, you may want
|
222
|
+
to follow start_watching with an empty loop in order to keep your
|
223
|
+
ruby process, and the the forked process which watches the controller
|
224
|
+
alive.
|
225
|
+
|
226
|
+
```ruby
|
227
|
+
device = RubyHid::Device.new(RubyHid::Device.list[0])
|
228
|
+
|
229
|
+
button = RubyHid::Button.find_by_name(:l1)
|
230
|
+
button.add_event(
|
231
|
+
lambda {|value|
|
232
|
+
if value == 1
|
233
|
+
puts "You pushed L1"
|
234
|
+
else
|
235
|
+
puts "You released L1"
|
236
|
+
end
|
237
|
+
}
|
238
|
+
)
|
239
|
+
|
240
|
+
device.start_watching20
|
241
|
+
|
242
|
+
loop do
|
243
|
+
sleep 1
|
244
|
+
end
|
245
|
+
```
|
246
|
+
|
247
|
+
Axis Events
|
248
|
+
-----------
|
249
|
+
|
250
|
+
Axes are continuous control events coming from a controller. Usually
|
251
|
+
these are joysticks or throttles.
|
252
|
+
|
253
|
+
They differ from buttons in that they have a wider range of values,
|
254
|
+
often the event is triggered a large number of times as the event is
|
255
|
+
triggered.
|
256
|
+
|
257
|
+
They work in the same ways as buttons, only they are accessed via the
|
258
|
+
RubyHid::Axis class.
|
259
|
+
|
260
|
+
*Note:* as the observers work on a separate process, and because axes
|
261
|
+
send a large number of messages it is wise to keep the events on your
|
262
|
+
axes as small as possible, and modify a shared object.
|
263
|
+
|
264
|
+
```ruby
|
265
|
+
require 'ostruct'
|
266
|
+
require_relative '../lib/ruby_hid.rb'
|
267
|
+
|
268
|
+
@cursor = OpenStruct.new(
|
269
|
+
:x => 50.0, :y => 50.0,
|
270
|
+
:x_speed => 0, :y_speed => 0
|
271
|
+
)
|
272
|
+
|
273
|
+
axis = RubyHid::Axis.find_by_name(:left_y)
|
274
|
+
axis.add_event(
|
275
|
+
lambda do |value|
|
276
|
+
# value / 255 is from 0 to 1
|
277
|
+
@cursor.y_speed = ((value.to_f / 255.0) - 0.5)
|
278
|
+
end
|
279
|
+
)
|
280
|
+
|
281
|
+
axis = RubyHid::Axis.find_by_name(:left_x)
|
282
|
+
axis.add_event(
|
283
|
+
lambda do |value|
|
284
|
+
# value / 255 is from 0 to 1
|
285
|
+
@cursor.x_speed = ((value.to_f / 255.0) - 0.5)
|
286
|
+
end
|
287
|
+
)
|
288
|
+
|
289
|
+
device = RubyHid::Device.new(RubyHid::Device.list[0])
|
290
|
+
device.start_watching
|
291
|
+
|
292
|
+
loop do
|
293
|
+
# Observers have set x_speed and y_speed
|
294
|
+
# each step increments both dimensions by it's own speed
|
295
|
+
@cursor.x += @cursor.x_speed
|
296
|
+
@cursor.y += @cursor.y_speed
|
297
|
+
|
298
|
+
puts "x: #{@cursor.x.to_i.to_s.ljust(4)} - y: #{@cursor.y.to_i}"
|
299
|
+
sleep 0.1
|
300
|
+
end
|
301
|
+
```
|
302
|
+
|
303
|
+
Helping Out
|
304
|
+
===========
|
305
|
+
|
306
|
+
Testing
|
307
|
+
-------
|
308
|
+
|
309
|
+
ruby_hid is currently in a very early beta, it has only been tested
|
310
|
+
on Ubuntu Linux with a small number of game controllers. I'd love
|
311
|
+
to hear if you managed to use it, what devices you've got to work and
|
312
|
+
if you had any difficulty using the library.
|
313
|
+
|
314
|
+
Contact me on @MarmiteJunction or andrewfaraday@hotmail.co.uk
|
315
|
+
|
316
|
+
Contributing
|
317
|
+
------------
|
318
|
+
|
319
|
+
I'd love to have any complete improvements, these could include:
|
320
|
+
|
321
|
+
* Support for other Linux distros, or Max OS
|
322
|
+
* Bug fixes
|
323
|
+
* Mappings for buttons or axes on other devices
|
324
|
+
|
325
|
+
To contribute:
|
326
|
+
|
327
|
+
1. Fork www.github.com/ajfaraday/ruby-hid
|
328
|
+
2. Make your changes (preferably on a named fix or feature branch)
|
329
|
+
3. Create a pull request back to the base repo
|
330
|
+
|
331
|
+
Acknowledgements
|
332
|
+
===============
|
333
|
+
|
334
|
+
This repo includes a modified version of the devinput class from
|
335
|
+
https://github.com/kamaradclimber/libdevinput
|
336
|
+
which was forked from
|
337
|
+
https://github.com/prullmann/libdevinput
|
338
|
+
|
339
|
+
Without that clone of libdev, written in ruby, I would not have been
|
340
|
+
able to
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module RubyHid
|
2
|
+
|
3
|
+
#
|
4
|
+
# An axis is a continuous control coming from a HID device.
|
5
|
+
# These are most often the output from joysticks.
|
6
|
+
#
|
7
|
+
# The most common values for axes range from 0 to 255.
|
8
|
+
# In this case the central (resting) position is 128.
|
9
|
+
#
|
10
|
+
# Axis includes d-pad axes, which have a distinctly
|
11
|
+
# different set of values.
|
12
|
+
#
|
13
|
+
# * -1 up or left
|
14
|
+
# * 0 centre
|
15
|
+
# * 1 down or right
|
16
|
+
#
|
17
|
+
class Axis < RubyHid::Observer
|
18
|
+
|
19
|
+
#
|
20
|
+
# List of Axes, with names
|
21
|
+
#
|
22
|
+
# Naming is mostly the stick name followed
|
23
|
+
# by x or y for the direction.
|
24
|
+
#
|
25
|
+
EVENTS = {
|
26
|
+
0 => :left_x,
|
27
|
+
1 => :left_y,
|
28
|
+
2 => :right_x,
|
29
|
+
5 => :right_y,
|
30
|
+
6 => :throttle,
|
31
|
+
16 => :dpad_x,
|
32
|
+
17 => :dpad_y
|
33
|
+
}
|
34
|
+
|
35
|
+
#
|
36
|
+
# Quick summary of the button
|
37
|
+
#
|
38
|
+
def to_s
|
39
|
+
"Axis: #{code} - #{name}"
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module RubyHid
|
2
|
+
|
3
|
+
#
|
4
|
+
# Button objects are observers of buttons on a controller.
|
5
|
+
# Buttons which are currently available are listed, by name
|
6
|
+
# in the EVENTS constant.
|
7
|
+
#
|
8
|
+
# Buttons can have 2 values passed to each event:
|
9
|
+
#
|
10
|
+
# * 1 - button down event
|
11
|
+
# * 0 - button up event
|
12
|
+
#
|
13
|
+
# To set the actions for a button use add_event:
|
14
|
+
#
|
15
|
+
# button = Button.find_by_name(:btn_1)
|
16
|
+
# button.add_event(lambda{ |value| puts "Button 1: #{value}" })
|
17
|
+
#
|
18
|
+
#
|
19
|
+
class Button < RubyHid::Observer
|
20
|
+
|
21
|
+
#
|
22
|
+
# List of button types, with names
|
23
|
+
#
|
24
|
+
EVENTS = {
|
25
|
+
# joy pads
|
26
|
+
288 => :btn_1,
|
27
|
+
289 => :btn_2,
|
28
|
+
290 => :btn_3,
|
29
|
+
291 => :btn_4,
|
30
|
+
292 => :l1,
|
31
|
+
293 => :r1,
|
32
|
+
294 => :l2,
|
33
|
+
295 => :r2,
|
34
|
+
296 => :select,
|
35
|
+
297 => :start,
|
36
|
+
298 => :l_stick,
|
37
|
+
299 => :r_stick
|
38
|
+
}
|
39
|
+
|
40
|
+
#
|
41
|
+
# Quick summary of the button
|
42
|
+
#
|
43
|
+
def to_s
|
44
|
+
"Button: #{code} - #{name}"
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
class NoFileSpecifiedError < RuntimeError
|
2
|
+
|
3
|
+
end
|
4
|
+
|
5
|
+
module RubyHid
|
6
|
+
#
|
7
|
+
# The main interface for the Buzz controllers. Primarily
|
8
|
+
# used to monitor key pushes and trigger events. Keep a single
|
9
|
+
# instance of the class:
|
10
|
+
#
|
11
|
+
# `RubyHid::Device.new`
|
12
|
+
#
|
13
|
+
# The `each` method exposes events directly as they come in
|
14
|
+
#
|
15
|
+
# `device.each { |event| puts event }`
|
16
|
+
#
|
17
|
+
# The `start_watching` method starts a background job which
|
18
|
+
# runs the events bound to each button via the RubyHid::Button
|
19
|
+
# class. You can end this worker with `stop_watching`.
|
20
|
+
#
|
21
|
+
class Device
|
22
|
+
|
23
|
+
#
|
24
|
+
# Event types we're interested in, used to filter out meta-data.
|
25
|
+
#
|
26
|
+
# 1 - button (0, 1)
|
27
|
+
# 3 - axis (usually 0 - 255, centred on 128)
|
28
|
+
#
|
29
|
+
BUTTON_TYPE = 1
|
30
|
+
AXIS_TYPE = 3
|
31
|
+
|
32
|
+
ALLOWED_EVENT_TYPES = [
|
33
|
+
BUTTON_TYPE,
|
34
|
+
AXIS_TYPE
|
35
|
+
]
|
36
|
+
|
37
|
+
#
|
38
|
+
# List possible devices from /dev/input/by-id/
|
39
|
+
#
|
40
|
+
# Or, list devices containing a string with search_term argument
|
41
|
+
#
|
42
|
+
def Device.list(search_term=nil)
|
43
|
+
if search_term
|
44
|
+
Dir["/dev/input/by-id/*#{search_term}*event-joystick*"]
|
45
|
+
else
|
46
|
+
Dir['/dev/input/by-id/*event-joystick*']
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
require 'time'
|
51
|
+
|
52
|
+
# The worker is a thread which is watching the device
|
53
|
+
attr_accessor :worker
|
54
|
+
|
55
|
+
Event = Struct.new(:tv_sec, :tv_usec, :type, :code, :value)
|
56
|
+
# open Event class and add some convenience methods
|
57
|
+
#
|
58
|
+
# Holds the un-packed data parsed from the raw input from the buzz controller.
|
59
|
+
class Event
|
60
|
+
def time;
|
61
|
+
Time.at(tv_sec)
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_s
|
65
|
+
type_s = type.to_s
|
66
|
+
code_s = code.to_s
|
67
|
+
value_s = value.to_s
|
68
|
+
"#{time.iso8601} type: #{type_s} code: #{code_s} value: #{value_s}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
#
|
73
|
+
# Initialise device, getting event file from /dev/input/by-id/
|
74
|
+
#
|
75
|
+
def initialize(filename=nil, block_size=24)
|
76
|
+
raise NoFileSpecifiedError if filename.nil?
|
77
|
+
@dev = File.open(filename)
|
78
|
+
@block_size = block_size
|
79
|
+
rescue NoFileSpecifiedError, Errno::ENOENT => er
|
80
|
+
puts "Could not find device: are your controllers plugged in?"
|
81
|
+
raise er
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
# The format string which RubyHid uses to decode raw data.
|
86
|
+
#
|
87
|
+
def format
|
88
|
+
@format ||= case @block_size
|
89
|
+
when 16
|
90
|
+
'llSSl'
|
91
|
+
when 24
|
92
|
+
'qqSSl'
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
#
|
97
|
+
# Read a single block.
|
98
|
+
#
|
99
|
+
def read
|
100
|
+
bin = @dev.read @block_size
|
101
|
+
Event.new *bin.unpack(format)
|
102
|
+
end
|
103
|
+
|
104
|
+
#
|
105
|
+
# Expose each event to a block of code as it comes in.
|
106
|
+
#
|
107
|
+
def each
|
108
|
+
begin
|
109
|
+
loop do
|
110
|
+
event = read
|
111
|
+
if event
|
112
|
+
next unless ALLOWED_EVENT_TYPES.include?(event.type)
|
113
|
+
yield event
|
114
|
+
end
|
115
|
+
end
|
116
|
+
rescue Errno::ENODEV
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
#
|
121
|
+
# Start a background worker which scans input file
|
122
|
+
# and triggers any events bound to each one.
|
123
|
+
#
|
124
|
+
def start_watching
|
125
|
+
return if @worker
|
126
|
+
@worker = Thread.new do
|
127
|
+
loop do
|
128
|
+
event = read
|
129
|
+
next unless ALLOWED_EVENT_TYPES.include?(event.type)
|
130
|
+
case event.type
|
131
|
+
when BUTTON_TYPE
|
132
|
+
RubyHid::Button.trigger_event(event.code, event.value)
|
133
|
+
when AXIS_TYPE
|
134
|
+
RubyHid::Axis.trigger_event(event.code, event.value)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
#
|
141
|
+
# Stop the background worker, release it's resources.
|
142
|
+
#
|
143
|
+
def stop_watching
|
144
|
+
@worker.kill
|
145
|
+
@worker = nil
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
module RubyHid
|
2
|
+
|
3
|
+
#
|
4
|
+
# Observer parent class, shared code used by all the
|
5
|
+
# controller observer classes:
|
6
|
+
#
|
7
|
+
# * Button
|
8
|
+
#
|
9
|
+
# Shared functionality keeps an in-memory array of
|
10
|
+
# each controller event which has been referred to.
|
11
|
+
#
|
12
|
+
class Observer
|
13
|
+
|
14
|
+
#
|
15
|
+
# Dummy events hash, this should be set in
|
16
|
+
# the individual observer classes.
|
17
|
+
#
|
18
|
+
EVENTS = {}
|
19
|
+
|
20
|
+
@@observers = []
|
21
|
+
|
22
|
+
# events will be an array of lambdas
|
23
|
+
attr_accessor :name, :code, :events
|
24
|
+
|
25
|
+
#
|
26
|
+
# Create an observer object to observe all of this kind of observer
|
27
|
+
#
|
28
|
+
# If this isn't called directly, it will be created as
|
29
|
+
# required when find or find_by_name are called.
|
30
|
+
#
|
31
|
+
def self.build
|
32
|
+
self::EVENTS.each { |code, name| self.new(code, name) }
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# Initialize a control observer
|
37
|
+
#
|
38
|
+
# Arguments:
|
39
|
+
#
|
40
|
+
# * code - Integer, the event code generated by this button
|
41
|
+
# * name - Symbol, the name of the button
|
42
|
+
#
|
43
|
+
def initialize(code, name)
|
44
|
+
@code = code
|
45
|
+
@name = name
|
46
|
+
@events = []
|
47
|
+
@@observers << self
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Find an observer of this type by its event code.
|
52
|
+
# Used by trigger_key to find an observer when
|
53
|
+
# its controller is used.
|
54
|
+
#
|
55
|
+
# Arguments:
|
56
|
+
#
|
57
|
+
# * code - Integer, event code to retrieve button by.
|
58
|
+
#
|
59
|
+
def self.find(code)
|
60
|
+
btn = @@observers.detect { |b| b.code == code }
|
61
|
+
if btn.nil?
|
62
|
+
btn = self.make_from_code(code)
|
63
|
+
end
|
64
|
+
btn
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# Create an observer object of this type from a known code.
|
69
|
+
# used by find when the observer has not been initialised.
|
70
|
+
#
|
71
|
+
# Arguments:
|
72
|
+
#
|
73
|
+
# * code - Integer, event code to retrieve button by.
|
74
|
+
#
|
75
|
+
def self.make_from_code(code)
|
76
|
+
name = EVENTS[code]
|
77
|
+
if name
|
78
|
+
self.new(code, name)
|
79
|
+
else
|
80
|
+
nil
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
# Find an observer of this type by its event code.
|
86
|
+
#
|
87
|
+
# Arguments:
|
88
|
+
#
|
89
|
+
# * name - Symbol, a known button name (from BUTTONS)
|
90
|
+
#
|
91
|
+
def self.find_by_name(name)
|
92
|
+
btn = @@observers.detect { |b| b.name == name }
|
93
|
+
if btn.nil?
|
94
|
+
btn = self.make_from_name(name)
|
95
|
+
end
|
96
|
+
btn
|
97
|
+
end
|
98
|
+
|
99
|
+
#
|
100
|
+
# Create an observer of this type from a known name.
|
101
|
+
# Used in find_by_name when the observer has not been
|
102
|
+
# initialised.
|
103
|
+
#
|
104
|
+
# Arguments:
|
105
|
+
#
|
106
|
+
# * name - symbol, a known button name
|
107
|
+
#
|
108
|
+
def self.make_from_name(name)
|
109
|
+
code, btn_name = self::EVENTS.detect { |code, btn_name| btn_name == name }
|
110
|
+
if code
|
111
|
+
self.new(code, name)
|
112
|
+
else
|
113
|
+
nil
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
#
|
119
|
+
# Add a process to be triggered when this observers
|
120
|
+
# controller is changed.
|
121
|
+
#
|
122
|
+
# Arguments:
|
123
|
+
#
|
124
|
+
# * proc - Proc, ruby method to be called, without arguments on button press.
|
125
|
+
#
|
126
|
+
def add_event(proc)
|
127
|
+
@events << proc
|
128
|
+
end
|
129
|
+
|
130
|
+
#
|
131
|
+
# Trigger every proc in the @events array.
|
132
|
+
#
|
133
|
+
def trigger_events(value=nil)
|
134
|
+
@events.each do |event|
|
135
|
+
event.call(value)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
#
|
140
|
+
# Find an observer of this type and run all
|
141
|
+
# of it's events.
|
142
|
+
#
|
143
|
+
# Used by RubyHid::Device when a control change
|
144
|
+
# is detected.
|
145
|
+
#
|
146
|
+
# Arguments:
|
147
|
+
#
|
148
|
+
# * code - Integer, event code to retrieve button by.
|
149
|
+
#
|
150
|
+
def self.trigger_event(code, value=nil)
|
151
|
+
btn = self.find(code)
|
152
|
+
if btn
|
153
|
+
btn.trigger_events(value)
|
154
|
+
else
|
155
|
+
puts unmapped_event_message(code)
|
156
|
+
end
|
157
|
+
rescue => er
|
158
|
+
puts "Error in observer #{code} event: #{er.message}"
|
159
|
+
puts er.backtrace
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.unmapped_event_message(code)
|
163
|
+
<<-TEXT
|
164
|
+
==============================================================
|
165
|
+
#{self} with event code #{code} has not been mapped.
|
166
|
+
Please add it to #{self}::EVENTS with a name.
|
167
|
+
==============================================================
|
168
|
+
|
169
|
+
TEXT
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
data/lib/ruby_hid.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
`sudo chmod 777 /sys/class/leds/*/brightness`
|
2
|
+
`sudo chmod 777 /dev/input/event*`
|
3
|
+
|
4
|
+
require_relative './ruby_hid/device.rb'
|
5
|
+
require_relative './ruby_hid/observer.rb'
|
6
|
+
require_relative './ruby_hid/button.rb'
|
7
|
+
require_relative './ruby_hid/axis.rb'
|
8
|
+
|
9
|
+
RubyHid::Axis.build
|
10
|
+
RubyHid::Button.build
|
metadata
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby_hid
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrew Faraday
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-10-07 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: HID device observer library for Ruby applications. Currently only ubuntu
|
14
|
+
Linux distributions.
|
15
|
+
email: andrewfaraday@hotmail.co.uk
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- LICENCE
|
21
|
+
- README.md
|
22
|
+
- lib/ruby_hid.rb
|
23
|
+
- lib/ruby_hid/axis.rb
|
24
|
+
- lib/ruby_hid/button.rb
|
25
|
+
- lib/ruby_hid/device.rb
|
26
|
+
- lib/ruby_hid/observer.rb
|
27
|
+
homepage: https://github.com/AJFaraday/ruby-hid
|
28
|
+
licenses:
|
29
|
+
- MIT
|
30
|
+
metadata: {}
|
31
|
+
post_install_message:
|
32
|
+
rdoc_options: []
|
33
|
+
require_paths:
|
34
|
+
- lib
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 2.0.0
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
requirements: []
|
46
|
+
rubyforge_project:
|
47
|
+
rubygems_version: 2.4.6
|
48
|
+
signing_key:
|
49
|
+
specification_version: 4
|
50
|
+
summary: HID game controller support for Ruby in Linux
|
51
|
+
test_files: []
|