Skip to content

Commit

Permalink
Use Curses.get_key_modifiers if available.
Browse files Browse the repository at this point in the history
  • Loading branch information
shugo committed Apr 22, 2017
1 parent b20d60a commit b79801b
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 74 deletions.
63 changes: 16 additions & 47 deletions lib/textbringer/window.rb
Expand Up @@ -2,52 +2,21 @@

require "curses"
require "unicode/display_width"
require "fiddle/import"

module Textbringer
# These features should be provided by curses.gem.
module PDCurses
KEY_OFFSET = 0xec00
ALT_0 = KEY_OFFSET + 0x97
ALT_9 = KEY_OFFSET + 0xa0
ALT_A = KEY_OFFSET + 0xa1
ALT_Z = KEY_OFFSET + 0xba
ALT_NUMBER_BASE = ALT_0 - ?0.ord
ALT_ALPHA_BASE = ALT_A - ?a.ord

KEY_MODIFIER_SHIFT = 1
KEY_MODIFIER_CONTROL = 2
KEY_MODIFIER_ALT = 4
KEY_MODIFIER_NUMLOCK = 8

@dll_loaded = false

class << self
attr_writer :dll_loaded

def dll_loaded?
@dll_loaded
end
end

begin
extend Fiddle::Importer
dlload "pdcurses.dll"
extern "unsigned long PDC_get_key_modifiers(void)"
extern "int PDC_save_key_modifiers(unsigned char)"
extern "int PDC_return_key_modifiers(unsigned char)"
@dll_loaded = true
rescue Fiddle::DLError
end
end

class Window
KEY_NAMES = {}
Curses.constants.grep(/\AKEY_/).each do |name|
KEY_NAMES[Curses.const_get(name)] =
name.slice(/\AKEY_(.*)/, 1).downcase.intern
end

HAVE_GET_KEY_MODIFIERS = defined?(Curses.get_key_modifiers)
if HAVE_GET_KEY_MODIFIERS
ALT_NUMBER_BASE = Curses::ALT_0 - ?0.ord
ALT_ALPHA_BASE = Curses::ALT_A - ?a.ord
end

@@started = false
@@list = []
@@current = nil
Expand Down Expand Up @@ -325,12 +294,12 @@ def current?
def read_event
key = get_char
if key.is_a?(Integer)
if PDCurses.dll_loaded?
if PDCurses::ALT_0 <= key && key <= PDCurses::ALT_9
@key_buffer.push((key - PDCurses::ALT_NUMBER_BASE).chr)
if HAVE_GET_KEY_MODIFIERS
if Curses::ALT_0 <= key && key <= Curses::ALT_9
@key_buffer.push((key - ALT_NUMBER_BASE).chr)
return "\e"
elsif PDCurses::ALT_A <= key && key <= PDCurses::ALT_Z
@key_buffer.push((key - PDCurses::ALT_ALPHA_BASE).chr)
elsif Curses::ALT_A <= key && key <= Curses::ALT_Z
@key_buffer.push((key - ALT_ALPHA_BASE).chr)
return "\e"
end
end
Expand Down Expand Up @@ -780,21 +749,21 @@ def delete_marks

def get_char
if @key_buffer.empty?
PDCurses.PDC_save_key_modifiers(1) if PDCurses.dll_loaded?
Curses.save_key_modifiers(true) if HAVE_GET_KEY_MODIFIERS
begin
need_retry = false
if @raw_key_buffer.empty?
key = @window.get_char
else
key = @raw_key_buffer.shift
end
if PDCurses.dll_loaded?
mods = PDCurses.PDC_get_key_modifiers
if HAVE_GET_KEY_MODIFIERS
mods = Curses.get_key_modifiers
if key.is_a?(String) && key.ascii_only?
if (mods & PDCurses::KEY_MODIFIER_CONTROL) != 0
if (mods & Curses::PDC_KEY_MODIFIER_CONTROL) != 0
key = key == ?? ? "\x7f" : (key.ord & 0x9f).chr
end
if (mods & PDCurses::KEY_MODIFIER_ALT) != 0
if (mods & Curses::PDC_KEY_MODIFIER_ALT) != 0
if key == "\0"
# Alt + `, Alt + < etc. return NUL, so ignore it.
need_retry = true
Expand Down
48 changes: 31 additions & 17 deletions test/test_helper.rb
@@ -1,6 +1,7 @@
require "simplecov"
require "test/unit"
require "tmpdir"
require "curses"

SimpleCov.profiles.define "textbringer" do
add_filter "/test/"
Expand All @@ -26,6 +27,36 @@ def format(*args)
SimpleCov.formatter = SimpleCov::Formatter::Codecov
end

module Curses
if !defined?(Curses.get_key_modifiers)
@key_modifiers = 0

def self.save_key_modifiers(flag)
end

def self.get_key_modifiers
@key_modifiers
end

def self.set_key_modifiers(key_modifiers)
@key_modifiers = key_modifiers
end

KEY_OFFSET = 0xec00
ALT_0 = KEY_OFFSET + 0x97
ALT_9 = KEY_OFFSET + 0xa0
ALT_A = KEY_OFFSET + 0xa1
ALT_Z = KEY_OFFSET + 0xba
ALT_NUMBER_BASE = ALT_0 - ?0.ord
ALT_ALPHA_BASE = ALT_A - ?a.ord

PDC_KEY_MODIFIER_SHIFT = 1
PDC_KEY_MODIFIER_CONTROL = 2
PDC_KEY_MODIFIER_ALT = 4
PDC_KEY_MODIFIER_NUMLOCK = 8
end
end

require "textbringer"

module Curses
Expand Down Expand Up @@ -190,23 +221,6 @@ def method_missing(mid, *args)
end
::Curses.send(:remove_const, :Window)
::Curses.const_set(:Window, FakeCursesWindow)

module PDCurses
self.dll_loaded = true

@key_modifiers = 0

def PDCurses.PDC_save_key_modifiers(flag)
end

def PDCurses.PDC_get_key_modifiers
@key_modifiers
end

def PDCurses.PDC_set_key_modifiers(key_modifiers)
@key_modifiers = key_modifiers
end
end

class Window
class << self
Expand Down
18 changes: 9 additions & 9 deletions test/textbringer/test_window.rb
Expand Up @@ -233,27 +233,27 @@ def test_read_event
@window.window.push_key(Curses::KEY_RIGHT)
assert_equal(:right, @window.read_event)

@window.window.push_key(PDCurses::ALT_0 + 3)
@window.window.push_key(Curses::ALT_0 + 3)
assert_equal("\e", @window.read_event)
assert_equal("3", @window.read_event)

@window.window.push_key(PDCurses::ALT_A + 5)
@window.window.push_key(Curses::ALT_A + 5)
assert_equal("\e", @window.read_event)
assert_equal("f", @window.read_event)

PDCurses.PDC_set_key_modifiers(PDCurses::KEY_MODIFIER_CONTROL)
Curses.set_key_modifiers(Curses::PDC_KEY_MODIFIER_CONTROL)
@window.window.push_key("a")
assert_equal("\C-a", @window.read_event)
@window.window.push_key("?")
assert_equal("\x7f", @window.read_event)

PDCurses.PDC_set_key_modifiers(PDCurses::KEY_MODIFIER_ALT)
Curses.set_key_modifiers(Curses::PDC_KEY_MODIFIER_ALT)
@window.window.push_key("\0")
@window.window.push_key("a")
assert_equal("\e", @window.read_event)
assert_equal("a", @window.read_event)
ensure
PDCurses.PDC_set_key_modifiers(0)
Curses.set_key_modifiers(0)
end

def test_read_event_nonblock
Expand All @@ -267,13 +267,13 @@ def test_wait_input
@window.window.push_key("a")
assert_equal("a", @window.wait_input(1))

PDCurses.PDC_set_key_modifiers(PDCurses::KEY_MODIFIER_ALT)
Curses.set_key_modifiers(Curses::PDC_KEY_MODIFIER_ALT)
@window.window.push_key("\0")
@window.window.push_key("a")
assert_equal("\e", @window.read_event)
assert_equal("a", @window.wait_input(1))
ensure
PDCurses.PDC_set_key_modifiers(0)
Curses.set_key_modifiers(0)
end

def test_has_input?
Expand All @@ -282,13 +282,13 @@ def test_has_input?
@window.window.push_key("a")
assert_equal(true, @window.has_input?)

PDCurses.PDC_set_key_modifiers(PDCurses::KEY_MODIFIER_ALT)
Curses.set_key_modifiers(Curses::PDC_KEY_MODIFIER_ALT)
@window.window.push_key("\0")
@window.window.push_key("a")
assert_equal("\e", @window.read_event)
assert_equal(true, @window.has_input?)
ensure
PDCurses.PDC_set_key_modifiers(0)
Curses.set_key_modifiers(0)
end

def test_echo_area_redisplay
Expand Down
2 changes: 1 addition & 1 deletion textbringer.gemspec
Expand Up @@ -21,7 +21,7 @@ Gem::Specification.new do |spec|

spec.required_ruby_version = '>= 2.3'

spec.add_runtime_dependency "curses", "~> 1.2"
spec.add_runtime_dependency "curses", ">= 1.2.2"
spec.add_runtime_dependency "unicode-display_width", "~> 1.1"
spec.add_runtime_dependency "clipboard", "~> 1.1"
spec.add_runtime_dependency "fiddley", ">= 0.0.5"
Expand Down

0 comments on commit b79801b

Please sign in to comment.