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_UP
WINDOW_BUFFER_SIZE_EVENT

Public Class Methods

check_input_event() click to toggle source
# File lib/reline/windows.rb, line 218
def self.check_input_event
  num_of_events = 0.chr * 8
  while @@output_buf.empty? #or true
    next if @@GetNumberOfConsoleInputEvents.(@@hConsoleInputHandle, num_of_events) == 0 or num_of_events.unpack('L').first == 0
    input_record = 0.chr * 18
    read_event = 0.chr * 4
    if @@ReadConsoleInputW.(@@hConsoleInputHandle, input_record, 1, read_event) != 0
      event = input_record[0, 2].unpack('s*').first
      case event
      when WINDOW_BUFFER_SIZE_EVENT
        @@winch_handler.()
      when KEY_EVENT
        key_down = input_record[4, 4].unpack('l*').first
        repeat_count = input_record[8, 2].unpack('s*').first
        virtual_key_code = input_record[10, 2].unpack('s*').first
        virtual_scan_code = input_record[12, 2].unpack('s*').first
        char_code = input_record[14, 2].unpack('S*').first
        control_key_state = input_record[16, 2].unpack('S*').first
        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
clear_screen() click to toggle source
# File lib/reline/windows.rb, line 326
def self.clear_screen
  csbi = 0.chr * 22
  return if @@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi) == 0
  buffer_width = csbi[0, 2].unpack('S').first
  attributes = csbi[8, 2].unpack('S').first
  _window_left, window_top, _window_right, window_bottom = *csbi[10,8].unpack('S*')
  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)
end
cursor_pos() click to toggle source
# File lib/reline/windows.rb, line 274
def self.cursor_pos
  csbi = 0.chr * 22
  @@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi)
  x = csbi[4, 2].unpack('s*').first
  y = csbi[6, 2].unpack('s*').first
  Reline::CursorPos.new(x, y)
end
deprep(otio) click to toggle source
# File lib/reline/windows.rb, line 353
def self.deprep(otio)
  # do nothing
end
empty_buffer?() click to toggle source
# File lib/reline/windows.rb, line 258
def self.empty_buffer?
  if not @@input_buf.empty?
    false
  elsif @@kbhit.call == 0
    true
  else
    false
  end
end
encoding() click to toggle source
# File lib/reline/windows.rb, line 4
def self.encoding
  Encoding::UTF_8
end
erase_after_cursor() click to toggle source
# File lib/reline/windows.rb, line 307
def self.erase_after_cursor
  csbi = 0.chr * 24
  @@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi)
  cursor = csbi[4, 4].unpack('L').first
  written = 0.chr * 4
  @@FillConsoleOutputCharacter.call(@@hConsoleHandle, 0x20, get_screen_size.last - cursor_pos.x, cursor, written)
  @@FillConsoleOutputAttribute.call(@@hConsoleHandle, 0, get_screen_size.last - cursor_pos.x, cursor, written)
end
get_screen_size() click to toggle source
# File lib/reline/windows.rb, line 268
def self.get_screen_size
  csbi = 0.chr * 22
  @@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi)
  csbi[0, 4].unpack('SS').reverse
end
getc() click to toggle source
# File lib/reline/windows.rb, line 245
def self.getc
  check_input_event
  @@output_buf.shift
end
in_pasting?() click to toggle source
# File lib/reline/windows.rb, line 254
def self.in_pasting?
  not self.empty_buffer?
end
move_cursor_column(val) click to toggle source
# File lib/reline/windows.rb, line 282
def self.move_cursor_column(val)
  @@SetConsoleCursorPosition.call(@@hConsoleHandle, cursor_pos.y * 65536 + val)
end
move_cursor_down(val) click to toggle source
# File lib/reline/windows.rb, line 296
def self.move_cursor_down(val)
  if val > 0
    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 lib/reline/windows.rb, line 286
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 lib/reline/windows.rb, line 160
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].unpack("L")[0]
  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 lib/reline/windows.rb, line 348
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 lib/reline/windows.rb, line 202
def self.process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)

  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.concat(key.char.bytes)
end
scroll_down(val) click to toggle source
# File lib/reline/windows.rb, line 316
def self.scroll_down(val)
  return if val.zero?
  screen_height = get_screen_size.first
  val = screen_height - 1 if val > (screen_height - 1)
  scroll_rectangle = [0, val, get_screen_size.last, get_screen_size.first].pack('s4')
  destination_origin = 0 # y * 65536 + x
  fill = [' '.ord, 0].pack('SS')
  @@ScrollConsoleScreenBuffer.call(@@hConsoleHandle, scroll_rectangle, nil, destination_origin, fill)
end
set_default_key_bindings(config) click to toggle source
# File lib/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
end
set_screen_size(rows, columns) click to toggle source
# File lib/reline/windows.rb, line 340
def self.set_screen_size(rows, columns)
  raise NotImplementedError
end
set_winch_handler(&handler) click to toggle source
# File lib/reline/windows.rb, line 344
def self.set_winch_handler(&handler)
  @@winch_handler = handler
end
ungetc(c) click to toggle source
# File lib/reline/windows.rb, line 250
def self.ungetc(c)
  @@output_buf.unshift(c)
end
win?() click to toggle source
# File lib/reline/windows.rb, line 8
def self.win?
  true
end
win_legacy_console?() click to toggle source
# File lib/reline/windows.rb, line 12
def self.win_legacy_console?
  @@legacy_console
end

Private Class Methods

getconsolemode() click to toggle source
# File lib/reline/windows.rb, line 141
                     def self.getconsolemode
  mode = "\000\000\000\000"
  @@GetConsoleMode.call(@@hConsoleHandle, mode)
  mode.unpack1('L')
end
setconsolemode(mode) click to toggle source
# File lib/reline/windows.rb, line 147
                     def self.setconsolemode(mode)
  @@SetConsoleMode.call(@@hConsoleHandle, mode)
end