Module: Ruby2D::CLI::Browser::WinConsole

Defined in:
lib/ruby2d/cli/browser.rb

Overview

Drives the Win32 console input mode through SetConsoleMode, because native-Windows Ruby's io/console raw is unreliable here (confirmed on aarch64-mingw-ucrt: raw left LINE/ECHO input enabled). Enabling VIRTUAL_TERMINAL_INPUT is what makes arrow keys arrive as \e[A sequences instead of being swallowed. All Fiddle use is lazy and failure-tolerant: any problem returns nil and the caller falls back to the plain io/console path.

Constant Summary collapse

STD_INPUT_HANDLE =
-10
PROCESSED_INPUT =
0x0001
LINE_INPUT =
0x0002
ECHO_INPUT =
0x0004
VT_INPUT =
0x0200

Class Method Summary collapse

Class Method Details

.apiObject

Lazily resolve the three kernel32 calls we need; memoize the result (nil if Fiddle or the console API is unavailable).



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/ruby2d/cli/browser.rb', line 39

def self.api
  unless @resolved
    @resolved = true
    @api =
      begin
        require 'fiddle'
        k32 = Fiddle.dlopen('kernel32')
        {
          get_handle: Fiddle::Function.new(k32['GetStdHandle'],   [Fiddle::TYPE_LONG], Fiddle::TYPE_VOIDP),
          get_mode:   Fiddle::Function.new(k32['GetConsoleMode'],  [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT),
          set_mode:   Fiddle::Function.new(k32['SetConsoleMode'],  [Fiddle::TYPE_VOIDP, Fiddle::TYPE_LONG], Fiddle::TYPE_INT)
        }
      rescue LoadError, StandardError
        nil
      end
  end
  @api
end

.enable_rawObject

Switch the console to raw + virtual-terminal input. Returns the prior mode (to hand back to restore), or nil when there's no console to set (Fiddle missing, stdin redirected, GetConsoleMode failed).



61
62
63
64
65
66
67
68
69
# File 'lib/ruby2d/cli/browser.rb', line 61

def self.enable_raw
  fns = api or return nil
  handle = fns[:get_handle].call(STD_INPUT_HANDLE)
  buf = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT, Fiddle::RUBY_FREE)
  return nil if fns[:get_mode].call(handle, buf) == 0
  prev = buf[0, Fiddle::SIZEOF_INT].unpack1('L')
  fns[:set_mode].call(handle, (prev & ~(LINE_INPUT | ECHO_INPUT | PROCESSED_INPUT)) | VT_INPUT)
  prev
end

.reassert_rawObject

Re-apply raw + VT without disturbing the saved prior mode — used after a child example returns, in case it left the shared console mode changed.



74
75
76
# File 'lib/ruby2d/cli/browser.rb', line 74

def self.reassert_raw
  enable_raw
end

.restore(prev) ⇒ Object



78
79
80
81
82
# File 'lib/ruby2d/cli/browser.rb', line 78

def self.restore(prev)
  return if prev.nil?
  fns = api or return
  fns[:set_mode].call(fns[:get_handle].call(STD_INPUT_HANDLE), prev)
end