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,48 @@
1
+ module Vigilem
2
+ module Evdev
3
+ module DOM
4
+ #
5
+ module InputEventUtils
6
+
7
+ include Vigilem::DOM::Utils
8
+
9
+ # takes a InputEvent#code and returns a String
10
+ # representing the keycode value
11
+ # @param [Integer] event_code, the number to convert
12
+ # @return [String] i.e. "keycode30"
13
+ def event_code_to_keycode_str(event_code)
14
+ "keycode#{event_code}"
15
+ end
16
+
17
+ # takes a keycode_name and returns a common location string
18
+ # if available
19
+ # @param [String || Symbol] keycode_name, i.e. KEY_RIGTHCTRL
20
+ # @return [String || NilClass] a common locaiton string i.e. 'Right'
21
+ def location_str_from_keycode_name(keycode_name)
22
+ if loc = keycode_name.to_s.gsub('KP', 'NUMPAD').scan(/LEFT|RIGHT|NUMPAD/i).first
23
+ loc.downcase.tap {|obj| obj[0] = obj[0].upcase }
24
+ end
25
+ end
26
+
27
+ # takes a keycode name and returns the keymap modifier name
28
+ # @todo meta
29
+ # @param [String ||Symbol] keycode_name, i.e. KEY_RIGHTCTRL
30
+ # @return [String] keymap_name of the modifier
31
+ def modifier_keymap_name(keycode_name)
32
+ if (keycode_name) =~ /caps|shift|alt|c(on)?tro?l/i
33
+ if keycode_name == :KEY_CAPSLOCK
34
+ 'capsshift'
35
+ else
36
+ keycode_name.to_s.gsub(/KEY_/, '').split(/ight|eft/i).reverse.join.downcase
37
+ end
38
+ end
39
+ end
40
+
41
+ extend self
42
+
43
+ extend Support::Utils
44
+
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,248 @@
1
+ require 'vigilem/support/key_map'
2
+
3
+ require 'vigilem/evdev/system'
4
+
5
+ module Vigilem
6
+ module Evdev::DOM
7
+ module KeyValuesTables
8
+
9
+ include Evdev::System::Input::KeysAndButtons
10
+
11
+ SpecialKeyValues = Support::KeyMap.new({'Unidentified' => nil })
12
+ ModifierKeys = Support::KeyMap.new.fuse!({
13
+ :'?' => 'Accel',
14
+ KEY_LEFTALT => 'Alt',
15
+ KEY_RIGHTALT => 'Alt'}, {
16
+ :'?' => 'AltGraph',
17
+ KEY_CAPSLOCK => 'CapsLock',
18
+ 'CtrlL_Lock' => 'CapsLock',
19
+ KEY_LEFTCTRL => 'Control',
20
+ KEY_RIGHTCTRL => 'Control',
21
+ 'Control' => 'Control'}, {
22
+ :'?' => ['Fn', 'FnLock', 'Hyper'],
23
+ KEY_LEFTMETA => 'Meta',
24
+ KEY_RIGHTMETA => 'Meta',
25
+ KEY_NUMLOCK => 'NumLock',
26
+ KEY_LEFTMETA => 'OS',
27
+ KEY_SCROLLLOCK => 'ScrollLock',
28
+ KEY_LEFTSHIFT => 'Shift',
29
+ KEY_RIGHTSHIFT => 'Shift'}, {
30
+ :'?' => ['Super', 'Symbol', 'SymbolLock']
31
+ })
32
+
33
+ WhitespaceKeys = Support::KeyMap.new({
34
+ KEY_ENTER => 'Enter',
35
+ 'KP_Enter' => 'Enter',
36
+ :'?' => 'Separator',
37
+ 'Tab' => 'Tab',
38
+ KEY_TAB => 'Tab'
39
+ })
40
+ # Space
41
+
42
+ NavigationKeys = Support::KeyMap.new({
43
+ KEY_DOWN => 'ArrowDown',
44
+ 'Down' => 'ArrowDown',
45
+ 'KP_2' => 'ArrowDown',
46
+ KEY_LEFT => 'ArrowLeft',
47
+ 'Left' => 'ArrowLeft',
48
+ 'KP_4' => 'ArrowLeft',
49
+ KEY_RIGHT => 'ArrowRight',
50
+ 'Right' => 'ArrowRight',
51
+ 'KP_6' => 'ArrowRight',
52
+ KEY_UP => 'ArrowUp',
53
+ 'Up' => 'ArrowUp',
54
+ 'KP_8' => 'ArrowUp',
55
+ KEY_END => 'End',
56
+ 'KP_1' => 'End',
57
+ KEY_HOME => 'Home',
58
+ 'KP_7' => 'Home',
59
+ KEY_PAGEDOWN => 'PageDown',
60
+ 'KP_3' => 'PageDown',
61
+ KEY_PAGEUP => 'PageUp',
62
+ 'KP_9' => 'PageUp'
63
+ })
64
+
65
+ EditingKeys = Support::KeyMap.new.fuse!({
66
+ KEY_BACKSPACE => 'Backspace',
67
+ KEY_CLEAR => 'Clear',
68
+ KEY_COPY => 'Copy',
69
+ :'?' => 'CrSel',
70
+ KEY_CUT => 'Cut',
71
+ KEY_DELETE => 'Delete'}, {
72
+ :'?' => ['EraseEof', 'ExSel'],
73
+ KEY_INSERT => 'Insert',
74
+ KEY_PASTE => 'Paste',
75
+ KEY_REDO => 'Redo',
76
+ KEY_UNDO => 'Undo'
77
+ })
78
+ UIKeys = Support::KeyMap.new.fuse!({
79
+ :'?' => 'Accept',
80
+ KEY_AGAIN => 'Again'}, {
81
+ :'?' => 'Attn',
82
+ KEY_CANCEL => 'Cancel',
83
+ KEY_COMPOSE => 'ContextMenu',
84
+ KEY_ESC => 'Escape'}, {
85
+ :'?' => 'Execute',
86
+ KEY_FIND => 'Find',
87
+ KEY_HELP => 'Help',
88
+ KEY_PAUSE => 'Pause',
89
+ KEY_PLAY => 'Play',
90
+ KEY_PROPS => 'Props',
91
+ KEY_SELECT => 'Select',
92
+ KEY_ZOOMIN => 'ZoomIn',
93
+ KEY_ZOOMOUT => 'ZoomOut'
94
+ })
95
+
96
+ DeviceKeys = Support::KeyMap.new.fuse!({
97
+ :'?' => ['BrightnessDown', 'BrightnessUp'],
98
+ KEY_CAMERA => 'Camera',
99
+ KEY_EJECTCD => 'Eject',
100
+ KEY_EJECTCLOSECD => 'Eject'}, {
101
+ :'?' => ['LogOff', 'Power', 'PowerOff'],
102
+ KEY_PRINT => 'PrintScreen'}, {
103
+ :'?' => ['Hibernate', 'Standby', 'WakeUp']
104
+ })
105
+ IMEandCompositionKeys = Support::KeyMap.new.fuse!({
106
+ :'?' => ['AllCandidates', 'Alphanumeric',
107
+ 'CodeInput'],
108
+ KEY_COMPOSE => 'Compose'}, {
109
+ :'?' => ['Convert', 'Dead', 'FinalMode',
110
+ 'GroupFirst', 'GroupLast'],
111
+ KEY_KBDINPUTASSIST_NEXTGROUP => 'GroupNext',
112
+ KEY_KBDINPUTASSIST_PREVGROUP => 'GroupPrevious',
113
+ KEY_MODE => 'ModeChange'}, {
114
+ :'?' => ['NextCandidate', 'NonConvert',
115
+ 'PreviousCandidate', 'Process',
116
+ 'SingleCandidate']
117
+ })
118
+ KeysspecifictoKoreankeyboards = Support::KeyMap.new.fuse!({
119
+ KEY_HANGEUL => 'HangulMode',
120
+ KEY_HANJA => 'HanjaMode',
121
+ :'?' => 'JunjaMode'
122
+ })
123
+ KeysspecifictoJapanesekeyboards = Support::KeyMap.new.fuse!({
124
+ :'?' => ['Eisu', 'Hankaku'],
125
+ KEY_HIRAGANA => 'Hiragana',
126
+ KEY_KATAKANAHIRAGANA => 'HiraganaKatakana'}, {
127
+ :'?' => ['KanaMode', 'KanjiMode'],
128
+ KEY_KATAKANA => 'Katakana'}, {
129
+ :'?' => ['Romaji', 'Zenkaku'],
130
+ KEY_ZENKAKUHANKAKU => 'ZenkakuHankaku'
131
+ })
132
+ General_PurposeFunctionKeys = Support::KeyMap.new({
133
+ KEY_F1 => 'F1',
134
+ KEY_F2 => 'F2',
135
+ KEY_F3 => 'F3',
136
+ KEY_F4 => 'F4',
137
+ KEY_F5 => 'F5',
138
+ KEY_F6 => 'F6',
139
+ KEY_F7 => 'F7',
140
+ KEY_F8 => 'F8',
141
+ KEY_F9 => 'F9',
142
+ KEY_F10 => 'F10',
143
+ KEY_F11 => 'F11',
144
+ KEY_F12 => 'F12',
145
+ :'?' => ['Soft1', 'Soft2', 'Soft3', 'Soft4']
146
+ })
147
+
148
+ MultimediaKeys = Support::KeyMap.new.fuse!({
149
+ KEY_CLOSECD => 'Close',
150
+ KEY_EJECTCLOSECD => 'Close',
151
+ KEY_FORWARDMAIL => 'MailForward',
152
+ KEY_REPLY => 'MailReply',
153
+ :'?' => 'MailSend'}, {
154
+ KEY_PLAYPAUSE => 'MediaPlayPause',
155
+ :'?' => 'MediaSelect', #too many option need to test
156
+ KEY_STOPCD => 'MediaStop',
157
+ KEY_NEXTSONG => 'MediaTrackNext',
158
+ KEY_PREVIOUSSONG => 'MediaTrackPrevious',
159
+ KEY_NEW => 'New',
160
+ KEY_OPEN => 'Open',
161
+ KEY_PRINT => 'Print',
162
+ KEY_SAVE => 'Save',
163
+ KEY_SPELLCHECK => 'SpellCheck',
164
+ KEY_VOLUMEDOWN => 'VolumeDown',
165
+ KEY_VOLUMEUP => 'VolumeUp',
166
+ KEY_MUTE => 'VolumeMute'
167
+ })
168
+
169
+ ApplicationKeys = Support::KeyMap.new({
170
+ KEY_CALC => 'LaunchCalculator',
171
+ KEY_CALENDAR => 'LaunchCalendar',
172
+ KEY_MAIL => 'LaunchMail',
173
+ KEY_PLAYER => ['LaunchMediaPlayer', 'LaunchMusicPlayer'],
174
+ KEY_PC => 'LaunchMyComputer',
175
+ KEY_COFFEE => 'LaunchScreenSaver',
176
+ KEY_SPREADSHEET => 'LaunchSpreadsheet',
177
+ KEY_WWW => 'LaunchWebBrowser',
178
+ :'?' => 'LaunchWebCam', #how's this differ from KEY_CAMERA?
179
+ KEY_WORDPROCESSOR => 'LaunchWordProcessor'
180
+ })
181
+
182
+ BrowserKeys = Support::KeyMap.new({
183
+ :'?' => ['BrowserBack','BrowserFavorites', 'BrowserForward',
184
+ 'BrowserHome', 'BrowserRefresh', 'BrowserSearch',
185
+ 'BrowserStop']
186
+ })
187
+
188
+ MediaControllerKeys = Support::KeyMap.new().fuse!({
189
+ :'?' => ['AudioBalanceLeft', 'AudioBalanceRight']}, {
190
+ KEY_BASSBOOST => ['AudioBassBoostDown', 'AudioBassBoostUp'],
191
+ :'?' => ['AudioFaderFront', 'AudioFaderRear',
192
+ 'AudioSurroundModeNext', 'AVRInput', 'AVRPower'],
193
+ KEY_CHANNELDOWN => 'ChannelDown',
194
+ KEY_CHANNELUP => 'ChannelUp',
195
+ KEY_RED => 'ColorF0Red',
196
+ KEY_GREEN => 'ColorF1Green',
197
+ KEY_YELLOW => 'ColorF2Yellow',
198
+ KEY_BLUE => 'ColorF3Blue'}, {
199
+ :'?' => ['ColorF4Grey', 'ColorF5Brown', 'ClosedCaptionToggle',
200
+ 'Dimmer', 'DisplaySwap', 'Exit',
201
+ 'FavoriteClear0', 'FavoriteClear1',
202
+ 'FavoriteClear2', 'FavoriteClear3',
203
+ 'FavoriteRecall0', 'FavoriteRecall1',
204
+ 'FavoriteRecall2', 'FavoriteRecall3',
205
+ 'FavoriteStore0', 'FavoriteStore1',
206
+ 'FavoriteStore2', 'FavoriteStore3',
207
+ 'Guide', 'GuideNextDay', 'GuidePreviousDay',
208
+ 'Info', 'InstantReplay', 'Link',
209
+ 'ListProgram', 'LiveContent', 'Lock',
210
+ 'MediaApps', 'MediaFastForward', 'MediaLast',
211
+ 'pMediaPause', 'MediaPlay', 'MediaRecord'],
212
+ KEY_REWIND => 'MediaRewind'}, {
213
+ :'?' => ['MediaSkip', 'NextFavoriteChannel',
214
+ 'NextUserProfile', 'OnDemand', 'PinPDown',
215
+ 'PinPMove', 'PinPToggle', 'PinPUp',
216
+ 'PlaySpeedDown', 'PlaySpeedReset',
217
+ 'PlaySpeedUp', 'RandomToggle', 'RcLowBattery',
218
+ 'RecordSpeedNext', 'RfBypass',
219
+ 'ScanChannelsToggle', 'ScreenModeNext',
220
+ 'Settings', 'SplitScreenToggle', 'STBInput',
221
+ 'STBPower', 'Subtitle', 'Teletext', 'TV',
222
+ 'TVInput', 'TVPower', 'VideoModeNext',
223
+ 'Wink', 'ZoomToggle', 'BrowserBack',
224
+ 'BrowserForward', 'ContextMenu', 'Eject',
225
+ 'End', 'Enter', 'Home', 'MediaPlayPause',
226
+ 'MediaStop', 'MediaNextTrack', 'MediaPreviousTrack',
227
+ 'Power', 'VolumeDown', 'VolumeUp', 'VolumeMute']
228
+ })
229
+ end
230
+
231
+ KeyTable = KeyValuesTables.constants.each_with_object(Support::KeyMap.new) do |table_name, memo|
232
+ if (key_map = KeyValuesTables.const_get(table_name)).is_a? Hash
233
+ key_map.right_side_alias(:dom_code)
234
+ key_map.right_side_alias(:dom_codes)
235
+ key_map.left_side_alias(:keycode)
236
+ key_map.left_side_alias(:keycodes)
237
+ key_map.left_side_alias(:keysym)
238
+ key_map.left_side_alias(:keysyms)
239
+ memo.merge! key_map
240
+ end
241
+ end
242
+
243
+ KeyTable.right_side_alias(:dom_code)
244
+ KeyTable.right_side_alias(:dom_codes)
245
+ KeyTable.left_side_alias(:keycode)
246
+ KeyTable.left_side_alias(:keycodes)
247
+ end
248
+ end
@@ -0,0 +1,52 @@
1
+ require 'vigilem/support/key_map'
2
+
3
+ require 'vigilem/evdev/system/input'
4
+
5
+ module Vigilem
6
+ module Evdev
7
+ module DOM
8
+ # keycode or sym...
9
+ KPTable = Support::KeyMap.new({
10
+ 'KP_Space' => "\u0020",
11
+ 'KP_Tab' => "\u0009",
12
+ 'KP_Enter' => "\u000d",
13
+ 'KP_F1' => "\u0000",
14
+ 'KP_F2' => "\u0000",
15
+ 'KP_F3' => "\u0000",
16
+ 'KP_F4' => "\u0000",
17
+ 'KP_Home' => "\u0000",
18
+ 'KP_Left' => "\u0000",
19
+ 'KP_Up' => "\u0000",
20
+ 'KP_Right' => "\u0000",
21
+ 'KP_Down' => "\u0000",
22
+ 'KP_Prior' => "\u0000",
23
+ 'KP_Next' => "\u0000",
24
+ 'KP_End' => "\u0000",
25
+ 'KP_Begin' => "\u0000",
26
+ 'KP_Insert' => "\u0000",
27
+ 'KP_Delete' => "\u0000",
28
+ 'KP_Multiply' => "\u002a",
29
+ 'KP_Add' => "\u002b",
30
+ 'KP_Separator' => "\u002c",
31
+ 'KP_Subtract' => "\u002d",
32
+ 'KP_Decimal' => "\u002e",
33
+ 'KP_Period' => "\u002e",
34
+ 'KP_Divide' => "\u002f",
35
+ 'KP_0' => "\u0030",
36
+ 'KP_1' => "\u0031",
37
+ 'KP_2' => "\u0032",
38
+ 'KP_3' => "\u0033",
39
+ 'KP_4' => "\u0034",
40
+ 'KP_5' => "\u0035",
41
+ 'KP_6' => "\u0036",
42
+ 'KP_7' => "\u0037",
43
+ 'KP_8' => "\u0038",
44
+ 'KP_9' => "\u0039",
45
+ 'KP_Equal' => "\u003d",
46
+ })
47
+ KPTable.right_side_alias(:char)
48
+ KPTable.left_side_alias(:sym)
49
+ KPTable.left_side_alias(:keysym)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,124 @@
1
+ require 'vigilem/_evdev'
2
+
3
+ require 'vigilem/evdev/context_filter'
4
+
5
+ require 'vigilem/x11/stat'
6
+
7
+ module Vigilem
8
+ module Evdev
9
+ #
10
+ # allows input_events through when the window has focus
11
+ class FocusContextFilter
12
+
13
+ include Evdev::ContextFilter
14
+
15
+ class << self
16
+
17
+ #
18
+ # @return [String || NilClass]
19
+ def env_display
20
+ ENV['DISPLAY']
21
+ end
22
+
23
+ #
24
+ #
25
+ def lazy_require
26
+ require 'vigilem/x11/terminal_window_utils'
27
+ require 'vigilem/x11/input_system_handler'
28
+ end
29
+
30
+ #
31
+ # @param [String] display
32
+ # @param [Integer ||NilClass] xwindow_id
33
+ # @param [FocusContextFilter || NilClass]
34
+ # @return [NilClass || self]
35
+ def new_if_installed(display=env_display, xwindow_id=nil)
36
+ if X11::Stat.default.installed?
37
+ new(display, xwindow_id)
38
+ end
39
+ end
40
+
41
+ #
42
+ # @param [String] display
43
+ # @param [Integer || NilClass] xwindow_id
44
+ # @raise [RuntimeError]
45
+ # @return [NilClass || self]
46
+ def new_if_installed!(display=env_display, xwindow_id=nil)
47
+ new_if_installed(display, xwindow_id) || raise('InputSystem unavailable')
48
+ end
49
+
50
+ end
51
+
52
+ attr_accessor :input_system_handler
53
+
54
+ def_delegators :input_system_handler, :display, :window_xid
55
+
56
+ #
57
+ # @param [String]
58
+ # @param [Integer || NilClass]
59
+ def initialize(display=self.class.env_display, xwindow_id=nil)
60
+ self.class.lazy_require
61
+ window_xid = xwindow_id || X11::TerminalWindowUtils.window_id
62
+
63
+ @input_system_handler = X11::InputSystemHandler.new(window_xid, display, Xlib::FocusChangeMask)
64
+ end
65
+
66
+ #
67
+ # @return [TrueClass || FalseClass]
68
+ def has_focus?
69
+ with_focus = X11.get_input_focus(self.display, window_xid)[1]
70
+ with_focus == self.window_xid or
71
+ self.window_xid == X11.query_tree(self.display, with_focus)[:parent_return]
72
+ end
73
+
74
+ alias_method :had_focus?, :was_off?
75
+
76
+ #
77
+ # @return [TrueClass || FalseClass]
78
+ def on?
79
+ if gained_focus?
80
+ on_change(OFF)
81
+ elsif lost_focus?
82
+ on_change(ON)
83
+ end
84
+ was_on?
85
+ end
86
+
87
+ #
88
+ # @return [TrueClass || FalseClass]
89
+ def off?
90
+ not on?
91
+ end
92
+
93
+ #
94
+ # @return [TrueClass || FalseClass]
95
+ def gained_focus?
96
+ (not had_focus?) and has_focus?
97
+ end
98
+
99
+ #
100
+ # @return [TrueClass || FalseClass]
101
+ def lost_focus?
102
+ had_focus? and not has_focus?
103
+ end
104
+
105
+ #
106
+ # @param [Array] events
107
+ # @return [Array]
108
+ def process(*events)
109
+ if on?
110
+ []
111
+ else
112
+ events
113
+ end
114
+ end
115
+
116
+ private
117
+ #
118
+ # @param [TrueClass || FalseClass] bool
119
+ # @return
120
+ alias_method :had_focus= ,:was_off=
121
+
122
+ end
123
+ end
124
+ end