vigilem-win32_api 0.0.10
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/LICENSE.txt +22 -0
- data/lib/vigilem/win32_api/console_input_events.rb +78 -0
- data/lib/vigilem/win32_api/constants.rb +97 -0
- data/lib/vigilem/win32_api/dom/adapter.rb +59 -0
- data/lib/vigilem/win32_api/dom/code_values_tables.rb +136 -0
- data/lib/vigilem/win32_api/dom/input_record_utils.rb +259 -0
- data/lib/vigilem/win32_api/dom/key_values_tables.rb +123 -0
- data/lib/vigilem/win32_api/dom.rb +5 -0
- data/lib/vigilem/win32_api/eventable.rb +41 -0
- data/lib/vigilem/win32_api/input__record.rb +53 -0
- data/lib/vigilem/win32_api/input_system_handler.rb +124 -0
- data/lib/vigilem/win32_api/p_input__record.rb +55 -0
- data/lib/vigilem/win32_api/rubyized.rb +114 -0
- data/lib/vigilem/win32_api/types.rb +153 -0
- data/lib/vigilem/win32_api/utils/keyboard.rb +120 -0
- data/lib/vigilem/win32_api/version.rb +5 -0
- data/lib/vigilem/win32_api/virtual_keys/map.rb +211 -0
- data/lib/vigilem/win32_api/virtual_keys.rb +9 -0
- data/lib/vigilem/win32_api.rb +61 -0
- data/spec/acceptance/custom_input_system.feature +3 -0
- data/spec/acceptance/dom_adapter.feature +7 -0
- data/spec/acceptance/rubyized.feature +6 -0
- data/spec/acceptance/steps/custom_input_system_steps.rb +37 -0
- data/spec/acceptance/steps/dom_adapter_steps.rb +7 -0
- data/spec/acceptance/steps/rubyized_steps.rb +20 -0
- data/spec/attributes_and_size_test.rb +10 -0
- data/spec/input_helper.rb +41 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/turnip_helper.rb +1 -0
- data/spec/vigilem/api_spec.rb +139 -0
- data/spec/vigilem/win32_api/console_input_events_spec.rb +67 -0
- data/spec/vigilem/win32_api/dom/adapter_spec.rb +164 -0
- data/spec/vigilem/win32_api/dom/code_values_tables_spec.rb +5 -0
- data/spec/vigilem/win32_api/dom/input_record_utils_spec.rb +255 -0
- data/spec/vigilem/win32_api/dom/key_values_tables_spec.rb +5 -0
- data/spec/vigilem/win32_api/eventable_spec.rb +96 -0
- data/spec/vigilem/win32_api/input__record_spec.rb +113 -0
- data/spec/vigilem/win32_api/input_system_handler_spec.rb +164 -0
- data/spec/vigilem/win32_api/p_input__record_spec.rb +43 -0
- data/spec/vigilem/win32_api/rubyized_spec.rb +134 -0
- data/spec/vigilem/win32_api/types_spec.rb +139 -0
- data/spec/vigilem/win32_api/utils/keyboard_spec.rb +126 -0
- data/spec/vigilem/win32_api/virtual_keys/map_spec.rb +10 -0
- data/spec/vigilem/win32_api/virtual_keys_spec.rb +28 -0
- 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
|