Class: KeyboardMap

Inherits:
Object
  • Object
show all
Defined in:
lib/keyboard_map.rb,
lib/keyboard_map/version.rb

Defined Under Namespace

Classes: Event

Constant Summary collapse

SINGLE_KEY_EVENT =
{
  "\t" => :tab,
  "\r" => :enter,
  "\u001F" => Event.new(:_,:ctrl),
  "\u007F" => :backspace
}.freeze
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.

{
  "A"    => :up,
  "B"    => :down,
  "C"    => :right,
  "D"    => :left,
  "E"    => :keypad_5,
  "F"    => :end,
  "H"    => :home,
  "P"    => :f1,
  "Q"    => :f2,
  "R"    => :f3,
  "S"    => :f4,
}.freeze
CSI_TILDE_MAP =

e[parameter1;…~ from parameter1 => key

{
  "2"   => :insert,
  "3"   => :delete,
  "5"   => :page_up,
  "6"   => :page_down,
  "11"  => :f1,
  "12"  => :f2,
  "13"  => :f3,
  "14"  => :f4,
  "15"  => :f5,
  "17"  => :f6,
  "18"  => :f7,
  "19"  => :f8,
  "20"  => :f9,
  "21"  => :f10,
  "23"  => :f11,
  "24"  => :f12,
  "200" => :start_paste,
  "201" => :end_paste,
}.freeze
ESCAPE_MAP =

Map of simple/non-parameterised escape sequences to symbols

{
  "\e[Z"    => event(:tab,:shift),
  "\eOP"    => :f1,
  "\eOQ"    => :f2,
  "\eOR"    => :f3,
  "\eOS"    => :f4
}.freeze
CSI_FINAL_BYTE =
0x40..0x7e
ESC =
"\e"
VERSION =
"0.1.2"
@@key_events =
{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeKeyboardMap

Returns a new instance of KeyboardMap.



106
107
108
109
110
# File 'lib/keyboard_map.rb', line 106

def initialize
  @tmp = ""
  @buf = ""
  @state = :text
end

Instance Attribute Details

#bufObject (readonly)

Returns the value of attribute buf.



8
9
10
# File 'lib/keyboard_map.rb', line 8

def buf
  @buf
end

Class Method Details

.event(key, *modifiers) ⇒ Object



81
82
83
84
85
86
87
# 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

Instance Method Details

#call(input) ⇒ Object



112
113
114
115
# File 'lib/keyboard_map.rb', line 112

def call(input)
  @buf << input
  run
end

#csi(ch) ⇒ Object



166
167
168
169
170
171
172
173
# File 'lib/keyboard_map.rb', line 166

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) ⇒ Object



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/keyboard_map.rb', line 175

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) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# 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
  elsif final == "m" || final == "M" # Mouse reporting
    return Event.new(final == "M" ? :mouse_down : :mouse_up, args: [params[0][1..-1].to_i, params[1].to_i, params[2].to_i])
  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) ⇒ Object



117
118
119
120
121
122
# 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) ⇒ Object



132
133
134
135
136
137
138
139
140
# 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) ⇒ Object



100
101
102
# File 'lib/keyboard_map.rb', line 100

def meta(key)
  self.class.event(key,:meta)
end

#runObject



223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/keyboard_map.rb', line 223

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) ⇒ Object



124
125
126
127
128
129
130
# File 'lib/keyboard_map.rb', line 124

def ss3(ch)
  tmp = @tmp
  tmp << ch
  @tmp = ""
  @state = :text
  return map_escape(tmp)
end

#text(ch) ⇒ Object



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/keyboard_map.rb', line 196

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