Module: Vigilem::Win32API::DOM::InputRecordUtils Abstract

Includes:
Constants, CodeValuesTables, Utils::Keyboard, VirtualKeys
Included in:
Adapter
Defined in:
lib/vigilem/win32_api/dom/input_record_utils.rb

Overview

This module is abstract.

requires a dom_ir_utils_source method and included into the same module as RubyizedAPI

TODO:

module KeyEventRecordUtils

msdn.microsoft.com/en-us/library/windows/desktop/dd375731%28v=vs.85%29.aspx methods to convert InputRecords to DOM Events

Constant Summary collapse

NULL_STR =
"\x00"
UNKNOWN_VAL =
'Unidentified'

Constants included from VirtualKeys

VirtualKeys::Map, VirtualKeys::VK

Constants included from CodeValuesTables

CodeValuesTables::ArrowPadSection, CodeValuesTables::ControlPadSection, CodeValuesTables::FunctionSection, CodeValuesTables::FunctionalKeys, CodeValuesTables::LegacyKeysandNon_StandardKeys, CodeValuesTables::MediaKeys, CodeValuesTables::NumpadSection, CodeValuesTables::WritingSystemKeys

Constants included from Constants

Constants::BACKGROUND_BLUE, Constants::BACKGROUND_GREEN, Constants::BACKGROUND_INTENSITY, Constants::BACKGROUND_RED, Constants::CONSOLE_TEXTMODE_BUFFER, Constants::DOUBLE_CLICK, Constants::ENABLE_ECHO_INPUT, Constants::ENABLE_LINE_INPUT, Constants::ENABLE_MOUSE_INPUT, Constants::ENABLE_PROCESSED_INPUT, Constants::ENABLE_PROCESSED_OUTPUT, Constants::ENABLE_WINDOW_INPUT, Constants::ENABLE_WRAP_AT_EOL_OUTPUT, Constants::FILE_SHARE_READ, Constants::FILE_SHARE_WRITE, Constants::FOREGROUND_BLUE, Constants::FOREGROUND_GREEN, Constants::FOREGROUND_INTENSITY, Constants::FOREGROUND_RED, Constants::FROM_LEFT_1ST_BUTTON_PRESSED, Constants::FROM_LEFT_2ND_BUTTON_PRESSED, Constants::FROM_LEFT_3RD_BUTTON_PRESSED, Constants::FROM_LEFT_4TH_BUTTON_PRESSED, Constants::GENERIC_READ, Constants::GENERIC_WRITE, Constants::INVALID_HANDLE_VALUE, Constants::MOUSE_MOVED, Constants::MOUSE_WHEELED, Constants::MapVK, Constants::RIGHTMOST_BUTTON_PRESSED, Constants::STD_ERROR_HANDLE, Constants::STD_INPUT_HANDLE, Constants::STD_OUTPUT_HANDLE

Constants included from Constants::MapType

Constants::MapType::MAPVK, Constants::MapType::MAPVK_VK_TO_CHAR, Constants::MapType::MAPVK_VK_TO_VSC, Constants::MapType::MAPVK_VSC_TO_VK, Constants::MapType::MAPVK_VSC_TO_VK_EX

Constants included from Constants::Events

Constants::Events::CTRL_BREAK_EVENT, Constants::Events::CTRL_CLOSE_EVENT, Constants::Events::CTRL_C_EVENT, Constants::Events::CTRL_LOGOFF_EVENT, Constants::Events::CTRL_SHUTDOWN_EVENT, Constants::Events::FOCUS_EVENT, Constants::Events::KEY_EVENT, Constants::Events::MENU_EVENT, Constants::Events::MOUSE_EVENT, Constants::Events::WINDOW_BUFFER_SIZE_EVENT

Constants included from Constants::DWControlKeys

Constants::DWControlKeys::CAPSLOCK_ON, Constants::DWControlKeys::ENHANCED_KEY, Constants::DWControlKeys::LEFT_ALT_PRESSED, Constants::DWControlKeys::LEFT_CTRL_PRESSED, Constants::DWControlKeys::NUMLOCK_ON, Constants::DWControlKeys::RIGHT_ALT_PRESSED, Constants::DWControlKeys::RIGHT_CTRL_PRESSED, Constants::DWControlKeys::SCROLLLOCK_ON, Constants::DWControlKeys::SHIFT_PRESSED

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Utils::Keyboard::ControlPadKeys

#control_pad_key?

Methods included from Utils::Keyboard::NavigationKeys

#arrow_key?, #nav_arrow_key?, #nav_control_key?

Methods included from Utils::Keyboard::NumpadKeys

#numlock?, #numpad?, #numpad_arrow?, #numpad_control_key?, #numpad_number_function?, #numpad_return?

Class Method Details

.empty_or_null?(str) ⇒ TrueClass || FalseClass

is #empty? or just contains NULL_STR

Parameters:

  • str, (String)

    value to test

Returns:

  • (TrueClass || FalseClass)

    whether or not the String



127
128
129
# File 'lib/vigilem/win32_api/dom/input_record_utils.rb', line 127

def empty_or_null?(str)
  str.strip.empty? or (str == NULL_STR * str.length)
end

.flip_lr_sides(str) ⇒ String<'R'||'r'||'L'||'l'>

Returns its opposite.

Parameters:

  • str, (String<'L'||'l'||'R'||'r'>)

    to convert

Returns:

  • (String<'R'||'r'||'L'||'l'>)

    its opposite



112
113
114
# File 'lib/vigilem/win32_api/dom/input_record_utils.rb', line 112

def flip_lr_sides(str)
  str.tr('LlRr', 'RrLl')
end

.lr_location_from_name(key_name) ⇒ String || NilClass

Parameters:

  • key_name (Symbol)

Returns:

  • (String || NilClass)


119
120
121
# File 'lib/vigilem/win32_api/dom/input_record_utils.rb', line 119

def lr_location_from_name(key_name)
  key_name.to_s.gsub(/VK_(L(?!EFT)|R(?!IGHT))?.+/, '\1')[/L|R/]
end

Instance Method Details

#current_keysArray

the current keys being pressed

Returns:

  • (Array)


36
37
38
# File 'lib/vigilem/win32_api/dom/input_record_utils.rb', line 36

def current_keys
  @current_keys ||= []
end

#dom_code(virtual_key, u_char_value, location, *dw_state_names) ⇒ Object

Parameters:

  • virtual_key (Symbol)
  • u_char_value (String)
  • location (String<"l"||"r"> || Integer)

Returns:

Raises:

  • RuntimeError



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/vigilem/win32_api/dom/input_record_utils.rb', line 209

def dom_code(virtual_key, u_char_value, location, *dw_state_names)
  if (code = CodeTable.dom_code(Support::Utils.unwrap_ary([*dw_state_names.grep(:ENHANCED_KEY), virtual_key])))
    if code.is_a? Array
      dom_loc = location.is_a?(String) ? ::VDOM::Utils.common_str_to_dom_location(location.upcase) : location
      code.grep(::VDOM::Utils.codes_regex[dom_loc]).first
    else
      code
    end
  else
    if(char = u_char_value.chr) =~ /^[a-z]$/i
      "Key#{char.upcase}"
    elsif char =~ /^[0-9]$/
      "Digit#{char}"
    else
      UNKNOWN_VAL
    end
  end
end

#dom_key(virtual_key, u_char) ⇒ String

Parameters:

  • virtual_key (Symbol)
  • u_char

Returns:

  • (String)

See Also:

  • MapVirtualKey,


192
193
194
195
196
197
198
199
200
201
# File 'lib/vigilem/win32_api/dom/input_record_utils.rb', line 192

def dom_key(virtual_key, u_char)
  vk = :"VK_#{virtual_key.to_s.gsub(/^VK_/, '')}"
     # returns 0 when no character available
  if KeyValuesTables::WhitespaceKeys.has_key?(vk) or
    (character = dom_ir_utils_source.map_virtual_key(Map.virtual_key_code(vk), MAPVK::VK_TO_CHAR)) == 0
    KeyTable.dom_key(vk) || UNKNOWN_VAL
  else
    u_char.chr
  end
end

#dom_location(vk_name, v_scancode, dw_state_names) ⇒ Integer<0|1|2>

Parameters:

  • vk_name (Symbol)
  • dw_state_names (Array<Symbol>)

Returns:

  • (Integer<0|1|2>)


137
138
139
140
141
142
# File 'lib/vigilem/win32_api/dom/input_record_utils.rb', line 137

def dom_location(vk_name, v_scancode, dw_state_names)
  l_r_location = InputRecordUtils.lr_location_from_name(vk_name) ||
                 lr_not_in_name(vk_name, v_scancode, dw_state_names) || ""
  
  ::VDOM::Utils.common_str_to_dom_location(l_r_location.upcase) || DOM_KEY_LOCATION_STANDARD
end

#dom_modifiers(*dw_control_state_names) ⇒ Array

Parameters:

  • dw_control_state_names (Array)

Returns:

  • (Array)

See Also:

  • DOM::KeyEvent::alternative_key_names


231
232
233
234
235
236
237
238
239
# File 'lib/vigilem/win32_api/dom/input_record_utils.rb', line 231

def dom_modifiers(*dw_control_state_names)
  ::VDOM::KeyboardEvent::shared_keyboard_and_mouse_event_init(dw_control_state_names.map do |mod| 
      if mod == :RIGHT_ALT_PRESSED
        :metaKey
      else
        mod.to_s.gsub(/right|left|pressed|on|_/i, '').downcase.to_sym
      end
    end)
end

#dw_control_key_state_vks(dw_control_key_state) ⇒ Array<Symbol>

converts a Integer representing dwControlKeyState from KEY_EVENT_RECORD to an array of virtual-keys, Symbols

Parameters:

  • dw_control_key_state (Integer)

Returns:

  • (Array<Symbol>)

    the win modifiers



82
83
84
85
86
# File 'lib/vigilem/win32_api/dom/input_record_utils.rb', line 82

def dw_control_key_state_vks(dw_control_key_state)
  DWControlKeys.constants.select do |const|
    (dw_control_key_state & (value = DWControlKeys.const_get(const))) == value
  end
end

#location_less_vks_mapHash

Returns:

  • (Hash)


90
91
92
# File 'lib/vigilem/win32_api/dom/input_record_utils.rb', line 90

def location_less_vks_map
  @location_less_vks_map ||= {:VK_MENU => /alt/i, :VK_CONTROL => /control|ctrl/i, :VK_SHIFT => /shift/i }
end

#lr_not_in_name(vk_name, v_scancode, dw_state_names) ⇒ String<'l'||'r'>

gets the l or r using other params than just the name

Parameters:

  • vk_name (Symbol)
  • v_scancode (Integer)
  • ] (Symbol<#location_less_vks_mapp.keys})

Returns:

  • (String<'l'||'r'>)

See Also:



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/vigilem/win32_api/dom/input_record_utils.rb', line 165

def lr_not_in_name(vk_name, v_scancode, dw_state_names)
  if vk_name == :VK_SHIFT
    if lr = InputRecordUtils.lr_location_from_name(shift_scan_code_to_location_vk[v_scancode])
      lr.downcase
    end
  else
    regexp = location_less_vks_map[vk_name]
    # other side key pressed? weird but eh
    if other_location = current_keys.find {|current| current.key =~ regexp }
      InputRecordUtils.flip_lr_sides(::VDOM::Utils.to_dom_location_common_str(other_location.location)).downcase
    # ok other one isn't being pressed then the one showing up in dw_control_state is this
    else
      applicable_state_names = dw_state_names.grep(regexp)
      # there are no previous keys 
      if applicable_state_names.size > 1
        raise "Both `#{vk_name}' are pressed but there is no record in the current keys:#{current_keys.join(',')}"
      elsif location = InputRecordUtils.lr_location_from_name(dw_state_names.grep(regexp).first)
        location.downcase
      end
    end
  end
end

#lr_not_in_name!(vk_name, v_scancode, dw_state_names) ⇒ String<'l'|'r'>

gets the l or r using other params than just the name

Parameters:

  • vk_name (Symbol)
  • v_scancode (Integer)
  • ] (Symbol<#location_less_vks_mapp.keys})

Returns:

  • (String<'l'|'r'>)

Raises:

  • (RuntimeError)

    when the location cannot be found

See Also:



151
152
153
154
155
156
157
# File 'lib/vigilem/win32_api/dom/input_record_utils.rb', line 151

def lr_not_in_name!(vk_name, v_scancode, dw_state_names)
  if lr = lr_not_in_name(vk_name, v_scancode, dw_state_names)
    lr
  else
    raise RuntimeError, "Cannot get location from #{vk_name}, #{v_scancode}, #{current_keys}, #{dw_state_names}"
  end
end

#shift_scan_code_to_location_vkHash

Returns:

  • (Hash)


103
104
105
106
# File 'lib/vigilem/win32_api/dom/input_record_utils.rb', line 103

def shift_scan_code_to_location_vk
  @shift_scan_location ||= { dom_ir_utils_source.map_virtual_key(VK[:LSHIFT], MAPVK::VK_TO_VSC) => :VK_LSHIFT, 
                             dom_ir_utils_source.map_virtual_key(VK[:RSHIFT], MAPVK::VK_TO_VSC) => :VK_RSHIFT }
end

#to_dom_key_event(event_record) ⇒ Array<Vigilem::DOM::KeyboardEvent>

Note:

the righ Alt and right ctrl are ‘enhanced’

converts and event_record to DOM KeyEvent

Parameters:

  • []

    event_record

Returns:

  • (Array<Vigilem::DOM::KeyboardEvent>)


44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/vigilem/win32_api/dom/input_record_utils.rb', line 44

def to_dom_key_event(event_record)
  dw_state_names = dw_control_key_state_vks(event_record.dwControlKeyState)
                
                # all test need fixed
                # will this work for a range? if not it needs to 
  virtual_key_name = Map.virtual_keyname(vk_code = event_record.wVirtualKeyCode)
  
  modifiers = dom_modifiers(*dw_state_names)
  
  dom_loc = dom_location(virtual_key_name, event_record.wVirtualScanCode, dw_state_names)
  
  key = dom_key(virtual_key_name, u_char = event_record.uChar.UnicodeChar)
  
  code = dom_code(virtual_key_name, u_char, dom_loc, *dw_state_names)
  
  options = {:key => key, :code => code, :location => dom_loc, :repeat => false, 
                          :modifiers => modifiers, :os_specific => ::FFIUtils.struct_to_h(event_record) }
  
  if event_record.bKeyDown == 1
    if (prev_event = current_keys.last) and %w(keypress keydown).include?(prev_event.type) and prev_event.key == options[:key]
      options[:repeat] = true
    end
    
    key_event = ::VDOM::KeyboardEvent.new('keydown', options)
    key_down_events = [key_event, key_event.copy_to('keypress')]
    @current_keys += key_down_events.flatten
    key_down_events
  else
    key_event = ::VDOM::KeyboardEvent.new('keyup', options)
    current_keys.delete_if {|current| current.key == key_event.key and current.location == key_event.location }
    [*key_event].flatten
  end
end

#vk_without_location_info?(vk_name) ⇒ TrueClass || FalseClass

Parameters:

  • vk_name (Symbol)

Returns:

  • (TrueClass || FalseClass)


97
98
99
# File 'lib/vigilem/win32_api/dom/input_record_utils.rb', line 97

def vk_without_location_info?(vk_name)
  location_less_vks_map.keys.include? vk_name
end