vigilem-evdev 0.1.3

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.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +22 -0
  3. data/ext/Rakefile +31 -0
  4. data/ext/rake_helper.rb +10 -0
  5. data/lib/vigilem/_evdev.rb +24 -0
  6. data/lib/vigilem/evdev.rb +14 -0
  7. data/lib/vigilem/evdev/at_exit.rb +8 -0
  8. data/lib/vigilem/evdev/context_filter.rb +92 -0
  9. data/lib/vigilem/evdev/demultiplexer.rb +26 -0
  10. data/lib/vigilem/evdev/device.rb +182 -0
  11. data/lib/vigilem/evdev/device_capabilities.rb +53 -0
  12. data/lib/vigilem/evdev/dom.rb +8 -0
  13. data/lib/vigilem/evdev/dom/adapter.rb +87 -0
  14. data/lib/vigilem/evdev/dom/code_values_tables.rb +172 -0
  15. data/lib/vigilem/evdev/dom/input_event_converter.rb +329 -0
  16. data/lib/vigilem/evdev/dom/input_event_utils.rb +48 -0
  17. data/lib/vigilem/evdev/dom/key_values_tables.rb +248 -0
  18. data/lib/vigilem/evdev/dom/kp_table.rb +52 -0
  19. data/lib/vigilem/evdev/focus_context_filter.rb +124 -0
  20. data/lib/vigilem/evdev/input_system_handler.rb +69 -0
  21. data/lib/vigilem/evdev/key_map_cache.rb +64 -0
  22. data/lib/vigilem/evdev/multiplexer.rb +73 -0
  23. data/lib/vigilem/evdev/system.rb +17 -0
  24. data/lib/vigilem/evdev/system/input.rb +1053 -0
  25. data/lib/vigilem/evdev/system/input/event.rb +4 -0
  26. data/lib/vigilem/evdev/system/input/input_event.rb +33 -0
  27. data/lib/vigilem/evdev/system/int.rb +9 -0
  28. data/lib/vigilem/evdev/system/ioctl.rb +143 -0
  29. data/lib/vigilem/evdev/system/keymap_loaders.rb +89 -0
  30. data/lib/vigilem/evdev/system/keymap_loaders/dumpkeys_loader.rb +98 -0
  31. data/lib/vigilem/evdev/system/keymap_loaders/kmap_loader.rb +74 -0
  32. data/lib/vigilem/evdev/system/posix_types.rb +5 -0
  33. data/lib/vigilem/evdev/system/time.rb +21 -0
  34. data/lib/vigilem/evdev/transfer_agent.rb +40 -0
  35. data/lib/vigilem/evdev/version.rb +5 -0
  36. data/lib/vigilem/evdev/vty_context_filter.rb +216 -0
  37. data/spec/after_each_example_group.rb +29 -0
  38. data/spec/delete_test_cache_after_group.rb +26 -0
  39. data/spec/spec_helper.rb +30 -0
  40. data/spec/vigilem/_evdev_spec.rb +11 -0
  41. data/spec/vigilem/evdev/context_filter_spec.rb +114 -0
  42. data/spec/vigilem/evdev/demultiplexer_spec.rb +44 -0
  43. data/spec/vigilem/evdev/device_capabilities_spec.rb +0 -0
  44. data/spec/vigilem/evdev/device_spec.rb +97 -0
  45. data/spec/vigilem/evdev/dom/adapter_spec.rb +5 -0
  46. data/spec/vigilem/evdev/dom/input_event_converter_spec.rb +253 -0
  47. data/spec/vigilem/evdev/dom/input_event_utils_spec.rb +23 -0
  48. data/spec/vigilem/evdev/focus_context_filter_spec.rb +112 -0
  49. data/spec/vigilem/evdev/input_system_handler_spec.rb +146 -0
  50. data/spec/vigilem/evdev/key_map_cache_spec.rb +65 -0
  51. data/spec/vigilem/evdev/multiplexer_spec.rb +55 -0
  52. data/spec/vigilem/evdev/system/input/input_event_spec.rb +33 -0
  53. data/spec/vigilem/evdev/system/input_spec.rb +274 -0
  54. data/spec/vigilem/evdev/system/int_spec.rb +30 -0
  55. data/spec/vigilem/evdev/system/ioctl_spec.rb +206 -0
  56. data/spec/vigilem/evdev/system/keymap_loaders/dumpkeys_loader_spec.rb +5 -0
  57. data/spec/vigilem/evdev/system/keymap_loaders/kmap_loader_spec.rb +24 -0
  58. data/spec/vigilem/evdev/system/keymap_loaders_spec.rb +22 -0
  59. data/spec/vigilem/evdev/system/posix_types_spec.rb +15 -0
  60. data/spec/vigilem/evdev/system/time_spec.rb +18 -0
  61. data/spec/vigilem/evdev/transfer_agent_spec.rb +57 -0
  62. data/spec/vigilem/evdev/vty_context_filter_spec.rb +282 -0
  63. metadata +286 -0
@@ -0,0 +1,5 @@
1
+ require 'ffi'
2
+
3
+ FFI.typedef :long, :__kernel_long_t
4
+ FFI.typedef :__kernel_long_t, :__kernel_time_t
5
+ FFI.typedef :int, :__kernel_suseconds_t
@@ -0,0 +1,21 @@
1
+ require 'vigilem/support'
2
+
3
+ require 'vigilem/evdev/system/posix_types'
4
+
5
+ module Vigilem
6
+ module Evdev
7
+ module Time
8
+ # represents timeval from time.h
9
+ class Timeval < ::VFFIStruct
10
+ layout_with_methods :tv_sec, :__kernel_time_t,
11
+ :tv_usec, :__kernel_suseconds_t
12
+
13
+ #
14
+ # @return [Numeric]
15
+ def to_f
16
+ tv_sec.to_f + (tv_usec.to_f/1000000.0)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,40 @@
1
+ require 'vigilem/core/transfer_agent'
2
+
3
+ require 'vigilem/evdev/demultiplexer'
4
+
5
+ require 'vigilem/evdev/multiplexer'
6
+
7
+ module Vigilem
8
+ module Evdev
9
+ #
10
+ #
11
+ class TransferAgent < Core::TransferAgent
12
+
13
+ class << self
14
+
15
+ # @todo move away from singleton and look at the one used by x11
16
+ # @param args [Hash]
17
+ # @param :inputs [Array]
18
+ # @param :outputs [Hash{observer_object => {event_opts}]
19
+ # @see Demultiplexer#add_oberver
20
+ # @return [TransferAgent]
21
+ def acquire(args={})
22
+ if @transfer_agent
23
+ @transfer_agent.multiplexer.add_inputs(*args[:inputs]) if args[:inputs]
24
+ @transfer_agent.add_observers(args[:outputs]) if args[:outputs]
25
+ if ((din = @transfer_agent.demultiplexer.input) || (mout = @transfer_agent.multiplexer.out)).nil? or not mout.equal?(din)
26
+ @transfer_agent.demultiplexer.input = @transfer_agent.multiplexer.out = (mout || din || [])
27
+ end
28
+ @transfer_agent
29
+ else
30
+ m = Multiplexer.acquire(args[:inputs])
31
+ d = Demultiplexer.acquire(args[:outputs])
32
+ @transfer_agent = new(d, m)
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,5 @@
1
+ module Vigilem
2
+ module Evdev
3
+ VERSION = '0.1.3'
4
+ end
5
+ end
@@ -0,0 +1,216 @@
1
+ require 'vigilem/support/core_ext'
2
+
3
+ require 'vigilem/support/key_map'
4
+
5
+ require 'vigilem/_evdev'
6
+
7
+ require 'vigilem/evdev/context_filter'
8
+
9
+ module Vigilem
10
+ module Evdev
11
+ #
12
+ # filters events if the VTY differs from the one of this process
13
+ class VTYContextFilter
14
+
15
+ KeyMap = Support::KeyMap
16
+
17
+ include ContextFilter
18
+ # @todo make these class_methods
19
+ attr_reader :current_console_num, :console_keys,
20
+ :current_console_keys, :other_console_keys
21
+
22
+ #
23
+ # @param [KeyMap] keymap
24
+ # @return
25
+ def initialize(keymap=Evdev.key_map)
26
+ @key_map = keymap unless keymap.eql? Evdev.key_map
27
+
28
+ @current_console_num = `fgconsole`.rstrip.to_i
29
+ curr_con_keys, oth_con_keys =
30
+ self.class.console_keys(keymap).partition {|syms,v| v == "Console_#{@current_console_num}" }
31
+ @current_console_keys, @other_console_keys = KeyMap[curr_con_keys], KeyMap[oth_con_keys]
32
+
33
+ @current_console_keys.left_side_aliases(:keycode, :keycodes)
34
+ @current_console_keys.right_side_aliases(:keysym, :keysyms)
35
+
36
+ @other_console_keys.left_side_aliases(:keycode, :keycodes)
37
+ @other_console_keys.right_side_aliases(:keysym, :keysyms)
38
+
39
+ @current_keys = []
40
+ end
41
+
42
+ #
43
+ # @param [KeyMap] keymap
44
+ # @return [KeyMap]
45
+ def self.console_keys(keymap)
46
+ @console_keys = if keymap.metadata[:loader].class.name =~ /KmapLoader/
47
+ keymap.select {|k,v| v =~ /console_\d+/i }
48
+ else
49
+ console_syms = keymap.info.keysyms.select {|k,v| v =~ /console_\d+/i }
50
+ tmp = keymap.select {|k,v| v =~ /^#{console_syms.keys.join('|')}$/ }
51
+ tmp.each {|k,v| tmp[k] = console_syms[v] }
52
+ end
53
+ end
54
+
55
+ #
56
+ # @return [KeyMap]
57
+ def key_map
58
+ @key_map || Evdev.key_map
59
+ end
60
+
61
+ #
62
+ # @return [Array]
63
+ def current_keys
64
+ if @current_keys and current_keys_changed?
65
+ max_and_one = KeyMap.mod_weights.values.max + 1
66
+ @current_keys.sort_by! {|ksym| KeyMap.mod_weights[ksym.downcase] || max_and_one }
67
+ @current_keys_hash_cache = @current_keys.hash
68
+ @current_keys
69
+ else
70
+ if @current_keys.nil?
71
+ @current_keys = []
72
+ @current_keys_hash_cache = @current_keys.hash
73
+ end
74
+ @current_keys
75
+ end
76
+ end
77
+
78
+ #
79
+ # @param [Array<System::InputEvent>] events
80
+ # @return [Array]
81
+ def process(*events)
82
+ events.select do |event|
83
+ off_status = off?
84
+ key_check = if event.type == System::Input::EV_KEY
85
+ if event.value == 1
86
+ add_key(keysym_or_keycode(event.code))
87
+ off_status
88
+ elsif event.value == 0
89
+ kork = keysym_or_keycode(event.code)
90
+ release_status = allow_release?(kork)
91
+ remove_key(kork)
92
+ release_status
93
+ end
94
+ end
95
+ if key_check.nil? then off_status else key_check end
96
+ end
97
+ end
98
+
99
+ #
100
+ # @param key
101
+ # @return [Array]
102
+ def add_key(keycode_or_keysym)
103
+ current_keys << keycode_or_keysym
104
+ end
105
+
106
+ #
107
+ # @param [Fixnum] key_num
108
+ # @return
109
+ def remove_key(keycode_or_keysym)
110
+ current_keys.delete(keycode_or_keysym)
111
+ end
112
+
113
+ #
114
+ # @todo name
115
+ # @return [String]
116
+ def keysym_or_keycode(key_num)
117
+ sym = keysym(keycode = "keycode#{key_num}")
118
+ if sym =~ /shift|alt|c(on)?tro?l|capsshift/i
119
+ sym
120
+ else
121
+ keycode
122
+ end
123
+ end
124
+
125
+ # @todo move to KeyMapUtils, or something like that
126
+ # @param [Integer] key_num
127
+ # @return [String]
128
+ def keysym(keycode)
129
+ if key_map.metadata[:loader].class.name =~ /KmapLoader/
130
+ key_map.keysym(keycode)
131
+ else
132
+ key_map.info.keysyms[key_map.char_ref(keycode)]
133
+ end
134
+ end
135
+
136
+ #
137
+ # @return [TrueClass || FalseClass || NilClass]
138
+ def on?
139
+ if changed_vty?
140
+ self.filter_ommisions = current_keys_downcase
141
+ on_change(ON)
142
+ elsif reverted_vty?
143
+ self.filter_ommisions = current_keys_downcase
144
+ on_change(OFF)
145
+ end
146
+ was_on?
147
+ end
148
+
149
+ #
150
+ # @return [TrueClass || FalseClass]
151
+ def reverted_vty?
152
+ was_on? and current_console_keys.keysym(current_keys_downcase)
153
+ end
154
+
155
+ #
156
+ # @return [TrueClass || FalseClass]
157
+ def changed_vty?
158
+ was_off? and other_console_keys.keysym(current_keys_downcase)
159
+ end
160
+
161
+ #
162
+ # @return [TrueClass || FalseClass]
163
+ def off?
164
+ not on?
165
+ end
166
+
167
+ private
168
+ #
169
+ # @return [Integer] the hash of current_keys last time it was set
170
+ def current_keys_hash_cache
171
+ @current_keys_hash_cache ||= @current_keys.hash
172
+ end
173
+
174
+ #
175
+ # @return [TrueClass || FalseClass] if the cached value of
176
+ # #current_keys.hash changed
177
+ def current_keys_changed?
178
+ current_keys_hash_cache != @current_keys.hash
179
+ end
180
+
181
+ # @todo name!
182
+ # @return [Array]
183
+ def current_keys_downcase
184
+ downcase_hash ||= 0
185
+ if @current_keys_downcase.nil? or current_keys_hash_cache != downcase_hash
186
+ downcase_hash = current_keys_hash_cache
187
+ @current_keys_downcase = current_keys.map(&:downcase)
188
+ else
189
+ @current_keys_downcase
190
+ end
191
+ end
192
+
193
+ private
194
+ attr_writer :filter_ommisions
195
+
196
+ #
197
+ # @param other
198
+ # @return [TrueClass || FalseClass]
199
+ def allow_release?(keycode_or_keysym)
200
+ lower_kork = keycode_or_keysym.downcase
201
+ if filter_ommisions.include? lower_kork
202
+ filter_ommisions.delete(lower_kork)
203
+ on?
204
+ else
205
+ off?
206
+ end
207
+ end
208
+
209
+ #
210
+ # @return [Array]
211
+ def filter_ommisions
212
+ @filter_ommisions ||= []
213
+ end
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,29 @@
1
+ #
2
+ # fires after every example_group
3
+ module AfterEachExampleGroup
4
+ def after_each_example_group?
5
+ @after_each_example_group_flag ||= false
6
+ end
7
+
8
+ def after_each_example_group(&block)
9
+ if block
10
+ @after_each_example_group_flag = true
11
+ @after_each_example_group = block
12
+ else
13
+ @after_each_example_group
14
+ end
15
+ end
16
+ end
17
+
18
+ RSpec.configure do |config|
19
+
20
+ config.before :all do |example_group|
21
+ if ((egc = example_group.class).respond_to? :after_each_example_group? and egc.after_each_example_group?)
22
+ (egc.descendants - [egc]).map do |eg|
23
+ eg.append_after(:context, &egc.after_each_example_group)
24
+ end
25
+ end
26
+ end
27
+
28
+ config.extend AfterEachExampleGroup
29
+ end
@@ -0,0 +1,26 @@
1
+ RSpec.configure do |config|
2
+
3
+ config.before :all do |example_group|
4
+ klass = example_group.class
5
+
6
+ (klass.descendants - [klass]).each do |egc|
7
+ if egc.metadata.key?(:clean_up_test_cache)
8
+ require 'fileutils'
9
+ require 'vigilem/evdev/key_map_cache'
10
+ test_name = 'key_map_cache_test'
11
+ egc.before(:each) do
12
+ Vigilem::Evdev::KeyMapCache.default_path = nil
13
+ Vigilem::Evdev::KeyMapCache.default_filename = test_name
14
+ end
15
+ egc.after(:each) do
16
+ Vigilem::Evdev::KeyMapCache.default_path = nil
17
+ Vigilem::Evdev::KeyMapCache.default_filename = nil
18
+ pth = File.join(Bundler.root, 'data', test_name)
19
+ FileUtils.remove(pth) if File.exists?(pth)
20
+ end
21
+ end
22
+ end
23
+
24
+ end
25
+
26
+ end
@@ -0,0 +1,30 @@
1
+ event_files = Dir["/dev/input/event*"]
2
+
3
+ if event_files.empty?
4
+ puts %q<can't find character devices in /dev/input/event*>
5
+ exit
6
+ elsif not event_files.any? {|f| File.readable?(f) }
7
+ puts "Your user account isn't allowed to read from /dev/input/event*. please rerun as sudo"
8
+ exit
9
+ end
10
+
11
+ require 'bundler'
12
+ Bundler.setup
13
+
14
+ require 'timeout'
15
+
16
+ require 'inline'
17
+
18
+ require 'vigilem/support/core_ext/debug_puts'
19
+
20
+ require 'vigilem/support/patch/ffi/pointer'
21
+
22
+ require 'after_each_example_group'
23
+
24
+ require 'delete_test_cache_after_group'
25
+
26
+ $ver = `uname -r`.split('-').first
27
+
28
+ $major = (ary = $ver.split('.')).first.to_i
29
+
30
+ $minor = ary[1].to_i
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ require 'vigilem/_evdev'
4
+
5
+ describe Vigilem::Evdev, :clean_up_test_cache do
6
+ describe '#key_map' do
7
+ it 'loads the keymap' do
8
+ expect(described_class.key_map).to be_a Vigilem::Support::KeyMap
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,114 @@
1
+ require 'vigilem/evdev/context_filter'
2
+
3
+ describe Vigilem::Evdev::ContextFilter do
4
+
5
+ class ContextFilterHost
6
+ include Vigilem::Evdev::ContextFilter
7
+ end
8
+
9
+ subject { ContextFilterHost.new }
10
+
11
+ describe '::included' do
12
+ it 'extends Forwardable' do
13
+ expect(subject.class.singleton_class.included_modules).to include(Forwardable)
14
+ end
15
+ end
16
+
17
+ describe '#last_known_state' do
18
+ it 'defaults to nil/UKNOWN' do
19
+ expect(subject.last_known_state).to be_nil
20
+ end
21
+ end
22
+
23
+ describe '#was_on?' do
24
+ it 'compares ON to #last_known_state defaulting to false' do
25
+ expect(subject.was_on?).to be_falsey
26
+ end
27
+
28
+ it 'returns true if #last_known_state == ON' do
29
+ subject.send(:last_known_state=, described_class::ON)
30
+ expect(subject.was_on?).to be_truthy
31
+ end
32
+ end
33
+
34
+ describe '#was_off?' do
35
+ it 'compares OFF to #last_known_state defaulting to true' do
36
+ expect(subject.was_off?).to be_truthy
37
+ end
38
+
39
+ it 'returns true if #last_known_state == OFF' do
40
+ subject.send(:last_known_state=, described_class::ON)
41
+ expect(subject.was_off?).to be_falsey
42
+ end
43
+ end
44
+
45
+ describe '#on?' do
46
+ it 'raises error because it needs to be overridden' do
47
+ expect { subject.on? }.to raise_error(NotImplementedError)
48
+ end
49
+ end
50
+
51
+ #alias_method :filtered?, :on?
52
+
53
+
54
+ describe '#off?' do
55
+ it 'raises error because it needs to be overridden' do
56
+ expect { subject.off? }.to raise_error(NotImplementedError)
57
+ end
58
+ end
59
+
60
+ describe '#on_change' do
61
+ it 'updates #last_known_state' do
62
+ subject.on_change(described_class::ON)
63
+ expect(subject.last_known_state).to eql(described_class::ON)
64
+ end
65
+
66
+ class FakeObserver
67
+ def update(type, value)
68
+ (@updates ||= []).concat([type, value])
69
+ end
70
+ attr_reader :updates
71
+ end
72
+
73
+ it 'notifies observers' do
74
+ fo = FakeObserver.new
75
+ subject.add_observer(fo)
76
+ subject.on_change(described_class::ON)
77
+ expect(fo.updates).to eql([subject, described_class::ON])
78
+ end
79
+ end
80
+
81
+ context 'private' do
82
+ describe '#last_known_state=' do
83
+ it 'sets #last_known_state' do
84
+ subject.send(:last_known_state=, described_class::ON)
85
+ expect(subject.last_known_state).to eql(described_class::ON)
86
+ end
87
+ end
88
+
89
+ describe '#was_on=' do
90
+ it 'sets #was_on?' do
91
+ subject.send(:was_on=, false)
92
+ expect(subject.was_on?).to be_falsey
93
+ end
94
+
95
+ it 'updates #last_known_state' do
96
+ subject.send(:was_on=, true)
97
+ expect(subject.last_known_state).to eql(described_class::ON)
98
+ end
99
+ end
100
+
101
+ describe '#was_off=' do
102
+ it 'sets #was_off?' do
103
+ subject.send(:was_off=, true)
104
+ expect(subject.was_off?).to be_truthy
105
+ end
106
+
107
+ it 'updates #last_known_state' do
108
+ subject.send(:was_off=, true)
109
+ expect(subject.last_known_state).to eql(described_class::OFF)
110
+ end
111
+ end
112
+ end
113
+
114
+ end