vigilem-win32_api 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +22 -0
  3. data/lib/vigilem/win32_api/console_input_events.rb +78 -0
  4. data/lib/vigilem/win32_api/constants.rb +97 -0
  5. data/lib/vigilem/win32_api/dom/adapter.rb +59 -0
  6. data/lib/vigilem/win32_api/dom/code_values_tables.rb +136 -0
  7. data/lib/vigilem/win32_api/dom/input_record_utils.rb +259 -0
  8. data/lib/vigilem/win32_api/dom/key_values_tables.rb +123 -0
  9. data/lib/vigilem/win32_api/dom.rb +5 -0
  10. data/lib/vigilem/win32_api/eventable.rb +41 -0
  11. data/lib/vigilem/win32_api/input__record.rb +53 -0
  12. data/lib/vigilem/win32_api/input_system_handler.rb +124 -0
  13. data/lib/vigilem/win32_api/p_input__record.rb +55 -0
  14. data/lib/vigilem/win32_api/rubyized.rb +114 -0
  15. data/lib/vigilem/win32_api/types.rb +153 -0
  16. data/lib/vigilem/win32_api/utils/keyboard.rb +120 -0
  17. data/lib/vigilem/win32_api/version.rb +5 -0
  18. data/lib/vigilem/win32_api/virtual_keys/map.rb +211 -0
  19. data/lib/vigilem/win32_api/virtual_keys.rb +9 -0
  20. data/lib/vigilem/win32_api.rb +61 -0
  21. data/spec/acceptance/custom_input_system.feature +3 -0
  22. data/spec/acceptance/dom_adapter.feature +7 -0
  23. data/spec/acceptance/rubyized.feature +6 -0
  24. data/spec/acceptance/steps/custom_input_system_steps.rb +37 -0
  25. data/spec/acceptance/steps/dom_adapter_steps.rb +7 -0
  26. data/spec/acceptance/steps/rubyized_steps.rb +20 -0
  27. data/spec/attributes_and_size_test.rb +10 -0
  28. data/spec/input_helper.rb +41 -0
  29. data/spec/spec_helper.rb +28 -0
  30. data/spec/turnip_helper.rb +1 -0
  31. data/spec/vigilem/api_spec.rb +139 -0
  32. data/spec/vigilem/win32_api/console_input_events_spec.rb +67 -0
  33. data/spec/vigilem/win32_api/dom/adapter_spec.rb +164 -0
  34. data/spec/vigilem/win32_api/dom/code_values_tables_spec.rb +5 -0
  35. data/spec/vigilem/win32_api/dom/input_record_utils_spec.rb +255 -0
  36. data/spec/vigilem/win32_api/dom/key_values_tables_spec.rb +5 -0
  37. data/spec/vigilem/win32_api/eventable_spec.rb +96 -0
  38. data/spec/vigilem/win32_api/input__record_spec.rb +113 -0
  39. data/spec/vigilem/win32_api/input_system_handler_spec.rb +164 -0
  40. data/spec/vigilem/win32_api/p_input__record_spec.rb +43 -0
  41. data/spec/vigilem/win32_api/rubyized_spec.rb +134 -0
  42. data/spec/vigilem/win32_api/types_spec.rb +139 -0
  43. data/spec/vigilem/win32_api/utils/keyboard_spec.rb +126 -0
  44. data/spec/vigilem/win32_api/virtual_keys/map_spec.rb +10 -0
  45. data/spec/vigilem/win32_api/virtual_keys_spec.rb +28 -0
  46. metadata +225 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bbde09d132a14953b05aeb4838acc918ab48c878
4
+ data.tar.gz: 8a9eb4816a5a373fedd2838ce1fb05eba9305d90
5
+ SHA512:
6
+ metadata.gz: 1cbfeaef82619e2b953cf1dc4da2c01756aebb4b32d41c869226e19090db8bca0af9dc8c6da2daa62bc61568bf127977efcb7fd0e889e2c79ec9a014d850c6ce
7
+ data.tar.gz: 8d93eaf3ee72ae910bf61d06e33ff9f69e335167c34c4d939818d59130af29f64d9bf0a09b547b624ca68cc02b121c738f8f1fcb9b99cbc29a20125e09557af8
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 jtzero
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.
@@ -0,0 +1,78 @@
1
+ module Vigilem
2
+ module Win32API
3
+ #
4
+ # group of all the console input events listed by MSoft
5
+ module ConsoleInputEvents
6
+
7
+
8
+ #
9
+ class MOUSE_EVENT_RECORD < ::VFFIStruct
10
+ layout_with_methods :dwMousePosition, Win32API::COORD,
11
+ :dwButtonState, :DWORD,
12
+ :dwControlKeyState, :DWORD,
13
+ :dwEventFlags, :DWORD
14
+ end
15
+
16
+
17
+ #
18
+ class WINDOW_BUFFER_SIZE_RECORD < ::VFFIStruct
19
+ layout_with_methods :dwSize, Win32API::COORD
20
+ end
21
+
22
+
23
+ # "These events are used internally and should be ignored."
24
+ class MENU_EVENT_RECORD < ::VFFIStruct
25
+ layout_with_methods :dwCommandId, :uint
26
+ end
27
+
28
+
29
+ # "These events are used internally and should be ignored."
30
+ class FOCUS_EVENT_RECORD < ::VFFIStruct
31
+ layout_with_methods :bSetFocus, :BOOL
32
+ end
33
+
34
+
35
+ #
36
+ class KEY_EVENT_RECORD < ::VFFIStruct
37
+ layout_with_methods :bKeyDown, :BOOL,
38
+ :wRepeatCount, :WORD,
39
+ :wVirtualKeyCode, :WORD,
40
+ :wVirtualScanCode, :WORD,
41
+ *union(:uChar,
42
+ [:UnicodeChar, :unicode_char], :WCHAR,
43
+ [:AsciiChar, :ascii_char], :CHAR
44
+ ),
45
+ :dwControlKeyState, :uint
46
+
47
+ alias_method :b_key_down, :bKeyDown
48
+ alias_method :w_repeat_count, :wRepeatCount
49
+ alias_method :w_virtual_key_code, :wVirtualKeyCode
50
+ alias_method :w_virtual_scan_code, :wVirtualScanCode
51
+ alias_method :u_char, :uChar
52
+ alias_method :dw_control_key_state, :dwControlKeyState
53
+ end
54
+
55
+ @events = Win32API::Constants::Events
56
+
57
+ #
58
+ # @return [Array<Symbol>]
59
+ def self.vk_names
60
+ @_console_input_events_ ||= @events.constants.grep(/^(?!CTRL).*/)
61
+ end
62
+
63
+ #
64
+ # @return [TransmutableHash<Integer, Symbol>]
65
+ def self.vk_hash
66
+ @_console_input_event_hash_ ||= vk_names.map.with_object(Support::TransmutableHash.new()) {|event_name, hsh| hsh[@events.const_get(event_name)] = event_name }
67
+ end
68
+
69
+ #
70
+ # @return [Array<VFFIStruct>]
71
+ def self.structs
72
+ @_structs_ ||= constants.map {|const| const_get(const) }
73
+ end
74
+ end
75
+
76
+ include ConsoleInputEvents
77
+ end
78
+ end
@@ -0,0 +1,97 @@
1
+ module Vigilem
2
+ module Win32API
3
+
4
+ # @note the colors may be removed in future releases
5
+ module Constants
6
+
7
+ STD_INPUT_HANDLE = 0xFFFFFFF6
8
+ STD_OUTPUT_HANDLE = 0xFFFFFFF5
9
+ STD_ERROR_HANDLE = 0xFFFFFFF4
10
+ INVALID_HANDLE_VALUE = 0xFFFFFFFF
11
+ GENERIC_READ = 0x80000000
12
+ GENERIC_WRITE = 0x40000000
13
+ FILE_SHARE_READ = 0x00000001
14
+ FILE_SHARE_WRITE = 0x00000002
15
+ CONSOLE_TEXTMODE_BUFFER = 0x00000001
16
+ FOREGROUND_BLUE = 0x0001
17
+ FOREGROUND_GREEN = 0x0002
18
+ FOREGROUND_RED = 0x0004
19
+ FOREGROUND_INTENSITY = 0x0008
20
+ BACKGROUND_BLUE = 0x0010
21
+ BACKGROUND_GREEN = 0x0020
22
+ BACKGROUND_RED = 0x0040
23
+ BACKGROUND_INTENSITY = 0x0080
24
+ ENABLE_PROCESSED_INPUT = 0x0001
25
+ ENABLE_LINE_INPUT = 0x0002
26
+ ENABLE_ECHO_INPUT = 0x0004
27
+ ENABLE_WINDOW_INPUT = 0x0008
28
+ ENABLE_MOUSE_INPUT = 0x0010
29
+ ENABLE_PROCESSED_OUTPUT = 0x0001
30
+ ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
31
+
32
+ MOUSE_WHEELED = 0x0004
33
+ DOUBLE_CLICK = 0x0002
34
+ MOUSE_MOVED = 0x0001
35
+ FROM_LEFT_1ST_BUTTON_PRESSED = 0x0001
36
+ FROM_LEFT_2ND_BUTTON_PRESSED = 0x0004
37
+ FROM_LEFT_3RD_BUTTON_PRESSED = 0x0008
38
+ FROM_LEFT_4TH_BUTTON_PRESSED = 0x0010
39
+ RIGHTMOST_BUTTON_PRESSED = 0x0002
40
+
41
+ module Events
42
+ CTRL_C_EVENT = 0x0000
43
+ CTRL_BREAK_EVENT = 0x0001
44
+ CTRL_CLOSE_EVENT = 0x0002
45
+ CTRL_LOGOFF_EVENT = 0x0005
46
+ CTRL_SHUTDOWN_EVENT = 0x0006
47
+ end
48
+
49
+ # @see ReadConsoleInput
50
+ module DWControlKeys
51
+ CAPSLOCK_ON = 0x0080 # The CAPS LOCK light is on.
52
+ ENHANCED_KEY = 0x0100 # The key is enhanced.
53
+ LEFT_ALT_PRESSED = 0x0002 # The left ALT key is pressed.
54
+ LEFT_CTRL_PRESSED = 0x0008 # The left CTRL key is pressed.
55
+ NUMLOCK_ON = 0x0020 # The NUM LOCK light is on.
56
+ RIGHT_ALT_PRESSED = 0x0001 # The right ALT key is pressed.
57
+ RIGHT_CTRL_PRESSED = 0x0004 # The right CTRL key is pressed.
58
+ SCROLLLOCK_ON = 0x0040 # The SCROLL LOCK light is on.
59
+ SHIFT_PRESSED = 0x0010 # The SHIFT key is pressed.
60
+ end
61
+
62
+ include DWControlKeys
63
+
64
+ module Events
65
+ KEY_EVENT = 0x0001
66
+ MOUSE_EVENT = 0x0002
67
+ WINDOW_BUFFER_SIZE_EVENT = 0x0004
68
+ MENU_EVENT = 0x0008
69
+ FOCUS_EVENT = 0x0010
70
+ end
71
+
72
+ include Events
73
+
74
+ module MapType
75
+ MAPVK_VK_TO_VSC = 0
76
+ MAPVK_VSC_TO_VK = 1
77
+ MAPVK_VK_TO_CHAR = 2
78
+ MAPVK_VSC_TO_VK_EX = 3
79
+ end
80
+
81
+ include MapType
82
+
83
+ module MAPVK
84
+ VK_TO_VSC = MapType::MAPVK_VK_TO_VSC
85
+ VSC_TO_VK = MapType::MAPVK_VSC_TO_VK
86
+ VK_TO_CHAR = MapType::MAPVK_VK_TO_CHAR
87
+ VSC_TO_VK_EX = MapType::MAPVK_VSC_TO_VK_EX
88
+ end
89
+ MapVK = MAPVK
90
+
91
+ MapType::MAPVK = MapType::MapVK = MAPVK
92
+
93
+ end
94
+ include Constants
95
+
96
+ end
97
+ end
@@ -0,0 +1,59 @@
1
+ require 'vigilem./core/adapters/buffered_adapter'
2
+
3
+ require 'vigilem/core/eventable'
4
+
5
+ require 'vigilem/core/event_handler'
6
+
7
+ require 'vigilem/win32_api/input_system_handler'
8
+
9
+ module Vigilem
10
+ module Win32API
11
+ module DOM
12
+ #
13
+ #
14
+ class Adapter
15
+
16
+ require 'vigilem/win32_api/dom/input_record_utils'
17
+
18
+ include InputRecordUtils
19
+
20
+ include Core::Adapters::BufferedAdapter
21
+
22
+ include Core::EventHandler
23
+
24
+ default_handler()
25
+
26
+ #
27
+ # @param link
28
+ def initialize(link=InputSystemHandler.new)
29
+ initialize_buffered(link)
30
+ self.dom_ir_utils_source = link
31
+ on(Win32API::KEY_EVENT_RECORD) {|event| to_dom_key_event(event) }
32
+ end
33
+
34
+ include Core::Eventable
35
+
36
+ #
37
+ # @param [Integer] limit
38
+ # @return
39
+ def read_many_nonblock(limit=1)
40
+ buffered!(limit) do |len_remainder|
41
+ dom_src_events = link.read_many_nonblock(len_remainder).map do |event|
42
+ handle(event.event_record)
43
+ end.compact.flatten
44
+ ret, to_buffer = Support::Utils.split_at(dom_src_events, len_remainder)
45
+ buffer.concat([*to_buffer])
46
+ ret
47
+ end
48
+ end
49
+
50
+ #
51
+ # @return [TrueClass || FalseClass]
52
+ def has_any?
53
+ not buffer.empty? || link.has_any?
54
+ end
55
+
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,136 @@
1
+ module Vigilem
2
+ module Win32API::DOM
3
+ # http://www.w3.org/TR/2014/WD-DOM-Level-3-Events-code-20140612/
4
+ module CodeValuesTables
5
+
6
+ code_values = Vigilem::DOM::CodeValues
7
+
8
+ WritingSystemKeys = Support::KeyMap.new({
9
+ :VK_OEM_3 => 'Backquote',
10
+ :VK_OEM_5 => 'Backslash',
11
+ :VK_BACK => 'Backspace',
12
+ :VK_OEM_4 => 'BracketLeft',
13
+ :VK_OEM_6 => 'BracketRight',
14
+ :VK_OEM_COMMA => 'Comma',
15
+ :VK_OEM_PLUS => 'Equal',
16
+ #'IntlBackslash', 'IntlHash', 'IntlRo', 'IntlYen',
17
+ :VK_OEM_MINUS => 'Minus',
18
+ :VK_OEM_PERIOD => 'Period',
19
+ :VK_OEM_7 => 'Quote',
20
+ :VK_OEM_1 => 'Semicolon',
21
+ :VK_OEM_2 => 'Slash'})
22
+
23
+ FunctionalKeys = Support::KeyMap.new({
24
+ :VK_MENU => %w(AltLeft AltRight),
25
+ :VK_LMEMU => 'AltLeft',
26
+ :VK_RMEMU => 'AltRight',
27
+ :VK_CAPITAL => 'CapsLock',
28
+ :VK_APPS => 'ContextMenu',
29
+ :VK_CONTROL => %w(ControlLeft ControlRight'),
30
+ :VK_LCONTROL => 'ControlLeft',
31
+ :VK_RCONTROL => 'ControlRight',
32
+ :VK_RETURN => 'Enter',
33
+ :VK_LWIN => 'OSLeft',
34
+ :VK_RWIN => 'OSRight',
35
+ :VK_SHIFT => %w(ShiftLeft ShiftRight),
36
+ :VK_LSHIFT => 'ShiftLeft',
37
+ :VK_RSHIFT => 'ShiftRight',
38
+ :VK_KANA => 'KanaMode',
39
+ :VK_NONCONVERT => 'NonConvert' })
40
+ #'Lang1', 'Lang2', 'Lang3', 'Lang4', 'Lang5' eh?
41
+
42
+ ControlPadSection = Support::KeyMap.new({
43
+ [:ENHANCED_KEY, :VK_DELETE] => 'Delete',
44
+ [:ENHANCED_KEY, :VK_END] => 'End',
45
+ :VK_HELP => 'Help',
46
+ [:ENHANCED_KEY, :VK_HOME] => 'Home',
47
+ [:ENHANCED_KEY, :VK_INSERT] => 'Insert',
48
+ [:ENHANCED_KEY, :VK_NEXT] => 'PageDown',
49
+ [:ENHANCED_KEY, :VK_PRIOR] => 'PageUp'
50
+ })
51
+
52
+ ArrowPadSection = Support::KeyMap[[
53
+ [:ENHANCED_KEY, :VK_DOWN],
54
+ [:ENHANCED_KEY, :VK_LEFT],
55
+ [:ENHANCED_KEY, :VK_RIGHT],
56
+ [:ENHANCED_KEY, :VK_UP]
57
+ ].zip(code_values::ArrowPadSection)
58
+ ]
59
+
60
+ NumpadSection = Support::KeyMap.new({
61
+ [:ENHANCED_KEY, :VK_NUMLOCK] => 'NumLock',
62
+ :VK_NUMPAD0 => 'Numpad0',
63
+ :VK_INSERT => 'Numpad0',
64
+ :VK_NUMPAD1 => 'Numpad1',
65
+ :VK_END => 'Numpad1',
66
+ :VK_NUMPAD2 => 'Numpad2',
67
+ :VK_DOWN => 'Numpad2',
68
+ :VK_NUMPAD3 => 'Numpad3',
69
+ :VK_NEXT => 'Numpad3',
70
+ :VK_NUMPAD4 => 'Numpad4',
71
+ :VK_LEFT => 'Numpad4',
72
+ :VK_NUMPAD5 => 'Numpad5',
73
+ :VK_NUMPAD6 => 'Numpad6',
74
+ :VK_RIGHT => 'Numpad6',
75
+ :VK_NUMPAD7 => 'Numpad7',
76
+ :VK_HOME => 'Numpad7',
77
+ :VK_NUMPAD8 => 'Numpad8',
78
+ :VK_UP => 'Numpad8',
79
+ :VK_NUMPAD9 => 'Numpad9',
80
+ :VK_PRIOR => 'Numpad9',
81
+ :VK_ADD => 'NumpadAdd',
82
+ :'?' => 'NumpadBackspace',
83
+ :VK_DELETE => 'NumpadDecimal',
84
+ :VK_DECIMAL => 'NumpadDecimal',
85
+ [:ENHANCED_KEY, :VK_DIVIDE] => 'NumpadDivide',
86
+ [:ENHANCED_KEY, :VK_RETURN] => 'NumpadEnter',
87
+ :VK_MULTIPLY => 'NumpadMultiply',
88
+ :VK_SUBTRACT => 'NumpadSubtract'})
89
+ #'NumpadClear', 'NumpadClearEntry', 'NumpadComma', 'NumpadEqual', 'NumpadMemoryAdd', 'NumpadMemoryClear', 'NumpadMemoryRecall', 'NumpadMemoryStore', 'NumpadMemorySubtract', 'NumpadParenLeft', 'NumpadParenRight'
90
+
91
+ FunctionSection = Support::KeyMap.new({
92
+ :VK_MENU => %w(AltLeft AltRight),
93
+ :VK_LMENU => 'AltLeft',
94
+ :VK_RMENU => 'AltRight',
95
+ [:ENHANCED_KEY, :VK_MENU] => 'AltRight',
96
+ :VK_CAPITAL => 'CapsLock',
97
+ [:ENHANCED_KEY, :VK_APPS] => 'ContextMenu',
98
+ :VK_LWIN => 'ContextMenu',
99
+ :VK_RWIN => 'ContextMenu',
100
+ :VK_CONTROL => ['ControlLeft', 'ControlRight'],
101
+ :VK_LCONTROL => 'ControlLeft',
102
+ :VK_RCONTROL => 'ControlRight',
103
+ :VK_SCROLL => 'ScrollLock',
104
+ :VK_PAUSE => 'Pause',
105
+ :VK_SPACE => 'Space',
106
+ :VK_TAB => 'Tab'
107
+ })
108
+
109
+ #['Fn', 'FLock', 'PrintScreen', ]
110
+
111
+ MediaKeys = Support::KeyMap.new({
112
+ :VK_MEDIA_NEXT_TRACK => 'MediaTrackNext',
113
+ :VK_MEDIA_PREV_TRACK => 'MediaTrackPrevious',
114
+ :VK_LAUNCH_MEDIA_SELECT => 'MediaSelect'})
115
+
116
+ #'Eject', 'Power', 'WakeUp'
117
+
118
+ LegacyKeysandNon_StandardKeys = Support::KeyMap.new({:VK_SELECT => 'Select'})
119
+
120
+ #['Hyper', 'Super', 'Turbo', 'Abort', 'Resume', 'Suspend', 'Again', 'Copy', 'Cut', 'Find', 'Open', 'Paste', 'Props', 'Undo', 'Hiragana', 'Katakana']
121
+ end
122
+ CodeTable = CodeValuesTables.constants.each_with_object(Support::KeyMap.new()) do |table_name, memo|
123
+ table = CodeValuesTables.const_get(table_name)
124
+ table.right_side_alias(:dom_code)
125
+ table.right_side_alias(:dom_codes)
126
+ table.left_side_alias(:win_vk)
127
+ table.left_side_alias(:win_vks)
128
+ memo.merge! table
129
+ end
130
+
131
+ CodeTable.right_side_alias(:dom_code)
132
+ CodeTable.right_side_alias(:dom_codes)
133
+ CodeTable.left_side_alias(:win_vk)
134
+ CodeTable.left_side_alias(:win_vks)
135
+ end
136
+ end
@@ -0,0 +1,259 @@
1
+ require 'vigilem/support'
2
+
3
+ require 'vigilem/win32_api'
4
+ require 'vigilem/win32_api/utils/keyboard'
5
+
6
+ require 'vigilem/win32_api/virtual_keys'
7
+
8
+ require 'vigilem/win32_api/dom/key_values_tables'
9
+ require 'vigilem/win32_api/dom/code_values_tables'
10
+
11
+ module Vigilem
12
+ module Win32API
13
+ module DOM
14
+ # http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731%28v=vs.85%29.aspx
15
+ # methods to convert InputRecords to DOM Events
16
+ # @abstract requires a dom_ir_utils_source method
17
+ # and included into the same module
18
+ # as RubyizedAPI
19
+ # @todo module KeyEventRecordUtils
20
+ module InputRecordUtils
21
+
22
+ NULL_STR = "\x00"
23
+
24
+ UNKNOWN_VAL = 'Unidentified'
25
+
26
+ include VirtualKeys
27
+
28
+ include Constants
29
+
30
+ include CodeValuesTables
31
+
32
+ include Utils::Keyboard
33
+
34
+ # the current keys being pressed
35
+ # @return [Array]
36
+ def current_keys
37
+ @current_keys ||= []
38
+ end
39
+
40
+ # converts and event_record to DOM KeyEvent
41
+ # @note the righ Alt and right ctrl are 'enhanced'
42
+ # @param [] event_record
43
+ # @return [Array<Vigilem::DOM::KeyboardEvent>]
44
+ def to_dom_key_event(event_record)
45
+ dw_state_names = dw_control_key_state_vks(event_record.dwControlKeyState)
46
+
47
+ # all test need fixed
48
+ # will this work for a range? if not it needs to
49
+ virtual_key_name = Map.virtual_keyname(vk_code = event_record.wVirtualKeyCode)
50
+
51
+ modifiers = dom_modifiers(*dw_state_names)
52
+
53
+ dom_loc = dom_location(virtual_key_name, event_record.wVirtualScanCode, dw_state_names)
54
+
55
+ key = dom_key(virtual_key_name, u_char = event_record.uChar.UnicodeChar)
56
+
57
+ code = dom_code(virtual_key_name, u_char, dom_loc, *dw_state_names)
58
+
59
+ options = {:key => key, :code => code, :location => dom_loc, :repeat => false,
60
+ :modifiers => modifiers, :os_specific => ::FFIUtils.struct_to_h(event_record) }
61
+
62
+ if event_record.bKeyDown == 1
63
+ if (prev_event = current_keys.last) and %w(keypress keydown).include?(prev_event.type) and prev_event.key == options[:key]
64
+ options[:repeat] = true
65
+ end
66
+
67
+ key_event = ::VDOM::KeyboardEvent.new('keydown', options)
68
+ key_down_events = [key_event, key_event.copy_to('keypress')]
69
+ @current_keys += key_down_events.flatten
70
+ key_down_events
71
+ else
72
+ key_event = ::VDOM::KeyboardEvent.new('keyup', options)
73
+ current_keys.delete_if {|current| current.key == key_event.key and current.location == key_event.location }
74
+ [*key_event].flatten
75
+ end
76
+ end
77
+
78
+ # converts a Integer representing dwControlKeyState from KEY_EVENT_RECORD to an
79
+ # array of virtual-keys, Symbols
80
+ # @param [Integer] dw_control_key_state
81
+ # @return [Array<Symbol>] the win modifiers
82
+ def dw_control_key_state_vks(dw_control_key_state)
83
+ DWControlKeys.constants.select do |const|
84
+ (dw_control_key_state & (value = DWControlKeys.const_get(const))) == value
85
+ end
86
+ end
87
+
88
+ #
89
+ # @return [Hash]
90
+ def location_less_vks_map
91
+ @location_less_vks_map ||= {:VK_MENU => /alt/i, :VK_CONTROL => /control|ctrl/i, :VK_SHIFT => /shift/i }
92
+ end
93
+
94
+ #
95
+ # @param [Symbol] vk_name
96
+ # @return [TrueClass || FalseClass]
97
+ def vk_without_location_info?(vk_name)
98
+ location_less_vks_map.keys.include? vk_name
99
+ end
100
+
101
+ #
102
+ # @return [Hash]
103
+ def shift_scan_code_to_location_vk
104
+ @shift_scan_location ||= { dom_ir_utils_source.map_virtual_key(VK[:LSHIFT], MAPVK::VK_TO_VSC) => :VK_LSHIFT,
105
+ dom_ir_utils_source.map_virtual_key(VK[:RSHIFT], MAPVK::VK_TO_VSC) => :VK_RSHIFT }
106
+ end
107
+
108
+ class << self
109
+ #
110
+ # @param [String<'L'||'l'||'R'||'r'>] str, to convert
111
+ # @return [String<'R'||'r'||'L'||'l'>] its opposite
112
+ def flip_lr_sides(str)
113
+ str.tr('LlRr', 'RrLl')
114
+ end
115
+
116
+ #
117
+ # @param [Symbol] key_name
118
+ # @return [String || NilClass]
119
+ def lr_location_from_name(key_name)
120
+ key_name.to_s.gsub(/VK_(L(?!EFT)|R(?!IGHT))?.+/, '\1')[/L|R/]
121
+ end
122
+
123
+ #
124
+ # @param [String] str, value to test
125
+ # @return [TrueClass || FalseClass] whether or not the String
126
+ # is #empty? or just contains NULL_STR
127
+ def empty_or_null?(str)
128
+ str.strip.empty? or (str == NULL_STR * str.length)
129
+ end
130
+
131
+ end
132
+
133
+ #
134
+ # @param [Symbol] vk_name
135
+ # @param [Array<Symbol>] dw_state_names
136
+ # @return [Integer<0|1|2>]
137
+ def dom_location(vk_name, v_scancode, dw_state_names)
138
+ l_r_location = InputRecordUtils.lr_location_from_name(vk_name) ||
139
+ lr_not_in_name(vk_name, v_scancode, dw_state_names) || ""
140
+
141
+ ::VDOM::Utils.common_str_to_dom_location(l_r_location.upcase) || DOM_KEY_LOCATION_STANDARD
142
+ end
143
+
144
+ # gets the l or r using other params than just the name
145
+ # @see location_less_vks_map
146
+ # @param [Symbol] vk_name
147
+ # @param [Integer] v_scancode
148
+ # @param [Symbol<#{location_less_vks_map.keys}>]
149
+ # @raise [RuntimeError] when the location cannot be found
150
+ # @return [String<'l'|'r'>]
151
+ def lr_not_in_name!(vk_name, v_scancode, dw_state_names)
152
+ if lr = lr_not_in_name(vk_name, v_scancode, dw_state_names)
153
+ lr
154
+ else
155
+ raise RuntimeError, "Cannot get location from #{vk_name}, #{v_scancode}, #{current_keys}, #{dw_state_names}"
156
+ end
157
+ end
158
+
159
+ # gets the l or r using other params than just the name
160
+ # @see location_less_vks_map
161
+ # @param [Symbol] vk_name
162
+ # @param [Integer] v_scancode
163
+ # @param [Symbol<#{location_less_vks_map.keys}>]
164
+ # @return [String<'l'||'r'>]
165
+ def lr_not_in_name(vk_name, v_scancode, dw_state_names)
166
+ if vk_name == :VK_SHIFT
167
+ if lr = InputRecordUtils.lr_location_from_name(shift_scan_code_to_location_vk[v_scancode])
168
+ lr.downcase
169
+ end
170
+ else
171
+ regexp = location_less_vks_map[vk_name]
172
+ # other side key pressed? weird but eh
173
+ if other_location = current_keys.find {|current| current.key =~ regexp }
174
+ InputRecordUtils.flip_lr_sides(::VDOM::Utils.to_dom_location_common_str(other_location.location)).downcase
175
+ # ok other one isn't being pressed then the one showing up in dw_control_state is this
176
+ else
177
+ applicable_state_names = dw_state_names.grep(regexp)
178
+ # there are no previous keys
179
+ if applicable_state_names.size > 1
180
+ raise "Both `#{vk_name}' are pressed but there is no record in the current keys:#{current_keys.join(',')}"
181
+ elsif location = InputRecordUtils.lr_location_from_name(dw_state_names.grep(regexp).first)
182
+ location.downcase
183
+ end
184
+ end
185
+ end
186
+ end
187
+
188
+ # @see MapVirtualKey,
189
+ # @param [Symbol] virtual_key
190
+ # @param u_char
191
+ # @return [String]
192
+ def dom_key(virtual_key, u_char)
193
+ vk = :"VK_#{virtual_key.to_s.gsub(/^VK_/, '')}"
194
+ # returns 0 when no character available
195
+ if KeyValuesTables::WhitespaceKeys.has_key?(vk) or
196
+ (character = dom_ir_utils_source.map_virtual_key(Map.virtual_key_code(vk), MAPVK::VK_TO_CHAR)) == 0
197
+ KeyTable.dom_key(vk) || UNKNOWN_VAL
198
+ else
199
+ u_char.chr
200
+ end
201
+ end
202
+
203
+ #
204
+ # @param [Symbol] virtual_key
205
+ # @param [String] u_char_value
206
+ # @param [String<"l"||"r"> || Integer] location
207
+ # @raise RuntimeError
208
+ # @return
209
+ def dom_code(virtual_key, u_char_value, location, *dw_state_names)
210
+ if (code = CodeTable.dom_code(Support::Utils.unwrap_ary([*dw_state_names.grep(:ENHANCED_KEY), virtual_key])))
211
+ if code.is_a? Array
212
+ dom_loc = location.is_a?(String) ? ::VDOM::Utils.common_str_to_dom_location(location.upcase) : location
213
+ code.grep(::VDOM::Utils.codes_regex[dom_loc]).first
214
+ else
215
+ code
216
+ end
217
+ else
218
+ if(char = u_char_value.chr) =~ /^[a-z]$/i
219
+ "Key#{char.upcase}"
220
+ elsif char =~ /^[0-9]$/
221
+ "Digit#{char}"
222
+ else
223
+ UNKNOWN_VAL
224
+ end
225
+ end
226
+ end
227
+
228
+ # @see Vigilem::DOM::KeyEvent::alternative_key_names
229
+ # @param [Array] dw_control_state_names
230
+ # @return [Array]
231
+ def dom_modifiers(*dw_control_state_names)
232
+ ::VDOM::KeyboardEvent::shared_keyboard_and_mouse_event_init(dw_control_state_names.map do |mod|
233
+ if mod == :RIGHT_ALT_PRESSED
234
+ :metaKey
235
+ else
236
+ mod.to_s.gsub(/right|left|pressed|on|_/i, '').downcase.to_sym
237
+ end
238
+ end)
239
+ end
240
+
241
+ private
242
+
243
+ attr_writer :dom_ir_utils_source
244
+
245
+ alias_method :dom_ir_utils_src=, :dom_ir_utils_source=
246
+
247
+ #
248
+ # @raise [NotImplementedError]
249
+ # @return
250
+ def dom_ir_utils_source
251
+ @dom_ir_utils_source ||= self
252
+ end
253
+
254
+ alias_method :dom_ir_utils_src=, :dom_ir_utils_source
255
+
256
+ end
257
+ end
258
+ end
259
+ end