myhidapi 1.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/CHANGELOG.md +6 -0
- data/Manifest.txt +10 -0
- data/README.md +73 -0
- data/Rakefile +41 -0
- data/ext/myhidapi/extconf.rb +25 -0
- data/ext/myhidapi/myhidapi.c +178 -0
- data/lib/myhidapi.rb +28 -0
- data/sample/kbprog.rb +190 -0
- data/sample/set_hsv.rb +21 -0
- data/test/test_myhidapi.rb +33 -0
- metadata +110 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: adfdddd71f381dfa83086b83af2a81dc686adf21df076b0286e253eb002491e1
|
4
|
+
data.tar.gz: 712d3badf64f7fdae9d6e6fbb8ebfda805f1668d83539a5ac6761d9a39b9198d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8a965240dbb7b7a760626bf7827beded3544c13629c021cb5980674ebecea5255a8734e22093aafded0fdfcf46c17b0e8c3a2f345262d18590a74564c9c523d4
|
7
|
+
data.tar.gz: 10d73dd3d377bc809e6d670de618dfa22459197ddf076630f3732a6d3815ad66bccd6cdbcafb3509b7b73f320d8a3e7580edd6052ab3b2f2265cdb38f83fc461
|
data/CHANGELOG.md
ADDED
data/Manifest.txt
ADDED
data/README.md
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# MyHIDAPI
|
2
|
+
|
3
|
+
* https://github.com/tenderlove/myhidapi
|
4
|
+
|
5
|
+
## DESCRIPTION:
|
6
|
+
|
7
|
+
This is a small wrapper around HIDAPI. I couldn't get other HIDAPI wrappers to
|
8
|
+
work, so I wrote this one. I'm using it to communicate with my keyboard, so
|
9
|
+
it really only supports enough of the HIDAPI to do that.
|
10
|
+
|
11
|
+
## FEATURES/PROBLEMS:
|
12
|
+
|
13
|
+
* Incomplete
|
14
|
+
* No tests
|
15
|
+
* Seems to work (for me)
|
16
|
+
|
17
|
+
## SYNOPSIS:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
devices = MyHIDAPI.enumerate 0x0, 0x0
|
21
|
+
dev = devices.find { |dev| dev.product_string == "ErgoDox EZ" }
|
22
|
+
|
23
|
+
handle = dev.open
|
24
|
+
|
25
|
+
while !handle
|
26
|
+
p "retry"
|
27
|
+
handle = dev.open
|
28
|
+
end
|
29
|
+
|
30
|
+
p handle
|
31
|
+
|
32
|
+
buf = [0x0, 0x3, 35]
|
33
|
+
loop do
|
34
|
+
break if handle.write buf.pack('C*')
|
35
|
+
end
|
36
|
+
puts "done writing"
|
37
|
+
|
38
|
+
buf = handle.read_timeout 1, 500
|
39
|
+
p buf
|
40
|
+
```
|
41
|
+
|
42
|
+
## REQUIREMENTS:
|
43
|
+
|
44
|
+
This depends on libhidapi.
|
45
|
+
|
46
|
+
## INSTALL:
|
47
|
+
|
48
|
+
* Install hidapi. On MacOS that is `brew install hidapi`
|
49
|
+
|
50
|
+
## LICENSE:
|
51
|
+
|
52
|
+
(The MIT License)
|
53
|
+
|
54
|
+
Copyright (c) 2019 Aaron Patterson
|
55
|
+
|
56
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
57
|
+
a copy of this software and associated documentation files (the
|
58
|
+
'Software'), to deal in the Software without restriction, including
|
59
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
60
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
61
|
+
permit persons to whom the Software is furnished to do so, subject to
|
62
|
+
the following conditions:
|
63
|
+
|
64
|
+
The above copyright notice and this permission notice shall be
|
65
|
+
included in all copies or substantial portions of the Software.
|
66
|
+
|
67
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
68
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
69
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
70
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
71
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
72
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
73
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
tries = 0
|
6
|
+
begin
|
7
|
+
require 'hoe'
|
8
|
+
require 'minitest'
|
9
|
+
require 'rake/extensiontask'
|
10
|
+
rescue LoadError
|
11
|
+
tries += 1
|
12
|
+
Gem.install 'hoe'
|
13
|
+
Gem.install 'rake-compiler'
|
14
|
+
Gem.install 'hoe-gemspec'
|
15
|
+
Gem.install 'hoe-git'
|
16
|
+
Gem.install 'minitest'
|
17
|
+
raise unless tries < 10
|
18
|
+
retry
|
19
|
+
end
|
20
|
+
|
21
|
+
Hoe.plugin :minitest
|
22
|
+
Hoe.plugin :gemspec # `gem install hoe-gemspec`
|
23
|
+
Hoe.plugin :git # `gem install hoe-git`
|
24
|
+
|
25
|
+
HOE = Hoe.spec 'myhidapi' do
|
26
|
+
developer('Aaron Patterson', 'tenderlove@ruby-lang.org')
|
27
|
+
license "MIT"
|
28
|
+
self.readme_file = 'README.md'
|
29
|
+
self.history_file = 'CHANGELOG.md'
|
30
|
+
self.extra_rdoc_files = FileList['*.md']
|
31
|
+
|
32
|
+
self.spec_extras = {
|
33
|
+
:extensions => ["ext/myhidapi/extconf.rb"],
|
34
|
+
:required_ruby_version => '>= 2.3.0'
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
Rake::ExtensionTask.new("myhidapi", HOE.spec) do |ext|
|
39
|
+
end
|
40
|
+
|
41
|
+
# vim: syntax=ruby
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
ldflags = cppflags = nil
|
4
|
+
if RbConfig::CONFIG["host_os"] =~ /darwin/
|
5
|
+
begin
|
6
|
+
brew_prefix = `brew --prefix hidapi`.chomp
|
7
|
+
ldflags = "#{brew_prefix}/lib"
|
8
|
+
cppflags = "#{brew_prefix}/include"
|
9
|
+
pkg_conf = "#{brew_prefix}/lib/pkgconfig"
|
10
|
+
|
11
|
+
# pkg_config should be less error prone than parsing compiler
|
12
|
+
# commandline options, but we need to set default ldflags and cpp flags
|
13
|
+
# in case the user doesn't have pkg-config installed
|
14
|
+
ENV['PKG_CONFIG_PATH'] ||= pkg_conf
|
15
|
+
rescue
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
pkg_config 'hidapi'
|
20
|
+
|
21
|
+
dir_config("hidapi", cppflags, ldflags)
|
22
|
+
|
23
|
+
raise "Install hidapi (brew install hidapi)" unless have_header 'hidapi.h'
|
24
|
+
|
25
|
+
create_makefile 'myhidapi'
|
@@ -0,0 +1,178 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <hidapi.h>
|
3
|
+
#include <stdlib.h>
|
4
|
+
|
5
|
+
VALUE mMyHIDAPI;
|
6
|
+
VALUE cMyHIDAPIHandle;
|
7
|
+
|
8
|
+
static void dealloc(void * ptr)
|
9
|
+
{
|
10
|
+
hid_device *handle = (hid_device *)ptr;
|
11
|
+
hid_close(handle);
|
12
|
+
}
|
13
|
+
|
14
|
+
static const rb_data_type_t myhidapi_handle_type = {
|
15
|
+
"MyHIDAPI/Handle",
|
16
|
+
{0, dealloc, 0,},
|
17
|
+
0, 0,
|
18
|
+
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
19
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
20
|
+
#endif
|
21
|
+
};
|
22
|
+
|
23
|
+
#define BUF_SIZE 4096
|
24
|
+
|
25
|
+
static VALUE
|
26
|
+
rb_wcstombs(wchar_t *str)
|
27
|
+
{
|
28
|
+
char buf[BUF_SIZE];
|
29
|
+
int len;
|
30
|
+
len = wcstombs(buf, str, BUF_SIZE);
|
31
|
+
if (len > 0) {
|
32
|
+
return rb_str_new(buf, len);
|
33
|
+
} else {
|
34
|
+
return Qnil;
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
static VALUE
|
39
|
+
enumerate(VALUE mod, VALUE vendor_id, VALUE product_id)
|
40
|
+
{
|
41
|
+
VALUE devices;
|
42
|
+
struct hid_device_info *devs, *cur_dev;
|
43
|
+
|
44
|
+
devices = rb_ary_new();
|
45
|
+
devs = hid_enumerate(NUM2USHORT(vendor_id), NUM2USHORT(product_id));
|
46
|
+
cur_dev = devs;
|
47
|
+
while (cur_dev) {
|
48
|
+
rb_ary_push(devices, rb_funcall(mMyHIDAPI, rb_intern("build_device_info"), 8,
|
49
|
+
INT2NUM(cur_dev->vendor_id),
|
50
|
+
INT2NUM(cur_dev->product_id),
|
51
|
+
rb_str_new2(cur_dev->path),
|
52
|
+
rb_wcstombs(cur_dev->serial_number),
|
53
|
+
rb_wcstombs(cur_dev->manufacturer_string),
|
54
|
+
rb_wcstombs(cur_dev->product_string),
|
55
|
+
INT2NUM(cur_dev->usage),
|
56
|
+
INT2NUM(cur_dev->interface_number)
|
57
|
+
));
|
58
|
+
cur_dev = cur_dev->next;
|
59
|
+
}
|
60
|
+
hid_free_enumeration(devs);
|
61
|
+
|
62
|
+
return devices;
|
63
|
+
}
|
64
|
+
|
65
|
+
static VALUE
|
66
|
+
rb_hid_open(VALUE mod, VALUE vid, VALUE pid)
|
67
|
+
{
|
68
|
+
hid_device *handle;
|
69
|
+
|
70
|
+
handle = hid_open(NUM2USHORT(vid), NUM2USHORT(pid), NULL);
|
71
|
+
|
72
|
+
if (handle) {
|
73
|
+
return TypedData_Wrap_Struct(cMyHIDAPIHandle, &myhidapi_handle_type, handle);
|
74
|
+
} else {
|
75
|
+
return Qfalse;
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
static VALUE
|
80
|
+
rb_hid_open_path(VALUE mod, VALUE path)
|
81
|
+
{
|
82
|
+
hid_device *handle;
|
83
|
+
|
84
|
+
handle = hid_open_path(StringValueCStr(path));
|
85
|
+
|
86
|
+
if (handle) {
|
87
|
+
return TypedData_Wrap_Struct(cMyHIDAPIHandle, &myhidapi_handle_type, handle);
|
88
|
+
} else {
|
89
|
+
return Qfalse;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
static VALUE
|
94
|
+
rb_hid_write(VALUE self, VALUE str)
|
95
|
+
{
|
96
|
+
hid_device *handle;
|
97
|
+
int written;
|
98
|
+
|
99
|
+
TypedData_Get_Struct(self, hid_device, &myhidapi_handle_type, handle);
|
100
|
+
|
101
|
+
written = hid_write(handle, (unsigned char *)StringValuePtr(str), RSTRING_LEN(str));
|
102
|
+
|
103
|
+
if (written >= 0) {
|
104
|
+
return INT2NUM(written);
|
105
|
+
} else {
|
106
|
+
return Qfalse;
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
static VALUE
|
111
|
+
rb_hid_set_nonblocking(VALUE self, VALUE val)
|
112
|
+
{
|
113
|
+
hid_device *handle;
|
114
|
+
TypedData_Get_Struct(self, hid_device, &myhidapi_handle_type, handle);
|
115
|
+
if (!hid_set_nonblocking(handle, NUM2INT(val))) {
|
116
|
+
return Qtrue;
|
117
|
+
} else {
|
118
|
+
return Qnil;
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
static VALUE
|
123
|
+
rb_hid_read(VALUE self, VALUE size)
|
124
|
+
{
|
125
|
+
hid_device *handle;
|
126
|
+
unsigned char * buf;
|
127
|
+
int read;
|
128
|
+
VALUE ret;
|
129
|
+
|
130
|
+
TypedData_Get_Struct(self, hid_device, &myhidapi_handle_type, handle);
|
131
|
+
|
132
|
+
buf = xcalloc(NUM2SIZET(size), sizeof(unsigned char));
|
133
|
+
|
134
|
+
read = hid_read(handle, buf, NUM2SIZET(size));
|
135
|
+
|
136
|
+
if (read > 0) {
|
137
|
+
ret = rb_str_new((char *)buf, read);
|
138
|
+
} else {
|
139
|
+
ret = Qnil;
|
140
|
+
}
|
141
|
+
xfree(buf);
|
142
|
+
return ret;
|
143
|
+
}
|
144
|
+
|
145
|
+
static VALUE
|
146
|
+
rb_hid_read_timeout(VALUE self, VALUE size, VALUE timeout_ms)
|
147
|
+
{
|
148
|
+
hid_device *handle;
|
149
|
+
unsigned char * buf;
|
150
|
+
int read;
|
151
|
+
VALUE ret;
|
152
|
+
|
153
|
+
TypedData_Get_Struct(self, hid_device, &myhidapi_handle_type, handle);
|
154
|
+
|
155
|
+
buf = xcalloc(NUM2SIZET(size), sizeof(unsigned char));
|
156
|
+
|
157
|
+
read = hid_read_timeout(handle, buf, NUM2SIZET(size), NUM2INT(timeout_ms));
|
158
|
+
|
159
|
+
if (read > 0) {
|
160
|
+
ret = rb_str_new((char *)buf, read);
|
161
|
+
} else {
|
162
|
+
ret = Qnil;
|
163
|
+
}
|
164
|
+
xfree(buf);
|
165
|
+
return ret;
|
166
|
+
}
|
167
|
+
|
168
|
+
void Init_myhidapi() {
|
169
|
+
mMyHIDAPI = rb_define_module("MyHIDAPI");
|
170
|
+
cMyHIDAPIHandle = rb_define_class_under(mMyHIDAPI, "Handle", rb_cObject);
|
171
|
+
rb_define_singleton_method(mMyHIDAPI, "enumerate", enumerate, 2);
|
172
|
+
rb_define_singleton_method(mMyHIDAPI, "open", rb_hid_open, 2);
|
173
|
+
rb_define_singleton_method(mMyHIDAPI, "open_path", rb_hid_open_path, 1);
|
174
|
+
rb_define_method(cMyHIDAPIHandle, "write", rb_hid_write, 1);
|
175
|
+
rb_define_method(cMyHIDAPIHandle, "read", rb_hid_read, 1);
|
176
|
+
rb_define_method(cMyHIDAPIHandle, "read_timeout", rb_hid_read_timeout, 2);
|
177
|
+
rb_define_method(cMyHIDAPIHandle, "set_nonblocking", rb_hid_set_nonblocking, 1);
|
178
|
+
}
|
data/lib/myhidapi.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require "myhidapi.so"
|
2
|
+
|
3
|
+
module MyHIDAPI
|
4
|
+
VERSION = '1.0.0'
|
5
|
+
|
6
|
+
class DeviceInfo
|
7
|
+
attr_reader :vendor_id, :product_id, :path, :serial_number, :manufacturer_string, :product_string, :usage, :interface_number
|
8
|
+
|
9
|
+
def initialize vendor_id, product_id, path, serial_number, manufacturer_string, product_string, usage, interface_number
|
10
|
+
@vendor_id = vendor_id
|
11
|
+
@product_id = product_id
|
12
|
+
@path = path
|
13
|
+
@serial_number = serial_number
|
14
|
+
@manufacturer_string = manufacturer_string
|
15
|
+
@product_string = product_string
|
16
|
+
@usage = usage
|
17
|
+
@interface_number = interface_number
|
18
|
+
end
|
19
|
+
|
20
|
+
def open
|
21
|
+
MyHIDAPI.open vendor_id, product_id
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.build_device_info(*args)
|
26
|
+
DeviceInfo.new(*args)
|
27
|
+
end
|
28
|
+
end
|
data/sample/kbprog.rb
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
require 'myhidapi'
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
class TeeloKB
|
5
|
+
class Error < StandardError; end
|
6
|
+
class CouldNotReadError < Error; end
|
7
|
+
class KeyboardNotFoundError < Error; end
|
8
|
+
|
9
|
+
COMMAND_VERSIONS = { 1 => {} }
|
10
|
+
|
11
|
+
%i{
|
12
|
+
version
|
13
|
+
rgblight_enable
|
14
|
+
rgblight_disable
|
15
|
+
rgblight_toggle
|
16
|
+
rgblight_mode
|
17
|
+
rgblight_sethsv
|
18
|
+
rgblight_get_mode
|
19
|
+
rgblight_get_hue
|
20
|
+
rgblight_get_sat
|
21
|
+
rgblight_get_val
|
22
|
+
}.each_with_index do |command, index|
|
23
|
+
COMMAND_VERSIONS[1][command] = index + 1
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.find
|
27
|
+
MyHIDAPI.enumerate(0x0, 0x0).find { |dev| dev.product_string == "ErgoDox EZ" }
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.open
|
31
|
+
dev = self.find
|
32
|
+
|
33
|
+
retries = 0
|
34
|
+
handle = dev.open
|
35
|
+
while !handle
|
36
|
+
retries += 1
|
37
|
+
raise KeyboardNotFoundError, "Couldn't find keyboard" if retries > 10
|
38
|
+
handle = dev.open
|
39
|
+
end
|
40
|
+
|
41
|
+
new handle
|
42
|
+
end
|
43
|
+
|
44
|
+
def initialize handle
|
45
|
+
@handle = handle
|
46
|
+
@version = protocol_version
|
47
|
+
end
|
48
|
+
|
49
|
+
def protocol_version
|
50
|
+
write [0x0, 0x1]
|
51
|
+
read(2).inject(:+)
|
52
|
+
end
|
53
|
+
|
54
|
+
def solid
|
55
|
+
rgblight_mode 0x1
|
56
|
+
end
|
57
|
+
|
58
|
+
def enable
|
59
|
+
write [0x0, _(:rgblight_enable)]
|
60
|
+
read 10
|
61
|
+
end
|
62
|
+
|
63
|
+
def disable
|
64
|
+
write [0x0, _(:rgblight_disable)]
|
65
|
+
read 10
|
66
|
+
end
|
67
|
+
|
68
|
+
def toggle
|
69
|
+
write [0x0, _(:rgblight_toggle)]
|
70
|
+
read 10
|
71
|
+
end
|
72
|
+
|
73
|
+
def mode
|
74
|
+
write [0x0, _(:rgblight_get_mode)]
|
75
|
+
read(2).last
|
76
|
+
end
|
77
|
+
|
78
|
+
def rainbow style = 0x6
|
79
|
+
rgblight_mode style
|
80
|
+
end
|
81
|
+
|
82
|
+
def rgblight_mode value
|
83
|
+
write [0x0, _(:rgblight_mode), value & 0xFF]
|
84
|
+
read 10
|
85
|
+
end
|
86
|
+
alias :mode= :rgblight_mode
|
87
|
+
|
88
|
+
def rgblight_sethsv h, s, v
|
89
|
+
write([0x0, _(:rgblight_sethsv)] + [(h >> 8) & 0xFF, h & 0xFF, s & 0xFF, v & 0xFF])
|
90
|
+
read 10
|
91
|
+
end
|
92
|
+
alias :sethsv :rgblight_sethsv
|
93
|
+
|
94
|
+
def setrgb r, g, b
|
95
|
+
sethsv *rgb2hsv(r, g, b)
|
96
|
+
end
|
97
|
+
|
98
|
+
def hue
|
99
|
+
write [0x0, _(:rgblight_get_hue)]
|
100
|
+
_, upper, lower = read 3
|
101
|
+
(upper << 8) | lower
|
102
|
+
end
|
103
|
+
|
104
|
+
def saturation
|
105
|
+
write [0x0, _(:rgblight_get_sat)]
|
106
|
+
read(2)[1]
|
107
|
+
end
|
108
|
+
|
109
|
+
def value
|
110
|
+
write [0x0, _(:rgblight_get_val)]
|
111
|
+
read(2)[1]
|
112
|
+
end
|
113
|
+
|
114
|
+
def hsv
|
115
|
+
[hue, saturation, value]
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def rgb2hsv r, g, b
|
121
|
+
v = [r, g, b].max
|
122
|
+
delta = v - [r, g, b].min
|
123
|
+
|
124
|
+
s = v == 0 ? 0 : (delta / v.to_f)
|
125
|
+
h = delta == 0 ? 0 : (case v
|
126
|
+
when r then ((g - b) / delta) % 6
|
127
|
+
when g then ((b - r) / delta) + 2
|
128
|
+
when b then ((r - g) / delta) + 4
|
129
|
+
end) * 60
|
130
|
+
|
131
|
+
[h.round, (s * 255).round, v]
|
132
|
+
end
|
133
|
+
|
134
|
+
def write buf
|
135
|
+
loop do
|
136
|
+
break if @handle.write buf.pack('C*')
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def read size
|
141
|
+
buf = @handle.read_timeout size, 300 # 300 ms timeout
|
142
|
+
if buf
|
143
|
+
buf.unpack('C*')
|
144
|
+
else
|
145
|
+
# Unfortunately, this seems to happen frequently.
|
146
|
+
raise CouldNotReadError, "could not read from device"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def _ command
|
151
|
+
COMMAND_VERSIONS.fetch(@version).fetch(command)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
commands = []
|
156
|
+
responses = []
|
157
|
+
|
158
|
+
OptionParser.new do |opts|
|
159
|
+
opts.banner = "Usage: kbprog.rb [options]"
|
160
|
+
|
161
|
+
opts.on("--hsv=[HSV]", "Set or get HSV (comma separated)") do |v|
|
162
|
+
if v
|
163
|
+
commands << lambda { |kb| kb.sethsv(*v.split(",").map(&:to_i)) }
|
164
|
+
else
|
165
|
+
commands << lambda { |kb| responses << { hsv: kb.hsv } }
|
166
|
+
end
|
167
|
+
end
|
168
|
+
opts.on("--mode=[HSV]", "Set or get mode") do |v|
|
169
|
+
if v
|
170
|
+
commands << lambda { |kb| kb.mode = v.to_i }
|
171
|
+
else
|
172
|
+
commands << lambda { |kb| responses << { mode: kb.mode } }
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end.parse!
|
176
|
+
|
177
|
+
kb = TeeloKB.open
|
178
|
+
commands.each { |cmd| cmd.call kb }
|
179
|
+
responses.each do |res|
|
180
|
+
p res
|
181
|
+
end
|
182
|
+
|
183
|
+
#p ez.mode
|
184
|
+
#ez.mode = 5
|
185
|
+
#ez.sethsv 300, 250, 255
|
186
|
+
#p ez.hsv
|
187
|
+
|
188
|
+
#rescue TeeloKB::Error => e
|
189
|
+
# exec "ruby --disable-gems -I lib:test #{__FILE__}"
|
190
|
+
#end
|
data/sample/set_hsv.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'myhidapi'
|
2
|
+
|
3
|
+
def try_block times
|
4
|
+
times.times { x = yield; return x if x }
|
5
|
+
raise "Couldn't do it"
|
6
|
+
end
|
7
|
+
|
8
|
+
dev = MyHIDAPI.enumerate(0x0, 0x0).find { |dev| dev.product_string == "ErgoDox EZ" }
|
9
|
+
|
10
|
+
handle = try_block(10) { dev.open }
|
11
|
+
p handle
|
12
|
+
|
13
|
+
h = 0 # 0x0 to 0x168 (which is 360 base 10)
|
14
|
+
s = 0xFF # 0x0 to 0xFF
|
15
|
+
v = 0xFF # 0x0 to 0xFF
|
16
|
+
|
17
|
+
try_block(10) do
|
18
|
+
handle.write [0x0, 0x6, (h >> 8) & 0xFF, h & 0xFF, s, v].pack('C*')
|
19
|
+
end
|
20
|
+
|
21
|
+
handle.read_timeout 10, 300 # 300 ms timeout
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'myhidapi'
|
3
|
+
|
4
|
+
class TestMyHIDAPI < MiniTest::Test
|
5
|
+
def test_it_works
|
6
|
+
devices = MyHIDAPI.enumerate 0x0, 0x0
|
7
|
+
dev = devices.find { |dev| dev.product_string == "ErgoDox EZ" }
|
8
|
+
|
9
|
+
handle = dev.open
|
10
|
+
|
11
|
+
while !handle
|
12
|
+
p "retry"
|
13
|
+
handle = dev.open
|
14
|
+
end
|
15
|
+
|
16
|
+
p handle
|
17
|
+
|
18
|
+
buf = [0x0, 0x3, 35]
|
19
|
+
loop do
|
20
|
+
break if handle.write buf.pack('C*')
|
21
|
+
end
|
22
|
+
puts "done writing"
|
23
|
+
|
24
|
+
buf = handle.read_timeout 1, 500
|
25
|
+
p buf
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_can_enumerate_by_ids
|
29
|
+
devices = MyHIDAPI.enumerate(0xfeed, 0x1307)
|
30
|
+
|
31
|
+
refute_predicate devices, :empty?
|
32
|
+
end
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: myhidapi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Aaron Patterson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-06-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: minitest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.11'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.11'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rdoc
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.0'
|
34
|
+
- - "<"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '7'
|
37
|
+
type: :development
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '4.0'
|
44
|
+
- - "<"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '7'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: hoe
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '3.17'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '3.17'
|
61
|
+
description: |-
|
62
|
+
This is a small wrapper around HIDAPI. I couldn't get other HIDAPI wrappers to
|
63
|
+
work, so I wrote this one. I'm using it to communicate with my keyboard, so
|
64
|
+
it really only supports enough of the HIDAPI to do that.
|
65
|
+
email:
|
66
|
+
- tenderlove@ruby-lang.org
|
67
|
+
executables: []
|
68
|
+
extensions:
|
69
|
+
- ext/myhidapi/extconf.rb
|
70
|
+
extra_rdoc_files:
|
71
|
+
- CHANGELOG.md
|
72
|
+
- Manifest.txt
|
73
|
+
- README.md
|
74
|
+
files:
|
75
|
+
- CHANGELOG.md
|
76
|
+
- Manifest.txt
|
77
|
+
- README.md
|
78
|
+
- Rakefile
|
79
|
+
- ext/myhidapi/extconf.rb
|
80
|
+
- ext/myhidapi/myhidapi.c
|
81
|
+
- lib/myhidapi.rb
|
82
|
+
- sample/kbprog.rb
|
83
|
+
- sample/set_hsv.rb
|
84
|
+
- test/test_myhidapi.rb
|
85
|
+
homepage: https://github.com/tenderlove/myhidapi
|
86
|
+
licenses:
|
87
|
+
- MIT
|
88
|
+
metadata: {}
|
89
|
+
post_install_message:
|
90
|
+
rdoc_options:
|
91
|
+
- "--main"
|
92
|
+
- README.md
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: 2.3.0
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubygems_version: 3.0.1
|
107
|
+
signing_key:
|
108
|
+
specification_version: 4
|
109
|
+
summary: This is a small wrapper around HIDAPI
|
110
|
+
test_files: []
|