gamepad 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dd64f2dc52c298fd48b2dbdb8dfb759eb5e8d972
4
+ data.tar.gz: af39e46a5869b99bd0834cad905014a32b78d758
5
+ SHA512:
6
+ metadata.gz: 80eb5e643ced7cf0f070291c16864eece8819c4ea3900503b30c979946c4d4a3ca0f1d2263787ee4bd6cb2bc805233e1e0717ff11cea63d5160718640f60a0c0
7
+ data.tar.gz: 0b32781da72d55daefc25527d5cf5e63de7f5ce64e4eccb3fb0e90c2c9c815b138cb4f7ab6aa4d531cc6d1225226a25fb97776cc858c4a37b0df7d2745c19bfc
data/.gitignore ADDED
@@ -0,0 +1,24 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ mkmf.log
19
+ gamepad.bundle
20
+ .DS_Store
21
+
22
+ notes
23
+ xusb*
24
+ log*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gamepad.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Will Jessop
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # gamepad
2
+
3
+ Gamepad is a gem I wrote to get the values of my xbox1 controller in a ruby program (to control my Parrot AR drone). I plan to use it for piloting my Parrot AR drone and other robotics stuff. It wasn't designed for use in game libraries, but it might work for you.
4
+
5
+ This is my first adventure into programming a Ruby c extention, and into c itself, so this lib is probably not safe to use in production, but then who needs to interface with an xbox1 controller in production…
6
+
7
+ Gamepad is a very early dev release made for me to play around with the xbox gamepad from Ruby, the API will likely change. Pull requests welcome.
8
+
9
+ ## Installation
10
+
11
+ On a mac:
12
+
13
+ brew install libusbx
14
+
15
+ On another platform YMMV. Add this line to your application's Gemfile:
16
+
17
+ gem 'gamepad'
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install gamepad
26
+
27
+ ## Usage
28
+
29
+ ````ruby
30
+ require 'gamepad'
31
+
32
+ gamepad = GameController::Xbox1.new
33
+ gamepad.on_changed do |values|
34
+ puts "Changed to #{values.inspect}"
35
+ end
36
+ ````
37
+
38
+ See examples/.
39
+
40
+ ## Contributing
41
+
42
+ 1. Fork it
43
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
44
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
45
+ 4. Push to the branch (`git push origin my-new-feature`)
46
+ 5. Create new Pull Request
47
+
48
+ ## TODO
49
+
50
+ - auto-detect xbox controllers being added/removed
51
+ - Handle more than one controller type
52
+ - display_xbox_status(libusb_device_handle *handle) crashes when the xbox controller is not connected
53
+ - ps1 controller
54
+ - Maybe use the async API of libusbx
55
+ - Signal handling is kind of odd
56
+
57
+ ## Author
58
+
59
+ * Will Jessop, @will_j, will@willj.net
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/extensiontask'
3
+ Rake::ExtensionTask.new('gamepad') do |ext|
4
+ ext.lib_dir = File.join(*['lib', 'gamepad'])
5
+ end
@@ -0,0 +1,9 @@
1
+ $:.unshift 'lib'
2
+ require 'gamepad'
3
+
4
+ gamepad = GameController::Xbox1.new
5
+ gamepad.on_changed do |values|
6
+ puts "Changed to #{values.inspect}"
7
+ end
8
+
9
+ puts "Done!"
@@ -0,0 +1,41 @@
1
+ ENV['RC_ARCHS'] = '' if RUBY_PLATFORM =~ /darwin/
2
+
3
+ require 'mkmf'
4
+
5
+ LIBDIR = RbConfig::CONFIG['libdir'] + '/gamepad'
6
+ INCLUDEDIR = RbConfig::CONFIG['includedir']
7
+ # RbConfig::CONFIG['CC'] = '/usr/bin/clang -v'
8
+
9
+ HEADER_DIRS = [
10
+ # Then search /usr/local for people that installed from source
11
+ '/usr/local/include',
12
+
13
+ # Check the ruby install locations
14
+ INCLUDEDIR,
15
+
16
+ # Finally fall back to /usr
17
+ '/usr/include'
18
+ ]
19
+
20
+ LIB_DIRS = [
21
+ # Then search /usr/local for people that installed from source
22
+ '/usr/local/lib',
23
+
24
+ # Check the ruby install locations
25
+ LIBDIR,
26
+
27
+ # Finally fall back to /usr
28
+ '/usr/lib'
29
+ ]
30
+
31
+ dir_config('gamepad', HEADER_DIRS, LIB_DIRS)
32
+
33
+ unless find_header('libusb-1.0/libusb.h')
34
+ abort "libusb is missing. please install libusb"
35
+ end
36
+
37
+ unless find_library('usb-1.0', 'libusb_init')
38
+ abort "libusb is missing. please install libusb"
39
+ end
40
+
41
+ create_makefile('gamepad/gamepad')
@@ -0,0 +1,8 @@
1
+ #include <gamepad.h>
2
+
3
+ VALUE m_game_controller;
4
+
5
+ void Init_gamepad() {
6
+ m_game_controller = rb_define_module("GameController");
7
+ Init_xbox_1(m_game_controller);
8
+ }
@@ -0,0 +1,9 @@
1
+ #ifndef RUBY_HID
2
+ #define RUBY_HID
3
+
4
+ #include <ruby.h>
5
+ #include <xbox_1.h>
6
+
7
+ extern VALUE m_game_controller;
8
+
9
+ #endif
@@ -0,0 +1,175 @@
1
+ #include <xbox_1.h>
2
+
3
+ int perr(char const *format, ...) {
4
+ va_list args;
5
+ int r;
6
+
7
+ va_start (args, format);
8
+ r = vfprintf(stderr, format, args);
9
+ va_end(args);
10
+
11
+ return r;
12
+ }
13
+
14
+ #define ERR_EXIT(errcode) do { perr(" %s\n", libusb_strerror((enum libusb_error)errcode)); return -1; } while (0)
15
+ #define CALL_CHECK(fcall) do { r=fcall; if (r < 0) ERR_EXIT(r); } while (0);
16
+ #define B(x) (((x)!=0)?1:0)
17
+ #define be_to_int32(buf) (((buf)[0]<<24)|((buf)[1]<<16)|((buf)[2]<<8)|(buf)[3])
18
+
19
+ #define RETRY_MAX 5
20
+ #define REQUEST_SENSE_LENGTH 0x12
21
+ #define INQUIRY_LENGTH 0x24
22
+ #define READ_CAPACITY_LENGTH 0x08
23
+
24
+ // HID Class-Specific Requests values. See section 7.2 of the HID specifications
25
+ #define HID_GET_REPORT 0x01
26
+ #define HID_GET_IDLE 0x02
27
+ #define HID_GET_PROTOCOL 0x03
28
+ #define HID_SET_REPORT 0x09
29
+ #define HID_SET_IDLE 0x0A
30
+ #define HID_SET_PROTOCOL 0x0B
31
+ #define HID_REPORT_TYPE_INPUT 0x01
32
+ #define HID_REPORT_TYPE_OUTPUT 0x02
33
+ #define HID_REPORT_TYPE_FEATURE 0x03
34
+
35
+
36
+ static int fetch_xbox_status(libusb_device_handle *handle, uint8_t input_report[20]);
37
+ static void loop_over_controller_status();
38
+
39
+ /*
40
+
41
+ Ruby definitions
42
+
43
+ */
44
+
45
+ VALUE method_on_changed(VALUE self);
46
+
47
+ void Init_xbox_1(VALUE module) {
48
+ VALUE c_xbox_1;
49
+ c_xbox_1 = rb_define_class_under(module, "Xbox1", rb_cObject);
50
+ rb_define_method(c_xbox_1, "on_changed", method_on_changed, 0);
51
+ }
52
+
53
+ VALUE method_on_changed(VALUE self) {
54
+ if (!rb_block_given_p())
55
+ rb_raise(rb_eArgError, "Expected block");
56
+
57
+ loop_over_controller_status();
58
+
59
+ // Never get here
60
+ return Qnil;
61
+ }
62
+
63
+ /*
64
+
65
+ Regular c functions
66
+
67
+ */
68
+
69
+ static bool run_usb_loop = true;
70
+
71
+ void signal_callback_handler(int signum) {
72
+ run_usb_loop = false;
73
+ }
74
+
75
+ /*
76
+
77
+ Yield a hash with the following data:
78
+
79
+ D-pad
80
+ Start
81
+ Back
82
+ Left Stick Press
83
+ Right Stick Press
84
+ A
85
+ B
86
+ X
87
+ Y
88
+ Black
89
+ White
90
+ Left Trigger
91
+ Right Trigger
92
+ Left Analog X
93
+ Left Analog Y
94
+ Right Analog X
95
+ Right Analog Y
96
+
97
+ */
98
+
99
+ static void loop_over_controller_status() {
100
+ // The default context is OK, we're not going to use more than one context: http://libusb.sourceforge.net/api-1.0/contexts.html
101
+ int ret = libusb_init(NULL);
102
+ if (ret != LIBUSB_SUCCESS) {
103
+ fprintf(stderr, "libusb_init returned %d\n", ret);
104
+ exit(1);
105
+ }
106
+
107
+ // libusb_set_debug(NULL, LIBUSB_LOG_LEVEL_DEBUG);
108
+
109
+ libusb_device_handle* handle = libusb_open_device_with_vid_pid(NULL, 0x045e, 0x0289);
110
+
111
+ int INPUT_REPORT_SIZE = 20;
112
+ int SIZEOF_ARRAY = INPUT_REPORT_SIZE * sizeof(uint8_t);
113
+
114
+ uint8_t input_report[INPUT_REPORT_SIZE];
115
+ uint8_t old_input_report[INPUT_REPORT_SIZE];
116
+
117
+ memset(input_report, 0, SIZEOF_ARRAY);
118
+ memset(old_input_report, 0, SIZEOF_ARRAY);
119
+
120
+ signal(SIGINT, signal_callback_handler);
121
+
122
+ while (run_usb_loop) {
123
+ fetch_xbox_status(handle, input_report);
124
+
125
+ // Compare the old and new values, we only want to yield if the values change
126
+ if (memcmp(input_report, old_input_report, SIZEOF_ARRAY) != 0) {
127
+
128
+ // Store the new values for comparison next time round
129
+ memcpy(old_input_report, input_report, SIZEOF_ARRAY);
130
+
131
+ VALUE values = rb_hash_new();
132
+ rb_hash_aset(values, ID2SYM(rb_intern("D-pad")), INT2NUM(input_report[2]&0x0F));
133
+ rb_hash_aset(values, ID2SYM(rb_intern("Start")), INT2NUM(B(input_report[2]&0x10)));
134
+ rb_hash_aset(values, ID2SYM(rb_intern("Back")), INT2NUM(B(input_report[2]&0x20)));
135
+ rb_hash_aset(values, ID2SYM(rb_intern("Left Stick Press")), INT2NUM(B(input_report[2]&0x40)));
136
+ rb_hash_aset(values, ID2SYM(rb_intern("Right Stick Press")), INT2NUM(B(input_report[2]&0x80)));
137
+
138
+ // Presure sensitive, values from 0 to 255
139
+ rb_hash_aset(values, ID2SYM(rb_intern("A")), INT2NUM(input_report[4]));
140
+ rb_hash_aset(values, ID2SYM(rb_intern("B")), INT2NUM(input_report[5]));
141
+ rb_hash_aset(values, ID2SYM(rb_intern("X")), INT2NUM(input_report[6]));
142
+ rb_hash_aset(values, ID2SYM(rb_intern("Y")), INT2NUM(input_report[7]));
143
+ rb_hash_aset(values, ID2SYM(rb_intern("Black")), INT2NUM(input_report[8]));
144
+ rb_hash_aset(values, ID2SYM(rb_intern("White")), INT2NUM(input_report[9]));
145
+
146
+ // Triggers are also pressure sensitive
147
+ rb_hash_aset(values, ID2SYM(rb_intern("Left Trigger")), INT2NUM(input_report[10]));
148
+ rb_hash_aset(values, ID2SYM(rb_intern("Right Trigger")), INT2NUM(input_report[11]));
149
+
150
+ // Left Analog stick x/y
151
+ rb_hash_aset(values, ID2SYM(rb_intern("Left Analog X")), INT2NUM((int16_t)((input_report[13]<<8)|input_report[12])));
152
+ rb_hash_aset(values, ID2SYM(rb_intern("Left Analog Y")), INT2NUM((int16_t)((input_report[15]<<8)|input_report[14])));
153
+
154
+ // Right Analog stick x/y
155
+ rb_hash_aset(values, ID2SYM(rb_intern("Right Analog X")), INT2NUM((int16_t)((input_report[17]<<8)|input_report[16])));
156
+ rb_hash_aset(values, ID2SYM(rb_intern("Right Analog Y")), INT2NUM((int16_t)((input_report[19]<<8)|input_report[18])));
157
+ rb_yield(values);
158
+ }
159
+
160
+ // Sleep for a while
161
+ struct timeval tv;
162
+ tv.tv_sec = 0;
163
+ tv.tv_usec = 100000;
164
+ select(0, NULL, NULL, NULL, &tv);
165
+ }
166
+
167
+ libusb_close(handle);
168
+ libusb_exit(NULL);
169
+ }
170
+
171
+ static int fetch_xbox_status(libusb_device_handle *handle, uint8_t input_report[20]) {
172
+ int r;
173
+ CALL_CHECK(libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE,HID_GET_REPORT, (HID_REPORT_TYPE_INPUT<<8)|0x00, 0, input_report, 20, 1000));
174
+ return 0;
175
+ }
@@ -0,0 +1,6 @@
1
+ #include <ruby.h>
2
+ #include <libusb-1.0/libusb.h>
3
+ #include <signal.h>
4
+ #include <stdbool.h>
5
+
6
+ void Init_xbox_1(VALUE module);
data/gamepad.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'gamepad/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "gamepad"
8
+ spec.version = Gamepad::VERSION
9
+ spec.authors = ["Will Jessop"]
10
+ spec.email = ["will@willj.net"]
11
+ spec.description = %q{Get values from an xbox1 gamepad}
12
+ spec.summary = %q{Get values from an xbox1 gamepad}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rake-compiler"
24
+ end
@@ -0,0 +1,3 @@
1
+ module Gamepad
2
+ VERSION = "0.0.1"
3
+ end
data/lib/gamepad.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'gamepad/version'
2
+ require 'gamepad/gamepad'
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gamepad
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Will Jessop
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake-compiler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Get values from an xbox1 gamepad
56
+ email:
57
+ - will@willj.net
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - examples/dump_values.rb
68
+ - ext/gamepad/extconf.rb
69
+ - ext/gamepad/gamepad.c
70
+ - ext/gamepad/gamepad.h
71
+ - ext/gamepad/xbox_1.c
72
+ - ext/gamepad/xbox_1.h
73
+ - gamepad.gemspec
74
+ - lib/gamepad.rb
75
+ - lib/gamepad/version.rb
76
+ homepage: ''
77
+ licenses:
78
+ - MIT
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.0.5
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: Get values from an xbox1 gamepad
100
+ test_files: []