class KeyboardMap

Constants

CSI_BASIC_MAP

e[ starts a CSI sequence. This maps the final character in the CSI sequence to a key and how to interpret the parameters.

CSI_FINAL_BYTE
CSI_TILDE_MAP

e[{parameter1}{;…}~ from parameter1 => key

ESC
ESCAPE_MAP

Map of simple/non-parameterised escape sequences to symbols

SINGLE_KEY_EVENT
VERSION

Attributes

buf[R]

Public Class Methods

event(key,*modifiers) click to toggle source
# File lib/keyboard_map.rb, line 81
def self.event(key,*modifiers)
  e = key if key.kind_of?(Event)
  e ||= Event.new(key,*modifiers)
  k = e.to_sym
  @@key_events[k] ||= e
  @@key_events[k]
end
new() click to toggle source
# File lib/keyboard_map.rb, line 106
def initialize
  @tmp = ""
  @buf = ""
  @state = :text
end

Public Instance Methods

call(input) click to toggle source
# File lib/keyboard_map.rb, line 112
def call(input)
  @buf << input
  run
end
csi(ch) click to toggle source
# File lib/keyboard_map.rb, line 164
def csi(ch)
  @tmp << ch
  return nil if !CSI_FINAL_BYTE.member?(ch.ord)
  @state = :text
  tmp = @tmp
  @tmp = ""
  return map_csi(tmp)
end
esc(ch) click to toggle source
# File lib/keyboard_map.rb, line 173
def esc(ch)
  if ch == "["
    @state = :csi
    @tmp << ch
    return nil
  elsif ch == "O"
    @state = :ss3
    @tmp << ch
    return nil
  elsif ch == "\t"
    @state = :text
    @tmp = ""
    return meta(:tab)
  elsif ch == "\e"
    return :esc
  end
  @state = :text
  @tmp = ""
  return meta(ch)
end
map_csi(seq) click to toggle source
# File lib/keyboard_map.rb, line 142
def map_csi(seq)
  if sym = ESCAPE_MAP[seq]
    return sym
  end
  final = seq[-1]
  params = String(seq[2..-2]).split(";")
  modifiers = []
  if final == "~"
    key = CSI_TILDE_MAP[params[0]]
    if key
      modifiers = map_modifiers(params[1])
    end
  else
    key = CSI_BASIC_MAP[final]
    modifiers = map_modifiers(params[1]) if key && params.first == "1" && params.size == 2
  end

  return Event.new(key,*Array(modifiers)) if key
  return Event.new((params << final).join("_"), :csi)
end
map_escape(seq) click to toggle source
# File lib/keyboard_map.rb, line 117
def map_escape(seq)
  if sym = ESCAPE_MAP[seq]
    return sym
  end
  return Event.new(seq,:esc)
end
map_modifiers(mod) click to toggle source
# File lib/keyboard_map.rb, line 132
def map_modifiers(mod)
  return [] if mod.nil?
  mod = mod.to_i - 1
  [].tap do |m|
    m << :shift if (mod & 1) == 1
    m << :meta  if (mod & 2) == 2
    m << :ctrl  if (mod & 4) == 4
  end
end
meta(key) click to toggle source
# File lib/keyboard_map.rb, line 100
def meta(key)
  self.class.event(key,:meta)
end
run() click to toggle source
# File lib/keyboard_map.rb, line 221
def run
  out = []
  while !@buf.empty?
    ch = @buf.slice!(0)
    r = send(@state,ch)
    out.concat(Array(r)) if r
  end
  if !@tmp.empty? && @state == :text
    out << @tmp
    @tmp = ""
  end
  out
end
ss3(ch) click to toggle source
# File lib/keyboard_map.rb, line 124
def ss3(ch)
  tmp = @tmp
  tmp << ch
  @tmp = ""
  @state = :text
  return map_escape(tmp)
end
text(ch) click to toggle source
# File lib/keyboard_map.rb, line 194
def text(ch)
  if ch == ESC
    @state = :esc
    out = @tmp.empty? ? nil : @tmp
    @tmp = ESC.dup
    return out
  end

  if m = SINGLE_KEY_EVENT[ch]
    tmp = @tmp
    @tmp = ""
    return [self.class.event(m)] if tmp.empty?
    return [tmp, self.class.event(m)]
  end

  if ch.ord < 32
    tmp = @tmp
    @tmp = ""
    ev = self.class.event((ch.ord+96).chr,:ctrl)
    return [ev] if tmp.empty?
    return [tmp,ev]
  end

  @tmp << ch
  nil
end