mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
parent
46c6da9c37
commit
5b9f3ed326
2 changed files with 110 additions and 39 deletions
|
@ -181,47 +181,38 @@ class Reline::Windows
|
||||||
name =~ /(msys-|cygwin-).*-pty/ ? true : false
|
name =~ /(msys-|cygwin-).*-pty/ ? true : false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
KEY_MAP = [
|
||||||
|
# It's treated as Meta+Enter on Windows.
|
||||||
|
[ { control_keys: :CTRL, virtual_key_code: 0x0D }, "\e\r".bytes ],
|
||||||
|
[ { control_keys: :SHIFT, virtual_key_code: 0x0D }, "\e\r".bytes ],
|
||||||
|
|
||||||
|
# It's treated as Meta+Space on Windows.
|
||||||
|
[ { control_keys: :CTRL, char_code: 0x20 }, "\e ".bytes ],
|
||||||
|
|
||||||
|
# Emulate getwch() key sequences.
|
||||||
|
[ { control_keys: [], virtual_key_code: VK_UP }, [0, 72] ],
|
||||||
|
[ { control_keys: [], virtual_key_code: VK_DOWN }, [0, 80] ],
|
||||||
|
[ { control_keys: [], virtual_key_code: VK_RIGHT }, [0, 77] ],
|
||||||
|
[ { control_keys: [], virtual_key_code: VK_LEFT }, [0, 75] ],
|
||||||
|
[ { control_keys: [], virtual_key_code: VK_DELETE }, [0, 83] ],
|
||||||
|
[ { control_keys: [], virtual_key_code: VK_HOME }, [0, 71] ],
|
||||||
|
[ { control_keys: [], virtual_key_code: VK_END }, [0, 79] ],
|
||||||
|
]
|
||||||
|
|
||||||
def self.process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
|
def self.process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
|
||||||
char = char_code.chr(Encoding::UTF_8)
|
|
||||||
if char_code == 0x0D and control_key_state.anybits?(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED | SHIFT_PRESSED)
|
key = KeyEventRecord.new(virtual_key_code, char_code, control_key_state)
|
||||||
# It's treated as Meta+Enter on Windows.
|
|
||||||
@@output_buf.push("\e".ord)
|
match = KEY_MAP.find { |args,| key.matches?(**args) }
|
||||||
@@output_buf.push(char_code)
|
unless match.nil?
|
||||||
elsif char_code == 0x20 and control_key_state.anybits?(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
|
@@output_buf.concat(match.last)
|
||||||
# It's treated as Meta+Space on Windows.
|
return
|
||||||
@@output_buf.push("\e".ord)
|
|
||||||
@@output_buf.push(char_code)
|
|
||||||
elsif control_key_state.anybits?(ENHANCED_KEY)
|
|
||||||
case virtual_key_code # Emulate getwch() key sequences.
|
|
||||||
when VK_END
|
|
||||||
@@output_buf.push(0, 79)
|
|
||||||
when VK_HOME
|
|
||||||
@@output_buf.push(0, 71)
|
|
||||||
when VK_LEFT
|
|
||||||
@@output_buf.push(0, 75)
|
|
||||||
when VK_UP
|
|
||||||
@@output_buf.push(0, 72)
|
|
||||||
when VK_RIGHT
|
|
||||||
@@output_buf.push(0, 77)
|
|
||||||
when VK_DOWN
|
|
||||||
@@output_buf.push(0, 80)
|
|
||||||
when VK_DELETE
|
|
||||||
@@output_buf.push(0, 83)
|
|
||||||
when VK_RETURN
|
|
||||||
@@output_buf.push(char_code) # must be 0x0D
|
|
||||||
when VK_DIVIDE
|
|
||||||
@@output_buf.push(char_code)
|
|
||||||
end
|
|
||||||
elsif char_code == 0 and control_key_state != 0
|
|
||||||
# unknown
|
|
||||||
else
|
|
||||||
case virtual_key_code
|
|
||||||
when VK_RETURN
|
|
||||||
@@output_buf.push("\n".ord)
|
|
||||||
else
|
|
||||||
@@output_buf.concat(char.bytes)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# no char, only control keys
|
||||||
|
return if key.char_code == 0 and key.control_keys.any?
|
||||||
|
|
||||||
|
@@output_buf.concat(key.char.bytes)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.check_input_event
|
def self.check_input_event
|
||||||
|
@ -362,4 +353,43 @@ class Reline::Windows
|
||||||
def self.deprep(otio)
|
def self.deprep(otio)
|
||||||
# do nothing
|
# do nothing
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class KeyEventRecord
|
||||||
|
|
||||||
|
attr_reader :virtual_key_code, :char_code, :control_key_state, :control_keys
|
||||||
|
|
||||||
|
def initialize(virtual_key_code, char_code, control_key_state)
|
||||||
|
@virtual_key_code = virtual_key_code
|
||||||
|
@char_code = char_code
|
||||||
|
@control_key_state = control_key_state
|
||||||
|
@enhanced = control_key_state & ENHANCED_KEY != 0
|
||||||
|
|
||||||
|
(@control_keys = []).tap do |control_keys|
|
||||||
|
# symbols must be sorted to make comparison is easier later on
|
||||||
|
control_keys << :ALT if control_key_state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) != 0
|
||||||
|
control_keys << :CTRL if control_key_state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) != 0
|
||||||
|
control_keys << :SHIFT if control_key_state & SHIFT_PRESSED != 0
|
||||||
|
end.freeze
|
||||||
|
end
|
||||||
|
|
||||||
|
def char
|
||||||
|
@char_code.chr(Encoding::UTF_8)
|
||||||
|
end
|
||||||
|
|
||||||
|
def enhanced?
|
||||||
|
@enhanced
|
||||||
|
end
|
||||||
|
|
||||||
|
# Verifies if the arguments match with this key event.
|
||||||
|
# Nil arguments are ignored, but at least one must be passed as non-nil.
|
||||||
|
# To verify that no control keys were pressed, pass an empty array: `control_keys: []`.
|
||||||
|
def matches?(control_keys: nil, virtual_key_code: nil, char_code: nil)
|
||||||
|
raise ArgumentError, 'No argument was passed to match key event' if control_keys.nil? && virtual_key_code.nil? && char_code.nil?
|
||||||
|
|
||||||
|
(control_keys.nil? || [*control_keys].sort == @control_keys) &&
|
||||||
|
(virtual_key_code.nil? || @virtual_key_code == virtual_key_code) &&
|
||||||
|
(char_code.nil? || char_code == @char_code)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
41
test/reline/windows/test_key_event_record.rb
Normal file
41
test/reline/windows/test_key_event_record.rb
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
require_relative '../helper'
|
||||||
|
require 'reline/windows'
|
||||||
|
|
||||||
|
class Reline::Windows
|
||||||
|
class KeyEventRecord::Test < Reline::TestCase
|
||||||
|
|
||||||
|
def setup
|
||||||
|
# Ctrl+A
|
||||||
|
@key = Reline::Windows::KeyEventRecord.new(0x41, 1, Reline::Windows::LEFT_CTRL_PRESSED)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_matches__with_no_arguments_raises_error
|
||||||
|
assert_raises(ArgumentError) { @key.matches? }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_matches_char_code
|
||||||
|
assert_true @key.matches?(char_code: 0x1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_matches_virtual_key_code
|
||||||
|
assert_true @key.matches?(virtual_key_code: 0x41)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_matches_control_keys
|
||||||
|
assert_true @key.matches?(control_keys: :CTRL)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_doesnt_match_alt
|
||||||
|
assert_false @key.matches?(control_keys: :ALT)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_doesnt_match_empty_control_key
|
||||||
|
assert_false @key.matches?(control_keys: [])
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_matches_control_keys_and_virtual_key_code
|
||||||
|
assert_true @key.matches?(control_keys: :CTRL, virtual_key_code: 0x41)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
Loading…
Add table
Add a link
Reference in a new issue