class Reline::Windows
Constants
- CAPSLOCK_ON
- ENABLE_VIRTUAL_TERMINAL_PROCESSING
- ENHANCED_KEY
- FILE_NAME_INFO
- FILE_TYPE_PIPE
- KEY_EVENT
- KEY_MAP
- LEFT_ALT_PRESSED
- LEFT_CTRL_PRESSED
- NUMLOCK_ON
- RIGHT_ALT_PRESSED
- RIGHT_CTRL_PRESSED
- SCROLLLOCK_ON
- SHIFT_PRESSED
- STD_INPUT_HANDLE
- STD_OUTPUT_HANDLE
- VK_CONTROL
- VK_DELETE
- VK_DIVIDE
- VK_DOWN
- VK_END
- VK_HOME
- VK_LEFT
- VK_LMENU
- VK_MENU
- VK_RETURN
- VK_RIGHT
- VK_SHIFT
- VK_TAB
- VK_UP
- WINDOW_BUFFER_SIZE_EVENT
Public Class Methods
check_input_event()
click to toggle source
# File reline/windows.rb, line 257 def self.check_input_event num_of_events = 0.chr * 8 while @@output_buf.empty? Reline.core.line_editor.resize if @@WaitForSingleObject.(@@hConsoleInputHandle, 100) != 0 # max 0.1 sec # prevent for background consolemode change @@legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0) next end next if @@GetNumberOfConsoleInputEvents.(@@hConsoleInputHandle, num_of_events) == 0 or num_of_events.unpack1('L') == 0 input_records = 0.chr * 20 * 80 read_event = 0.chr * 4 if @@ReadConsoleInputW.(@@hConsoleInputHandle, input_records, 80, read_event) != 0 read_events = read_event.unpack1('L') 0.upto(read_events) do |idx| input_record = input_records[idx * 20, 20] event = input_record[0, 2].unpack1('s*') case event when WINDOW_BUFFER_SIZE_EVENT @@winch_handler.() when KEY_EVENT key_down = input_record[4, 4].unpack1('l*') repeat_count = input_record[8, 2].unpack1('s*') virtual_key_code = input_record[10, 2].unpack1('s*') virtual_scan_code = input_record[12, 2].unpack1('s*') char_code = input_record[14, 2].unpack1('S*') control_key_state = input_record[16, 2].unpack1('S*') is_key_down = key_down.zero? ? false : true if is_key_down process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state) end end end end end end
clear_screen()
click to toggle source
# File reline/windows.rb, line 417 def self.clear_screen if @@legacy_console return unless csbi = get_console_screen_buffer_info buffer_width, _buffer_lines, attributes, window_top, window_bottom = csbi.unpack('ss@8S@12sx2s') fill_length = buffer_width * (window_bottom - window_top + 1) screen_topleft = window_top * 65536 written = 0.chr * 4 @@FillConsoleOutputCharacter.call(@@hConsoleHandle, 0x20, fill_length, screen_topleft, written) @@FillConsoleOutputAttribute.call(@@hConsoleHandle, attributes, fill_length, screen_topleft, written) @@SetConsoleCursorPosition.call(@@hConsoleHandle, screen_topleft) else @@output.write "\e[2J" "\e[H" end end
cursor_pos()
click to toggle source
# File reline/windows.rb, line 346 def self.cursor_pos unless csbi = get_console_screen_buffer_info return Reline::CursorPos.new(0, 0) end x = csbi[4, 2].unpack1('s') y = csbi[6, 2].unpack1('s') Reline::CursorPos.new(x, y) end
deprep(otio)
click to toggle source
# File reline/windows.rb, line 459 def self.deprep(otio) # do nothing end
empty_buffer?()
click to toggle source
# File reline/windows.rb, line 311 def self.empty_buffer? if not @@output_buf.empty? false elsif @@kbhit.call == 0 true else false end end
encoding()
click to toggle source
# File reline/windows.rb, line 4 def self.encoding Encoding::UTF_8 end
erase_after_cursor()
click to toggle source
# File reline/windows.rb, line 381 def self.erase_after_cursor return unless csbi = get_console_screen_buffer_info attributes = csbi[8, 2].unpack1('S') cursor = csbi[4, 4].unpack1('L') written = 0.chr * 4 @@FillConsoleOutputCharacter.call(@@hConsoleHandle, 0x20, get_screen_size.last - cursor_pos.x, cursor, written) @@FillConsoleOutputAttribute.call(@@hConsoleHandle, attributes, get_screen_size.last - cursor_pos.x, cursor, written) end
get_console_screen_buffer_info()
click to toggle source
# File reline/windows.rb, line 321 def self.get_console_screen_buffer_info # CONSOLE_SCREEN_BUFFER_INFO # [ 0,2] dwSize.X # [ 2,2] dwSize.Y # [ 4,2] dwCursorPositions.X # [ 6,2] dwCursorPositions.Y # [ 8,2] wAttributes # [10,2] srWindow.Left # [12,2] srWindow.Top # [14,2] srWindow.Right # [16,2] srWindow.Bottom # [18,2] dwMaximumWindowSize.X # [20,2] dwMaximumWindowSize.Y csbi = 0.chr * 22 return if @@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi) == 0 csbi end
get_screen_size()
click to toggle source
# File reline/windows.rb, line 339 def self.get_screen_size unless csbi = get_console_screen_buffer_info return [1, 1] end csbi[0, 4].unpack('SS').reverse end
getc(_timeout_second)
click to toggle source
# File reline/windows.rb, line 298 def self.getc(_timeout_second) check_input_event @@output_buf.shift end
hide_cursor()
click to toggle source
# File reline/windows.rb, line 436 def self.hide_cursor size = 100 visible = 0 # 0 means false cursor_info = [size, visible].pack('Li') @@SetConsoleCursorInfo.call(@@hConsoleHandle, cursor_info) end
in_pasting?()
click to toggle source
# File reline/windows.rb, line 307 def self.in_pasting? not self.empty_buffer? end
move_cursor_column(val)
click to toggle source
# File reline/windows.rb, line 355 def self.move_cursor_column(val) @@SetConsoleCursorPosition.call(@@hConsoleHandle, cursor_pos.y * 65536 + val) end
move_cursor_down(val)
click to toggle source
# File reline/windows.rb, line 369 def self.move_cursor_down(val) if val > 0 return unless csbi = get_console_screen_buffer_info screen_height = get_screen_size.first y = cursor_pos.y + val y = screen_height - 1 if y > (screen_height - 1) @@SetConsoleCursorPosition.call(@@hConsoleHandle, (cursor_pos.y + val) * 65536 + cursor_pos.x) elsif val < 0 move_cursor_up(-val) end end
move_cursor_up(val)
click to toggle source
# File reline/windows.rb, line 359 def self.move_cursor_up(val) if val > 0 y = cursor_pos.y - val y = 0 if y < 0 @@SetConsoleCursorPosition.call(@@hConsoleHandle, y * 65536 + cursor_pos.x) elsif val < 0 move_cursor_down(-val) end end
msys_tty?(io = @@hConsoleInputHandle)
click to toggle source
# File reline/windows.rb, line 173 def self.msys_tty?(io = @@hConsoleInputHandle) # check if fd is a pipe if @@GetFileType.call(io) != FILE_TYPE_PIPE return false end bufsize = 1024 p_buffer = "\0" * bufsize res = @@GetFileInformationByHandleEx.call(io, FILE_NAME_INFO, p_buffer, bufsize - 2) return false if res == 0 # get pipe name: p_buffer layout is: # struct _FILE_NAME_INFO { # DWORD FileNameLength; # WCHAR FileName[1]; # } FILE_NAME_INFO len = p_buffer[0, 4].unpack1("L") name = p_buffer[4, len].encode(Encoding::UTF_8, Encoding::UTF_16LE, invalid: :replace) # Check if this could be a MSYS2 pty pipe ('\msys-XXXX-ptyN-XX') # or a cygwin pty pipe ('\cygwin-XXXX-ptyN-XX') name =~ /(msys-|cygwin-).*-pty/ ? true : false end
prep()
click to toggle source
# File reline/windows.rb, line 454 def self.prep # do nothing nil end
process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
click to toggle source
# File reline/windows.rb, line 220 def self.process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state) # high-surrogate if 0xD800 <= char_code and char_code <= 0xDBFF @@hsg = char_code return end # low-surrogate if 0xDC00 <= char_code and char_code <= 0xDFFF if @@hsg char_code = 0x10000 + (@@hsg - 0xD800) * 0x400 + char_code - 0xDC00 @@hsg = nil else # no high-surrogate. ignored. return end else # ignore high-surrogate without low-surrogate if there @@hsg = nil end key = KeyEventRecord.new(virtual_key_code, char_code, control_key_state) match = KEY_MAP.find { |args,| key.matches?(**args) } unless match.nil? @@output_buf.concat(match.last) return end # no char, only control keys return if key.char_code == 0 and key.control_keys.any? @@output_buf.push("\e".ord) if key.control_keys.include?(:ALT) and !key.control_keys.include?(:CTRL) @@output_buf.concat(key.char.bytes) end
scroll_down(val)
click to toggle source
# File reline/windows.rb, line 390 def self.scroll_down(val) return if val < 0 return unless csbi = get_console_screen_buffer_info buffer_width, buffer_lines, x, y, attributes, window_left, window_top, window_bottom = csbi.unpack('ssssSssx2s') screen_height = window_bottom - window_top + 1 val = screen_height if val > screen_height if @@legacy_console || window_left != 0 # unless ENABLE_VIRTUAL_TERMINAL, # if srWindow.Left != 0 then it's conhost.exe hosted console # and puts "\n" causes horizontal scroll. its glitch. # FYI irb write from culumn 1, so this gives no gain. scroll_rectangle = [0, val, buffer_width, buffer_lines - val].pack('s4') destination_origin = 0 # y * 65536 + x fill = [' '.ord, attributes].pack('SS') @@ScrollConsoleScreenBuffer.call(@@hConsoleHandle, scroll_rectangle, nil, destination_origin, fill) else origin_x = x + 1 origin_y = y - window_top + 1 @@output.write [ (origin_y != screen_height) ? "\e[#{screen_height};H" : nil, "\n" * val, (origin_y != screen_height or !x.zero?) ? "\e[#{origin_y};#{origin_x}H" : nil ].join end end
set_default_key_bindings(config)
click to toggle source
# File reline/windows.rb, line 16 def self.set_default_key_bindings(config) { [224, 72] => :ed_prev_history, # ↑ [224, 80] => :ed_next_history, # ↓ [224, 77] => :ed_next_char, # → [224, 75] => :ed_prev_char, # ← [224, 83] => :key_delete, # Del [224, 71] => :ed_move_to_beg, # Home [224, 79] => :ed_move_to_end, # End [ 0, 41] => :ed_unassigned, # input method on/off [ 0, 72] => :ed_prev_history, # ↑ [ 0, 80] => :ed_next_history, # ↓ [ 0, 77] => :ed_next_char, # → [ 0, 75] => :ed_prev_char, # ← [ 0, 83] => :key_delete, # Del [ 0, 71] => :ed_move_to_beg, # Home [ 0, 79] => :ed_move_to_end # End }.each_pair do |key, func| config.add_default_key_binding_by_keymap(:emacs, key, func) config.add_default_key_binding_by_keymap(:vi_insert, key, func) config.add_default_key_binding_by_keymap(:vi_command, key, func) end { [27, 32] => :em_set_mark, # M-<space> [24, 24] => :em_exchange_mark, # C-x C-x }.each_pair do |key, func| config.add_default_key_binding_by_keymap(:emacs, key, func) end # Emulate ANSI key sequence. { [27, 91, 90] => :completion_journey_up, # S-Tab }.each_pair do |key, func| config.add_default_key_binding_by_keymap(:emacs, key, func) config.add_default_key_binding_by_keymap(:vi_insert, key, func) end end
set_screen_size(rows, columns)
click to toggle source
# File reline/windows.rb, line 432 def self.set_screen_size(rows, columns) raise NotImplementedError end
set_winch_handler(&handler)
click to toggle source
# File reline/windows.rb, line 450 def self.set_winch_handler(&handler) @@winch_handler = handler end
show_cursor()
click to toggle source
# File reline/windows.rb, line 443 def self.show_cursor size = 100 visible = 1 # 1 means true cursor_info = [size, visible].pack('Li') @@SetConsoleCursorInfo.call(@@hConsoleHandle, cursor_info) end
ungetc(c)
click to toggle source
# File reline/windows.rb, line 303 def self.ungetc(c) @@output_buf.unshift(c) end
win?()
click to toggle source
# File reline/windows.rb, line 8 def self.win? true end
win_legacy_console?()
click to toggle source
# File reline/windows.rb, line 12 def self.win_legacy_console? @@legacy_console end
with_raw_input() { || ... }
click to toggle source
# File reline/windows.rb, line 294 def self.with_raw_input yield end
Private Class Methods
getconsolemode()
click to toggle source
# File reline/windows.rb, line 152 def self.getconsolemode mode = "\000\000\000\000" @@GetConsoleMode.call(@@hConsoleHandle, mode) mode.unpack1('L') end
setconsolemode(mode)
click to toggle source
# File reline/windows.rb, line 158 def self.setconsolemode(mode) @@SetConsoleMode.call(@@hConsoleHandle, mode) end