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
@@ -0,0 +1,123 @@
|
|
1
|
+
module Vigilem
|
2
|
+
module Win32API::DOM
|
3
|
+
|
4
|
+
# converts Windows VK if available or VK
|
5
|
+
# https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.code
|
6
|
+
# https://bugzilla.mozilla.org/show_bug.cgi?id=865649
|
7
|
+
module KeyValuesTables
|
8
|
+
key_values = Vigilem::DOM::KeyValues
|
9
|
+
|
10
|
+
ModifierKeys = Support::KeyMap.new({
|
11
|
+
:'' => 'Accel',
|
12
|
+
:VK_MENU => 'Alt',
|
13
|
+
:VK_LMENU => 'Alt',
|
14
|
+
:'' => 'AltGraph',
|
15
|
+
:VK_CAPITAL => 'CapsLock',
|
16
|
+
:VK_CONTROL => 'Control',
|
17
|
+
:VK_LCONTROL => 'Control',
|
18
|
+
:VK_RCONTROL => 'Control',
|
19
|
+
:'' => 'Fn',
|
20
|
+
:'' => 'FnLock',
|
21
|
+
:'' => 'Hyper',
|
22
|
+
:VK_RMENU => 'Meta',
|
23
|
+
:VK_NUMLOCK => 'NumLock',
|
24
|
+
:VK_LWIN => 'OS', #The operating system key (e.g. the "Windows Logo" key).
|
25
|
+
:VK_SCROLL => 'ScrollLock',
|
26
|
+
:VK_SHIFT => 'Shift',
|
27
|
+
:VK_LSHIFT => 'Shift',
|
28
|
+
:VK_RSHIFT => 'Shift',
|
29
|
+
:'' => 'Super',
|
30
|
+
:'' => 'Symbol',
|
31
|
+
:VK_SYMBOL => 'SymbolLock' #0x7A:VK_F11:VK_SYMBOL:Symbol (SYM) key.
|
32
|
+
})
|
33
|
+
|
34
|
+
WhitespaceKeys = Support::KeyMap[[:VK_RETURN, :VK_SEPARATOR, :VK_TAB].zip(key_values::WhitespaceKeys)]
|
35
|
+
#The space or spacebar key is encoded as ' '.
|
36
|
+
|
37
|
+
NavigationKeys = Support::KeyMap[[:VK_DOWN, :VK_LEFT, :VK_RIGHT, :VK_UP,
|
38
|
+
:VK_END, :VK_HOME,:VK_NEXT, :VK_PRIOR].zip(key_values::NavigationKeys)]
|
39
|
+
EditingKeys = Support::KeyMap[[:VK_BACK, :VK_CLEAR, :'', :VK_CRSEL, :'', :VK_DELETE, :VK_EREOF,
|
40
|
+
:VK_EXSEL, :VK_INSERT, :'', :'', :''].zip(key_values::EditingKeys)]
|
41
|
+
UIKeys = Support::KeyMap[[:VK_ACCEPT, #IME accept?
|
42
|
+
:'', :VK_ATTN, :VK_CANCEL, :VK_APPS, :VK_ESCAPE, :VK_EXECUTE,
|
43
|
+
:'', :VK_HELP, :VK_PAUSE, :'', :'',
|
44
|
+
:VK_SCROLL, :VK_ZOOM, :VK_ZOOM].zip(key_values::UIKeys)]
|
45
|
+
DeviceKeys = Support::KeyMap.new({
|
46
|
+
:'' => ['BrightnessDown', 'BrightnessUp', 'Camera', 'Eject', 'LogOff', 'Power', 'PowerOff', 'Hibernate', 'Standby', 'WakeUp'],
|
47
|
+
:VK_SNAPSHOT => 'PrintScreen' #doesn;t work with readconsoleinput
|
48
|
+
})
|
49
|
+
IMEandCompositionKeys = Support::KeyMap.new({
|
50
|
+
:'' => ['AllCandidates', 'Alphanumeric', 'CodeInput', 'Compose', 'GroupFirst', 'GroupLast', 'GroupNext', 'GroupPrevious',
|
51
|
+
'NextCandidate', 'PreviousCandidate', 'SingleCandidate'],
|
52
|
+
:VK_CONVERT => 'Convert',
|
53
|
+
:VK_FINAL => 'FinalMode',
|
54
|
+
:VK_MODECHANGE => 'ModeChange',
|
55
|
+
:VK_NONCONVERT => 'NonConvert',
|
56
|
+
:VK_PROCESSKEY => 'Process'
|
57
|
+
})
|
58
|
+
KeysspecifictoKoreankeyboards = Support::KeyMap.new({
|
59
|
+
:VK_OEM_BACKTAB => 'RomanCharacters', #"RomanCharacters" for Japanese keyboard layout, "Unidentified" for the others.
|
60
|
+
:VK_HANGUEL => 'HangulMode',
|
61
|
+
:VK_HANGUEL => 'HangulMode',
|
62
|
+
:VK_HANJA => 'HanjaMode',
|
63
|
+
:VK_JUNJA => 'JunjaMode'
|
64
|
+
})
|
65
|
+
KeysspecifictoJapanesekeyboards = Support::KeyMap.new({
|
66
|
+
:VK_OEM_ENLW => 'Zenkaku',
|
67
|
+
:VK_OEM_AUTO => 'Hankaku',
|
68
|
+
:'' => ['ZenkakuHankaku', 'Katakana', 'HiraganaKatakana', 'Eisu'],
|
69
|
+
:VK_KANA => 'KanaMode',
|
70
|
+
:VK_KANJI => 'KanjiMode',
|
71
|
+
:VK_OEM_COPY => 'Hiragana' #"Hiragana" for Japanese keyboard layout, "Unidentified" for the others.
|
72
|
+
})
|
73
|
+
General_PurposeFunctionKeys = Support::KeyMap.new({
|
74
|
+
:VK_F1 => 'F1',
|
75
|
+
:VK_F2 => 'F2',
|
76
|
+
:VK_F3 => 'F3',
|
77
|
+
:VK_F4 => 'F4',
|
78
|
+
:VK_F5 => 'F5',
|
79
|
+
:VK_F6 => 'F6',
|
80
|
+
:VK_F7 => 'F7',
|
81
|
+
:VK_F8 => 'F8',
|
82
|
+
:VK_F9 => 'F9',
|
83
|
+
:VK_F10 => 'F10',
|
84
|
+
:VK_F11 => 'F11',
|
85
|
+
:VK_F12 => 'F12',
|
86
|
+
:'' => ['Soft1', 'Soft2', 'Soft3', 'Soft4']
|
87
|
+
})
|
88
|
+
#Mediamedia
|
89
|
+
MultimediaKeys = Support::KeyMap.new({
|
90
|
+
#These are extra keys found on "multimedia" keyboards.
|
91
|
+
:'' => ['Close', 'MailForward', 'MailReply', 'MailSend', 'New', 'Open', 'Save', 'SpellCheck'],
|
92
|
+
:VK_MEDIA_PLAY_PAUSE => 'MediaPlayPause',
|
93
|
+
:VK_LAUNCH_MEDIA_SELECT => 'MediaSelect',
|
94
|
+
:VK_MEDIA_STOP => 'MediaStop',
|
95
|
+
:VK_MEDIA_NEXT_TRACK => 'MediaTrackNext',
|
96
|
+
:VK_MEDIA_PREV_TRACK => 'MediaTrackPrevious',
|
97
|
+
:VK_PRINT => 'Print',
|
98
|
+
:VK_VOLUME_DOWN => 'VolumeDown',
|
99
|
+
:VK_VOLUME_UP => 'VolumeUp',
|
100
|
+
:VK_VOLUME_MUTE => 'VolumeMute'
|
101
|
+
})
|
102
|
+
ApplicationKeys = Support::KeyMap.new({
|
103
|
+
:'' => ['LaunchCalculator', 'LaunchCalendar', 'LaunchMediaPlayer', 'LaunchMusicPlayer',
|
104
|
+
'LaunchMyComputer', 'LaunchScreenSaver', 'LaunchSpreadsheet', 'LaunchWebBrowser',
|
105
|
+
'LaunchWebCam', 'LaunchWordProcessor'],
|
106
|
+
:VK_LAUNCH_MAIL => 'LaunchMail'
|
107
|
+
})
|
108
|
+
BrowserKeys = Support::KeyMap[key_values::BrowserKeys.zip([:VK_BROWSER_BACK, :VK_BROWSER_FAVORITES, :VK_BROWSER_FORWARD, :VK_BROWSER_HOME, :VK_BROWSER_REFRESH, :VK_BROWSER_SEARCH, :VK_BROWSER_STOP])]
|
109
|
+
#The key values for media controllers (e.g. remote controls for
|
110
|
+
#television, audio systems, and set-top boxes) are
|
111
|
+
#derived in part from the consumer electronics technical specifications:
|
112
|
+
MediaControllerKeys = Support::KeyMap[key_values::MediaControllerKeys.zip([:'']).reverse]
|
113
|
+
|
114
|
+
SpecialKeyValues = Support::KeyMap.new({ :'' => 'Unidentified' })
|
115
|
+
|
116
|
+
end
|
117
|
+
KeyTable = KeyValuesTables.constants.each_with_object(Support::KeyMap.new()) {|table_name, memo| memo.merge! KeyValuesTables.const_get(table_name) }
|
118
|
+
KeyTable.default = 'Unidentified'
|
119
|
+
|
120
|
+
KeyTable.right_side_alias(:dom_key)
|
121
|
+
KeyTable.left_side_alias(:win_vk)
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Vigilem::Win32API
|
2
|
+
#
|
3
|
+
# @abstract included into the same module as RubyizedAPI
|
4
|
+
# or respond_to? [:read_console_input, :peek_console_input]
|
5
|
+
module Eventable
|
6
|
+
|
7
|
+
# @param [Integer] limit
|
8
|
+
# @return [Array]
|
9
|
+
def read_many_nonblock(limit=1)
|
10
|
+
[*(read_console_input({:nLength => limit, :blocking => false }) if has_any?)]
|
11
|
+
end
|
12
|
+
|
13
|
+
# blocks until the specified number of events are read
|
14
|
+
# @param [Integer] number_of_events=1
|
15
|
+
# @return [Array]
|
16
|
+
def read_many(number_of_events=1)
|
17
|
+
read_console_input({:nLength => number_of_events, :blocking => true })
|
18
|
+
end
|
19
|
+
|
20
|
+
# non_blocking
|
21
|
+
# commonly used with event processing
|
22
|
+
# @param [Integer]
|
23
|
+
# @return [InputRecord]
|
24
|
+
def read_one_nonblock
|
25
|
+
read_one if has_any?
|
26
|
+
end
|
27
|
+
|
28
|
+
# blocking
|
29
|
+
# reads one event from the input buffer
|
30
|
+
# @return [Array]
|
31
|
+
def read_one
|
32
|
+
read_console_input.shift
|
33
|
+
end
|
34
|
+
|
35
|
+
# checks whether the input buffer has events
|
36
|
+
# @return [TrueClass || FalseClass]
|
37
|
+
def has_any?
|
38
|
+
peek_console_input.size > 0
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Vigilem
|
2
|
+
|
3
|
+
#
|
4
|
+
module Win32API
|
5
|
+
|
6
|
+
|
7
|
+
#
|
8
|
+
class INPUT_RECORD < ::VFFIStruct
|
9
|
+
|
10
|
+
# @!attr [Integer] the ID type of this record
|
11
|
+
layout_with_methods :EventType, :WORD,
|
12
|
+
*(union(:Event) do
|
13
|
+
ConsoleInputEvents.vk_names.map do |event|
|
14
|
+
event.to_s.downcase.titlecase.split(/\s+/).join.to_sym
|
15
|
+
end.sort.zip(ConsoleInputEvents.structs.sort {|klass, other_klass| klass.name <=> other_klass.name }).flatten
|
16
|
+
end)
|
17
|
+
|
18
|
+
#
|
19
|
+
# @return [Hash]
|
20
|
+
def to_h
|
21
|
+
FFIUtils.struct_to_h(self)
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# @return [Integer]
|
26
|
+
def type
|
27
|
+
self.EventType
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# @return [INPUT_RECORD::Union::*_EVENT_RECORD]
|
32
|
+
def event_record
|
33
|
+
self.class.event_record(self)
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# @param input_record [EventUnion?]
|
38
|
+
# @return [INPUT_RECORD::Union::*_EVENT_RECORD]
|
39
|
+
def self.event_record(input_record)
|
40
|
+
sym = ConsoleInputEvents.vk_hash[input_record.EventType].to_s.downcase.titlecase.gsub(/\s+/, '').to_sym
|
41
|
+
input_record.Event[sym] unless sym.nil? or sym.empty?
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# @return [String]
|
46
|
+
def inspect
|
47
|
+
head, tail = super.split(' ', 2)
|
48
|
+
"#{head} event_record=#{event_record.inspect} #{tail}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
InputRecord = INPUT_RECORD
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'vigilem/core/input_system_handler'
|
2
|
+
|
3
|
+
require 'vigilem/core/hub'
|
4
|
+
|
5
|
+
require 'vigilem/core/adapters/buffered_adapter'
|
6
|
+
|
7
|
+
require 'vigilem/win32_api'
|
8
|
+
|
9
|
+
require 'vigilem/win32_api/rubyized'
|
10
|
+
|
11
|
+
require 'vigilem/win32_api/eventable'
|
12
|
+
|
13
|
+
module Vigilem
|
14
|
+
module Win32API
|
15
|
+
|
16
|
+
#
|
17
|
+
class InputSystemHandler
|
18
|
+
|
19
|
+
include Core::InputSystemHandler
|
20
|
+
|
21
|
+
include Core::Adapters::BufferedAdapter
|
22
|
+
|
23
|
+
include Rubyized
|
24
|
+
|
25
|
+
include Eventable
|
26
|
+
|
27
|
+
#
|
28
|
+
# @param lnk
|
29
|
+
def initialize(lnk=nil)
|
30
|
+
initialize_buffered(lnk || Vigilem::Win32API)
|
31
|
+
end
|
32
|
+
|
33
|
+
def win32_api_rubyized_source
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
def_delegator :link, :GetStdHandle
|
38
|
+
|
39
|
+
#
|
40
|
+
# @param [Finum] hConsoleInput
|
41
|
+
# @param [PINPUT_RECORD] lpBuffer, out, this item will be updated
|
42
|
+
# @param [Integer] nLength
|
43
|
+
# @param [::FFI::Pointer] lpNumberOfEventsRead, out, this item will be updated
|
44
|
+
# @return [Integer] 1 or 0
|
45
|
+
def PeekConsoleInput(hConsoleInput, lpBuffer, nLength, lpNumberOfEventsRead)
|
46
|
+
semaphore.synchronize {
|
47
|
+
events = buffered(nLength) do |len_remainder|
|
48
|
+
ret = link.PeekConsoleInputW(hConsoleInput, lpBuffer, nLength, lpNumberOfEventsRead)
|
49
|
+
lpBuffer
|
50
|
+
end
|
51
|
+
_update_out_args(lpBuffer, lpNumberOfEventsRead, events)
|
52
|
+
ret ||= 1
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# @param [Finum] hConsoleInput
|
58
|
+
# @param [PINPUT_RECORD] lpBuffer, out, this item will be updated
|
59
|
+
# @param [Integer] nLength
|
60
|
+
# @param [::FFI::Pointer] lpNumberOfEventsRead, out, this item will be updated
|
61
|
+
# @return [Integer] 1 or 0
|
62
|
+
def ReadConsoleInput(hConsoleInput, lpBuffer, nLength, lpNumberOfEventsRead)
|
63
|
+
semaphore.synchronize {
|
64
|
+
events = buffered!(nLength) do |still_to_get|
|
65
|
+
ret = link.ReadConsoleInputW(hConsoleInput, lpBuffer, still_to_get, lpNumberOfEventsRead)
|
66
|
+
demux(*lpBuffer) unless lpBuffer.empty?
|
67
|
+
lpBuffer
|
68
|
+
end
|
69
|
+
_update_out_args(lpBuffer, lpNumberOfEventsRead, events)
|
70
|
+
ret ||= 1
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# @see
|
76
|
+
# @param [Integer] uCode
|
77
|
+
# @param [Integer] uMapType
|
78
|
+
# @return
|
79
|
+
def MapVirtualKey(uCode, uMapType)
|
80
|
+
# without this it could fail silently
|
81
|
+
raise ArgumentError, "uCode has to be a Integer not #{uCode.class}:`#{uCode}'" unless uCode.is_a? Integer
|
82
|
+
raise ArgumentError, "uMapType has to be a Integer not #{uMapType.class}:`#{uMapType}'" unless uMapType.is_a? Integer
|
83
|
+
link.MapVirtualKeyW(uCode, uMapType)
|
84
|
+
end
|
85
|
+
|
86
|
+
# the hub that sends and receives messages for
|
87
|
+
# this buffer
|
88
|
+
# @raise RuntimeError
|
89
|
+
# @return
|
90
|
+
def hub
|
91
|
+
@hub ||= (Core::Hub.aquire(link()) << self.buffer)
|
92
|
+
end
|
93
|
+
|
94
|
+
#
|
95
|
+
# @see Hub#demux
|
96
|
+
# @param [Array] msgs
|
97
|
+
# @return
|
98
|
+
def demux(*msgs)
|
99
|
+
hub.demux(self, *msgs)
|
100
|
+
end
|
101
|
+
private
|
102
|
+
|
103
|
+
#
|
104
|
+
# @param [PINPUT_RECORD] lpBuffer
|
105
|
+
# @param [::FFI::Pointer] lpNumberOfEventsRead
|
106
|
+
# @param [Array] events
|
107
|
+
# @return [Array]
|
108
|
+
def _update_out_args(lpBuffer, lpNumberOfEventsRead, events)
|
109
|
+
FFIUtils.add_int_typedef(lpNumberOfEventsRead, :dword, evnt_sze = events.size)
|
110
|
+
begin
|
111
|
+
lpBuffer.replace(events + [*lpBuffer[evnt_sze..-1]])
|
112
|
+
rescue ArgumentError => e
|
113
|
+
if e.message =~ /bad value for range/
|
114
|
+
e.message.replace("#{e.message}, #{evnt_sze.inspect}..-1")
|
115
|
+
raise e
|
116
|
+
else
|
117
|
+
raise
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'vigilem/ffi'
|
2
|
+
|
3
|
+
module Vigilem
|
4
|
+
module Win32API
|
5
|
+
|
6
|
+
#
|
7
|
+
class PINPUT_RECORD
|
8
|
+
|
9
|
+
include FFI::ArrayPointerSync
|
10
|
+
|
11
|
+
# @see ArrayPointerSync#initialize_array_sync
|
12
|
+
# @param [Integer || FFI::Pointer] max_len_or_ptr
|
13
|
+
# @param [Array]
|
14
|
+
def initialize(max_len_or_ptr, *init_values)
|
15
|
+
initialize_ary_ptr_sync(max_len_or_ptr, *init_values)
|
16
|
+
end
|
17
|
+
|
18
|
+
class << self
|
19
|
+
|
20
|
+
#
|
21
|
+
# @param [FFI::Pointer]
|
22
|
+
# @return [self]
|
23
|
+
def from_pointer(pointer)
|
24
|
+
new(pointer)
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
# @return [Class || Symbol]
|
29
|
+
def ary_type
|
30
|
+
INPUT_RECORD
|
31
|
+
end
|
32
|
+
|
33
|
+
# Converts the specified value from the native type.
|
34
|
+
# @param value
|
35
|
+
# @param ctx
|
36
|
+
# @return [PINPUT_RECORD]
|
37
|
+
def from_native(value, ctx)
|
38
|
+
new(value)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Converts the specified value to the native type.
|
42
|
+
# @param value
|
43
|
+
# @param ctx
|
44
|
+
# @return [FFI::Pointer]
|
45
|
+
def to_native(value, ctx)
|
46
|
+
value.ptr
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
PInputRecord = PINPUT_RECORD
|
52
|
+
::FFI.typedef(PINPUT_RECORD, :pinput_record)
|
53
|
+
::FFI.typedef(PINPUT_RECORD, :PINPUT_RECORD)
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'vigilem/win32_api'
|
2
|
+
|
3
|
+
module Vigilem::Win32API
|
4
|
+
# @abstract
|
5
|
+
# @see http://msdn.microsoft.com
|
6
|
+
module Rubyized
|
7
|
+
|
8
|
+
include Vigilem::Win32API::Constants
|
9
|
+
|
10
|
+
#
|
11
|
+
# @param [Integer] handle defaults to Vigilem::Win32API::STD_INPUT_HANDLE
|
12
|
+
# @return [Integer]
|
13
|
+
def get_std_handle(handle=Vigilem::Win32API::STD_INPUT_HANDLE)
|
14
|
+
win32_api_rubyized_src.GetStdHandle(handle)
|
15
|
+
end
|
16
|
+
|
17
|
+
#
|
18
|
+
# @param [Hash]
|
19
|
+
# @option opts [Integer] :hConsoleInput
|
20
|
+
# @option opts [PINPUT_RECORD || Array] :lpBuffer
|
21
|
+
# @option opts [Integer] :nLength
|
22
|
+
# @option opts [Integer] :lpNumberOfEventsRead
|
23
|
+
# @return [PINPUT_RECORD]
|
24
|
+
def peek_console_input(opts={})
|
25
|
+
_options(opts)
|
26
|
+
win32_api_rubyized_src.PeekConsoleInput(opts[:hConsoleInput], opts[:lpBuffer], opts[:nLength], opts[:lpNumberOfEventsRead])
|
27
|
+
opts[:lpBuffer]
|
28
|
+
end
|
29
|
+
|
30
|
+
# default behaviour is that of read_console_input (block if no msgs in the buffer,
|
31
|
+
# if opts[:blocking] == true, the method will block until lpBuffer full
|
32
|
+
# if opts[:blocking] == false, there will be no blocking
|
33
|
+
# @param [Hash]
|
34
|
+
# @option opts [Integer] :hConsoleInput
|
35
|
+
# @option opts [PINPUT_RECORD || Array] :lpBuffer
|
36
|
+
# @option opts [Integer] :nLength
|
37
|
+
# @option opts [Integer] :lpNumberOfEventsRead
|
38
|
+
# @return [PINPUT_RECORD]
|
39
|
+
def read_console_input(opts={})
|
40
|
+
_options(opts)
|
41
|
+
|
42
|
+
lp_buffer = []
|
43
|
+
|
44
|
+
if (default = (blocking = opts[:blocking]).nil?) or blocking
|
45
|
+
begin
|
46
|
+
win32_api_rubyized_src.ReadConsoleInput(opts[:hConsoleInput], opts[:lpBuffer], opts[:nLength], opts[:lpNumberOfEventsRead])
|
47
|
+
lp_buffer += opts[:lpBuffer]
|
48
|
+
end while (not default) and lp_buffer.size < opts[:nLength]
|
49
|
+
opts[:lpBuffer].replace(lp_buffer)
|
50
|
+
elsif not peek_console_input.empty?
|
51
|
+
win32_api_rubyized_src.ReadConsoleInput(opts[:hConsoleInput], opts[:lpBuffer], opts[:nLength], opts[:lpNumberOfEventsRead])
|
52
|
+
opts[:lpBuffer]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Translates (maps) a virtual-key code into a scan code or character
|
57
|
+
# value, or translates a scan code into a virtual-key code.
|
58
|
+
# @param [Integer] code, the uCode
|
59
|
+
# @param [Symbol || Integer] conversion, the uMapType, Vigilem::Win32API::Constants::MapType
|
60
|
+
# @raise ArgumentError when conversion is a Symbol and not a valid uMapType name
|
61
|
+
# @raise ArgumentError when conversion is a Integer and not a valid uMapType code
|
62
|
+
# @return [Integer]
|
63
|
+
def map_virtual_key(code, conversion)
|
64
|
+
conversion_value = if conversion.is_a? Symbol
|
65
|
+
raise ArgumentError, "`#{conversion}' is not an available uMapType name" unless MapType.constants.include? conversion
|
66
|
+
API::Rubyized.const_get(conversion)
|
67
|
+
elsif not (@uMapeTypes ||= MapType.constants.map {|const| Vigilem::Win32API::Rubyized.const_get(const) }).include? conversion
|
68
|
+
raise ArgumentError, "`#{conversion}' is not an available uMapType"
|
69
|
+
end
|
70
|
+
win32_api_rubyized_src.MapVirtualKey(code, conversion_value || conversion)
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
# sets up default options for peek and read based
|
76
|
+
# on user input
|
77
|
+
# @note default nLength is 1
|
78
|
+
# @param [Hash] opts
|
79
|
+
# @option opts [Integer] :hConsoleInput
|
80
|
+
# @option opts [Integer] :nLength
|
81
|
+
# @option opts [Win32API::PINPUT_RECORD || Array] :lpBuffer
|
82
|
+
# @option opts [NilClass || Integer] :lpNumberOfEventsRead
|
83
|
+
# @option opts [NilClass || TrueClass || FalseClass] :blocking
|
84
|
+
# @return [Hash]
|
85
|
+
def _options(opts={})
|
86
|
+
opts[:hConsoleInput] ||= get_std_handle()
|
87
|
+
|
88
|
+
if opts[:lpBuffer].is_a? Array
|
89
|
+
opts[:nLength] = opts[:lpBuffer].size
|
90
|
+
opts[:lpBuffer] = Vigilem::Win32API::PINPUT_RECORD.new(opts[:nLength], *opts[:lpBuffer])
|
91
|
+
else
|
92
|
+
opts[:nLength] ||= 1
|
93
|
+
opts[:lpBuffer] ||= Vigilem::Win32API::PINPUT_RECORD.new(opts[:nLength])
|
94
|
+
end
|
95
|
+
opts[:lpNumberOfEventsRead] ||= FFI::MemoryPointer.new(:DWORD, 1)
|
96
|
+
|
97
|
+
opts
|
98
|
+
end
|
99
|
+
|
100
|
+
attr_writer :win32_api_rubyized_source
|
101
|
+
|
102
|
+
alias_method :win32_api_rubyized_src=, :win32_api_rubyized_source=
|
103
|
+
|
104
|
+
#
|
105
|
+
# @raise [NotImplementedError]
|
106
|
+
# @return
|
107
|
+
def win32_api_rubyized_source
|
108
|
+
@win32_api_rubyized_source ||= self
|
109
|
+
end
|
110
|
+
|
111
|
+
alias_method :win32_api_rubyized_src, :win32_api_rubyized_source
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
require 'vigilem/core'
|
4
|
+
|
5
|
+
module Vigilem
|
6
|
+
module Win32API
|
7
|
+
|
8
|
+
#
|
9
|
+
module Types
|
10
|
+
|
11
|
+
extend ::FFI::Library
|
12
|
+
|
13
|
+
# Check for 64b operating systems.
|
14
|
+
if Vigilem::Core::System.x64bit?
|
15
|
+
::FFI.typedef(:uint64, :ulong_ptr)
|
16
|
+
::FFI.typedef(:int64, :long_ptr)
|
17
|
+
else
|
18
|
+
::FFI.typedef(:ulong, :ulong_ptr)
|
19
|
+
::FFI.typedef(:long, :long_ptr)
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
#
|
24
|
+
module PVOID
|
25
|
+
extend ::FFI::DataConverter
|
26
|
+
native_type ::FFI::Type::POINTER
|
27
|
+
|
28
|
+
class << self
|
29
|
+
# Converts the specified value from the native type.
|
30
|
+
# @return [Bignum, Integer]
|
31
|
+
def from_native(value, ctx)
|
32
|
+
value.address
|
33
|
+
end
|
34
|
+
|
35
|
+
# Converts the specified value to the native type.
|
36
|
+
# @return [::FFI::Pointer]
|
37
|
+
def to_native(value, ctx)
|
38
|
+
case
|
39
|
+
when value.kind_of?(::FFI::Pointer)
|
40
|
+
value
|
41
|
+
when value.kind_of?(::FFI::Struct)
|
42
|
+
value.to_ptr
|
43
|
+
else
|
44
|
+
::FFI::Pointer.new(value.to_i)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
#
|
52
|
+
class PBYTE
|
53
|
+
|
54
|
+
include ::Vigilem::FFI::ArrayPointerSync
|
55
|
+
|
56
|
+
# @see ArrayPointerSync#initialize_array_sync
|
57
|
+
# @param [Integer || ::FFI::Pointer] max_len_or_ptr
|
58
|
+
# @param [Array]
|
59
|
+
def initialize(max_len_or_ptr, *init_values)
|
60
|
+
initialize_array_sync(max_len_or_ptr, *init_values)
|
61
|
+
end
|
62
|
+
|
63
|
+
class << self
|
64
|
+
|
65
|
+
#
|
66
|
+
# [Class || Symbol]
|
67
|
+
def array_type
|
68
|
+
:BYTE
|
69
|
+
end
|
70
|
+
|
71
|
+
# Converts the specified value from the native type.
|
72
|
+
# @return [Integer]
|
73
|
+
def from_native(value, ctx)
|
74
|
+
new(value)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Converts the specified value to the native type.
|
78
|
+
# @return [::FFI::Pointer]
|
79
|
+
def to_native(value, ctx)
|
80
|
+
case
|
81
|
+
when value.is_a?(::FFI::Pointer)
|
82
|
+
value
|
83
|
+
when value.is_a?(self)
|
84
|
+
value.ptr
|
85
|
+
else
|
86
|
+
raise "#{value} is an Unsupported Type"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
::FFI.typedef(PVOID, :p_void)
|
93
|
+
::FFI.typedef(PVOID, :PVOID)
|
94
|
+
|
95
|
+
::FFI.typedef(PBYTE, :PBYTE)
|
96
|
+
|
97
|
+
::FFI.typedef(:p_void, :handle)
|
98
|
+
::FFI.typedef(:PVOID, :HANDLE)
|
99
|
+
|
100
|
+
::FFI.typedef(:handle, :h_wnd)
|
101
|
+
::FFI.typedef(:h_wnd, :HWND)
|
102
|
+
|
103
|
+
::FFI.typedef(:ushort, :word)
|
104
|
+
::FFI.typedef(:word, :WORD)
|
105
|
+
|
106
|
+
::FFI.typedef(:ushort, :wchar)
|
107
|
+
::FFI.typedef(:wchar, :WCHAR)
|
108
|
+
|
109
|
+
::FFI.typedef(:ushort, :char)
|
110
|
+
::FFI.typedef(:char, :CHAR)
|
111
|
+
|
112
|
+
::FFI.typedef(:uint, :dword)
|
113
|
+
::FFI.typedef(:uint, :DWORD)
|
114
|
+
|
115
|
+
::FFI.typedef(:uint, :UINT)
|
116
|
+
|
117
|
+
::FFI.typedef(:int, :BOOL)
|
118
|
+
|
119
|
+
::FFI.typedef(:uchar, :BYTE)
|
120
|
+
|
121
|
+
::FFI.typedef(:ulong_ptr, :WPARAM)
|
122
|
+
::FFI.typedef(:long_ptr, :LPARAM)
|
123
|
+
|
124
|
+
|
125
|
+
#
|
126
|
+
class POINT < ::VFFIStruct
|
127
|
+
layout_with_methods :x, :long,
|
128
|
+
:y, :long
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
#
|
133
|
+
class MSG < ::VFFIStruct
|
134
|
+
layout_with_methods :hwnd, :HWND,
|
135
|
+
:message, :uint,
|
136
|
+
:wParam, :WPARAM,
|
137
|
+
:lParam, :LPARAM,
|
138
|
+
:time, :DWORD,
|
139
|
+
:pt, POINT
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
#
|
144
|
+
class COORD < ::VFFIStruct
|
145
|
+
layout_with_methods :x, :short,
|
146
|
+
:y, :short
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
include Types
|
152
|
+
end
|
153
|
+
end
|