tty-reader 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +5 -5
- data/CHANGELOG.md +22 -1
- data/Gemfile +4 -5
- data/README.md +176 -27
- data/appveyor.yml +0 -4
- data/benchmarks/speed_read_char.rb +34 -0
- data/benchmarks/speed_read_line.rb +34 -0
- data/examples/keypress.rb +16 -0
- data/examples/line.rb +7 -0
- data/examples/multiline.rb +7 -0
- data/examples/noecho.rb +6 -0
- data/examples/shell.rb +12 -0
- data/lib/tty/reader.rb +121 -58
- data/lib/tty/reader/console.rb +2 -2
- data/lib/tty/reader/history.rb +6 -2
- data/lib/tty/reader/key_event.rb +4 -35
- data/lib/tty/reader/keys.rb +165 -0
- data/lib/tty/reader/line.rb +96 -9
- data/lib/tty/reader/version.rb +1 -1
- data/lib/tty/reader/win_console.rb +2 -2
- data/tty-reader.gemspec +7 -3
- metadata +46 -12
- data/lib/tty/reader/codes.rb +0 -120
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative '../lib/tty-reader'
|
2
|
+
|
3
|
+
reader = TTY::Reader.new
|
4
|
+
|
5
|
+
puts "Press a key (or Ctrl-X to exit)"
|
6
|
+
|
7
|
+
loop do
|
8
|
+
print "=> "
|
9
|
+
char = reader.read_keypress
|
10
|
+
if ?\C-x == char
|
11
|
+
puts "Exiting..."
|
12
|
+
exit
|
13
|
+
else
|
14
|
+
puts "#{char.inspect} [#{char.ord}] (hex: #{char.ord.to_s(16)})"
|
15
|
+
end
|
16
|
+
end
|
data/examples/line.rb
ADDED
data/examples/noecho.rb
ADDED
data/examples/shell.rb
ADDED
data/lib/tty/reader.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require 'tty-cursor'
|
5
|
+
require 'tty-screen'
|
4
6
|
require 'wisper'
|
5
7
|
|
6
8
|
require_relative 'reader/history'
|
@@ -15,7 +17,7 @@ module TTY
|
|
15
17
|
#
|
16
18
|
# Used internally to provide key and line reading functionality
|
17
19
|
#
|
18
|
-
# @api
|
20
|
+
# @api public
|
19
21
|
class Reader
|
20
22
|
include Wisper::Publisher
|
21
23
|
|
@@ -24,6 +26,15 @@ module TTY
|
|
24
26
|
# @api public
|
25
27
|
InputInterrupt = Class.new(StandardError)
|
26
28
|
|
29
|
+
# Check if Windowz mode
|
30
|
+
#
|
31
|
+
# @return [Boolean]
|
32
|
+
#
|
33
|
+
# @api public
|
34
|
+
def self.windows?
|
35
|
+
::File::ALT_SEPARATOR == '\\'
|
36
|
+
end
|
37
|
+
|
27
38
|
attr_reader :input
|
28
39
|
|
29
40
|
attr_reader :output
|
@@ -35,11 +46,13 @@ module TTY
|
|
35
46
|
|
36
47
|
attr_reader :console
|
37
48
|
|
49
|
+
attr_reader :cursor
|
50
|
+
|
38
51
|
# Key codes
|
39
52
|
CARRIAGE_RETURN = 13
|
40
53
|
NEWLINE = 10
|
41
|
-
BACKSPACE =
|
42
|
-
DELETE =
|
54
|
+
BACKSPACE = 8
|
55
|
+
DELETE = 127
|
43
56
|
|
44
57
|
# Initialize a Reader
|
45
58
|
#
|
@@ -54,18 +67,26 @@ module TTY
|
|
54
67
|
# disable line history tracking, true by default
|
55
68
|
#
|
56
69
|
# @api public
|
57
|
-
def initialize(
|
58
|
-
@input = input
|
59
|
-
@output = output
|
70
|
+
def initialize(**options)
|
71
|
+
@input = options.fetch(:input) { $stdin }
|
72
|
+
@output = options.fetch(:output) { $stdout }
|
60
73
|
@interrupt = options.fetch(:interrupt) { :error }
|
61
74
|
@env = options.fetch(:env) { ENV }
|
75
|
+
|
62
76
|
@track_history = options.fetch(:track_history) { true }
|
77
|
+
@history_cycle = options.fetch(:history_cycle) { false }
|
78
|
+
exclude_proc = ->(line) { line.strip == '' }
|
79
|
+
@history_exclude = options.fetch(:history_exclude) { exclude_proc }
|
80
|
+
@history_duplicates = options.fetch(:history_duplicates) { false }
|
81
|
+
|
63
82
|
@console = select_console(input)
|
64
83
|
@history = History.new do |h|
|
65
|
-
h.
|
66
|
-
h.
|
84
|
+
h.cycle = @history_cycle
|
85
|
+
h.duplicates = @history_duplicates
|
86
|
+
h.exclude = @history_exclude
|
67
87
|
end
|
68
88
|
@stop = false # gathering input
|
89
|
+
@cursor = TTY::Cursor
|
69
90
|
|
70
91
|
subscribe(self)
|
71
92
|
end
|
@@ -74,7 +95,7 @@ module TTY
|
|
74
95
|
#
|
75
96
|
# @api private
|
76
97
|
def select_console(input)
|
77
|
-
if windows? && !env['TTY_TEST']
|
98
|
+
if self.class.windows? && !env['TTY_TEST']
|
78
99
|
WinConsole.new(input)
|
79
100
|
else
|
80
101
|
Console.new(input)
|
@@ -133,14 +154,14 @@ module TTY
|
|
133
154
|
def get_codes(options = {}, codes = [])
|
134
155
|
opts = { echo: true, raw: false }.merge(options)
|
135
156
|
char = console.get_char(opts)
|
136
|
-
handle_interrupt if char ==
|
157
|
+
handle_interrupt if console.keys[char] == :ctrl_c
|
137
158
|
return if char.nil?
|
138
159
|
codes << char.ord
|
139
160
|
|
140
161
|
condition = proc { |escape|
|
141
162
|
(codes - escape).empty? ||
|
142
163
|
(escape - codes).empty? &&
|
143
|
-
!(64..126).
|
164
|
+
!(64..126).cover?(codes.last)
|
144
165
|
}
|
145
166
|
|
146
167
|
while console.escape_codes.any?(&condition)
|
@@ -162,38 +183,44 @@ module TTY
|
|
162
183
|
# @return [String]
|
163
184
|
#
|
164
185
|
# @api public
|
165
|
-
def read_line(
|
166
|
-
options = args.last.respond_to?(:to_hash) ? args.pop : {}
|
167
|
-
prompt = args.empty? ? '' : args.pop
|
186
|
+
def read_line(prompt = '', **options)
|
168
187
|
opts = { echo: true, raw: true }.merge(options)
|
169
|
-
line = Line.new('')
|
170
|
-
|
171
|
-
clear_line = "\e[2K\e[1G"
|
188
|
+
line = Line.new(prompt, '')
|
189
|
+
screen_width = TTY::Screen.width
|
172
190
|
|
173
|
-
|
191
|
+
output.print(line.prompt)
|
192
|
+
|
193
|
+
while (codes = get_codes(opts)) && (code = codes[0])
|
174
194
|
char = codes.pack('U*')
|
175
195
|
trigger_key_event(char)
|
176
196
|
|
177
|
-
if console.keys[
|
178
|
-
|
179
|
-
|
180
|
-
line
|
181
|
-
|
197
|
+
break if [:ctrl_d, :ctrl_z].include?(console.keys[char])
|
198
|
+
|
199
|
+
if opts[:raw] && opts[:echo]
|
200
|
+
clear_display(line, screen_width)
|
201
|
+
end
|
202
|
+
|
203
|
+
if console.keys[char] == :backspace || BACKSPACE == code
|
204
|
+
if !line.start?
|
205
|
+
line.left
|
206
|
+
line.delete
|
207
|
+
end
|
208
|
+
elsif console.keys[char] == :delete || DELETE == code
|
182
209
|
line.delete
|
183
|
-
elsif
|
184
|
-
console.keys[:ctrl_z]].include?(char)
|
185
|
-
break
|
186
|
-
elsif ctrls.include?(console.keys.key(char))
|
210
|
+
elsif console.keys[char].to_s =~ /ctrl_/
|
187
211
|
# skip
|
188
|
-
elsif console.keys[
|
189
|
-
|
190
|
-
|
191
|
-
elsif console.keys[:down] == char
|
212
|
+
elsif console.keys[char] == :up
|
213
|
+
line.replace(history_previous) if history_previous?
|
214
|
+
elsif console.keys[char] == :down
|
192
215
|
line.replace(history_next? ? history_next : '')
|
193
|
-
elsif console.keys[
|
216
|
+
elsif console.keys[char] == :left
|
194
217
|
line.left
|
195
|
-
elsif console.keys[
|
218
|
+
elsif console.keys[char] == :right
|
196
219
|
line.right
|
220
|
+
elsif console.keys[char] == :home
|
221
|
+
line.move_to_start
|
222
|
+
elsif console.keys[char] == :end
|
223
|
+
line.move_to_end
|
197
224
|
else
|
198
225
|
if opts[:raw] && code == CARRIAGE_RETURN
|
199
226
|
char = "\n"
|
@@ -202,28 +229,73 @@ module TTY
|
|
202
229
|
line.insert(char)
|
203
230
|
end
|
204
231
|
|
232
|
+
if (console.keys[char] == :backspace || BACKSPACE == code) && opts[:echo]
|
233
|
+
if opts[:raw]
|
234
|
+
output.print("\e[1X") unless line.start?
|
235
|
+
else
|
236
|
+
output.print(?\s + (line.start? ? '' : ?\b))
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
205
240
|
if opts[:raw] && opts[:echo]
|
206
|
-
output.print(
|
207
|
-
output.print(prompt + line.to_s)
|
241
|
+
output.print(line.to_s)
|
208
242
|
if char == "\n"
|
209
243
|
line.move_to_start
|
210
|
-
elsif !line.end?
|
211
|
-
output.print(
|
244
|
+
elsif !line.end? # readjust cursor position
|
245
|
+
output.print(cursor.backward(line.text_size - line.cursor))
|
212
246
|
end
|
213
247
|
end
|
214
248
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
if opts[:raw]
|
219
|
-
output.print("\e[1X") unless line.start?
|
220
|
-
else
|
221
|
-
output.print(?\s + (line.start? ? '' : ?\b))
|
222
|
-
end
|
249
|
+
if [CARRIAGE_RETURN, NEWLINE].include?(code)
|
250
|
+
output.puts unless opts[:echo]
|
251
|
+
break
|
223
252
|
end
|
224
253
|
end
|
225
|
-
|
226
|
-
|
254
|
+
if track_history? && opts[:echo]
|
255
|
+
add_to_history(line.text.rstrip)
|
256
|
+
end
|
257
|
+
line.text
|
258
|
+
end
|
259
|
+
|
260
|
+
# Clear display for the current line input
|
261
|
+
#
|
262
|
+
# Handles clearing input that is longer than the current
|
263
|
+
# terminal width which allows copy & pasting long strings.
|
264
|
+
#
|
265
|
+
# @param [Line] line
|
266
|
+
# the line to display
|
267
|
+
# @param [Number] screen_width
|
268
|
+
# the terminal screen width
|
269
|
+
#
|
270
|
+
# @api private
|
271
|
+
def clear_display(line, screen_width)
|
272
|
+
total_lines = count_screen_lines(line.size, screen_width)
|
273
|
+
current_line = count_screen_lines(line.prompt_size + line.cursor, screen_width)
|
274
|
+
lines_down = total_lines - current_line
|
275
|
+
|
276
|
+
output.print(cursor.down(lines_down)) unless lines_down.zero?
|
277
|
+
output.print(cursor.clear_lines(total_lines))
|
278
|
+
end
|
279
|
+
|
280
|
+
# Count the number of screen lines given line takes up in terminal
|
281
|
+
#
|
282
|
+
# @param [Integer] line_or_size
|
283
|
+
# the current line or its length
|
284
|
+
# @param [Integer] screen_width
|
285
|
+
# the width of terminal screen
|
286
|
+
#
|
287
|
+
# @return [Integer]
|
288
|
+
#
|
289
|
+
# @api public
|
290
|
+
def count_screen_lines(line_or_size, screen_width = TTY::Screen.width)
|
291
|
+
line_size = if line_or_size.is_a?(Integer)
|
292
|
+
line_or_size
|
293
|
+
else
|
294
|
+
Line.sanitize(line_or_size).size
|
295
|
+
end
|
296
|
+
# new character + we don't want to add new line on screen_width
|
297
|
+
new_chars = self.class.windows? ? -1 : 1
|
298
|
+
1 + [0, (line_size - new_chars) / screen_width].max
|
227
299
|
end
|
228
300
|
|
229
301
|
# Read multiple lines and return them in an array.
|
@@ -238,11 +310,11 @@ module TTY
|
|
238
310
|
# @return [Array[String]]
|
239
311
|
#
|
240
312
|
# @api public
|
241
|
-
def read_multiline(
|
313
|
+
def read_multiline(*args)
|
242
314
|
@stop = false
|
243
315
|
lines = []
|
244
316
|
loop do
|
245
|
-
line = read_line(
|
317
|
+
line = read_line(*args)
|
246
318
|
break if !line || line == ''
|
247
319
|
next if line !~ /\S/ && !@stop
|
248
320
|
if block_given?
|
@@ -335,14 +407,5 @@ module TTY
|
|
335
407
|
raise InputInterrupt
|
336
408
|
end
|
337
409
|
end
|
338
|
-
|
339
|
-
# Check if Windowz mode
|
340
|
-
#
|
341
|
-
# @return [Boolean]
|
342
|
-
#
|
343
|
-
# @api public
|
344
|
-
def windows?
|
345
|
-
::File::ALT_SEPARATOR == '\\'
|
346
|
-
end
|
347
410
|
end # Reader
|
348
411
|
end # TTY
|
data/lib/tty/reader/console.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require_relative '
|
4
|
+
require_relative 'keys'
|
5
5
|
require_relative 'mode'
|
6
6
|
|
7
7
|
module TTY
|
@@ -27,7 +27,7 @@ module TTY
|
|
27
27
|
def initialize(input)
|
28
28
|
@input = input
|
29
29
|
@mode = Mode.new(input)
|
30
|
-
@keys =
|
30
|
+
@keys = Keys.ctrl_keys.merge(Keys.keys)
|
31
31
|
@escape_codes = [[ESC.ord], CSI.bytes.to_a]
|
32
32
|
end
|
33
33
|
|
data/lib/tty/reader/history.rb
CHANGED
@@ -35,13 +35,17 @@ module TTY
|
|
35
35
|
# the maximum size for history buffer
|
36
36
|
#
|
37
37
|
# param [Hash[Symbol]] options
|
38
|
+
# @option options [Boolean] :cycle
|
39
|
+
# whether or not the history should cycle, false by default
|
38
40
|
# @option options [Boolean] :duplicates
|
39
41
|
# whether or not to store duplicates, true by default
|
42
|
+
# @option options [Boolean] :exclude
|
43
|
+
# a Proc to exclude items from storing in history
|
40
44
|
#
|
41
45
|
# @api public
|
42
|
-
def initialize(max_size = DEFAULT_SIZE, options
|
46
|
+
def initialize(max_size = DEFAULT_SIZE, **options)
|
43
47
|
@max_size = max_size
|
44
|
-
@index =
|
48
|
+
@index = nil
|
45
49
|
@history = []
|
46
50
|
@duplicates = options.fetch(:duplicates) { true }
|
47
51
|
@exclude = options.fetch(:exclude) { proc {} }
|
data/lib/tty/reader/key_event.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require_relative 'keys'
|
5
|
+
|
4
6
|
module TTY
|
5
7
|
class Reader
|
6
8
|
# Responsible for meta-data information about key pressed
|
@@ -27,16 +29,9 @@ module TTY
|
|
27
29
|
# @api public
|
28
30
|
def self.from(keys, char)
|
29
31
|
key = Key.new
|
30
|
-
|
32
|
+
key.name = (name = keys[char]) ? name : :ignore
|
31
33
|
|
32
34
|
case char
|
33
|
-
when keys[:return] then key.name = :return
|
34
|
-
when keys[:enter] then key.name = :enter
|
35
|
-
when keys[:tab] then key.name = :tab
|
36
|
-
when keys[:backspace] then key.name = :backspace
|
37
|
-
when keys[:delete] then key.name = :delete
|
38
|
-
when keys[:space] then key.name = :space
|
39
|
-
when keys[:escape] then key.name = :escape
|
40
35
|
when proc { |c| c =~ /^[a-z]{1}$/ }
|
41
36
|
key.name = :alpha
|
42
37
|
when proc { |c| c =~ /^[A-Z]{1}$/ }
|
@@ -44,34 +39,8 @@ module TTY
|
|
44
39
|
key.shift = true
|
45
40
|
when proc { |c| c =~ /^\d+$/ }
|
46
41
|
key.name = :num
|
47
|
-
|
48
|
-
when keys[:up] then key.name = :up
|
49
|
-
when keys[:down] then key.name = :down
|
50
|
-
when keys[:left] then key.name = :left
|
51
|
-
when keys[:right] then key.name = :right
|
52
|
-
# editing
|
53
|
-
when keys[:clear] then key.name = :clear
|
54
|
-
when keys[:end] then key.name = :end
|
55
|
-
when keys[:home] then key.name = :home
|
56
|
-
when keys[:insert] then key.name = :insert
|
57
|
-
when keys[:page_up] then key.name = :page_up
|
58
|
-
when keys[:page_down] then key.name = :page_down
|
59
|
-
when proc { |cs| ctrls.any? { |name| keys[name] == cs } }
|
60
|
-
key.name = keys.key(char)
|
42
|
+
when proc { |cs| !Keys.ctrl_keys[cs].nil? }
|
61
43
|
key.ctrl = true
|
62
|
-
# f1 - f12
|
63
|
-
when keys[:f1], keys[:f1_xterm] then key.name = :f1
|
64
|
-
when keys[:f2], keys[:f2_xterm] then key.name = :f2
|
65
|
-
when keys[:f3], keys[:f3_xterm] then key.name = :f3
|
66
|
-
when keys[:f4], keys[:f4_xterm] then key.name = :f4
|
67
|
-
when keys[:f5] then key.name = :f5
|
68
|
-
when keys[:f6] then key.name = :f6
|
69
|
-
when keys[:f7] then key.name = :f7
|
70
|
-
when keys[:f8] then key.name = :f8
|
71
|
-
when keys[:f9] then key.name = :f9
|
72
|
-
when keys[:f10] then key.name = :f10
|
73
|
-
when keys[:f11] then key.name = :f11
|
74
|
-
when keys[:f12] then key.name = :f12
|
75
44
|
end
|
76
45
|
|
77
46
|
new(char, key)
|
@@ -0,0 +1,165 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module TTY
|
5
|
+
class Reader
|
6
|
+
# Mapping of escape codes to keys
|
7
|
+
module Keys
|
8
|
+
def ctrl_keys
|
9
|
+
{
|
10
|
+
?\C-a => :ctrl_a,
|
11
|
+
?\C-b => :ctrl_b,
|
12
|
+
?\C-c => :ctrl_c,
|
13
|
+
?\C-d => :ctrl_d,
|
14
|
+
?\C-e => :ctrl_e,
|
15
|
+
?\C-f => :ctrl_f,
|
16
|
+
?\C-g => :ctrl_g,
|
17
|
+
?\C-h => :ctrl_h, # identical to '\b'
|
18
|
+
?\C-i => :ctrl_i, # identical to '\t'
|
19
|
+
?\C-j => :ctrl_j, # identical to '\n'
|
20
|
+
?\C-k => :ctrl_k,
|
21
|
+
?\C-l => :ctrl_l,
|
22
|
+
?\C-m => :ctrl_m, # identical to '\r'
|
23
|
+
?\C-n => :ctrl_n,
|
24
|
+
?\C-o => :ctrl_o,
|
25
|
+
?\C-p => :ctrl_p,
|
26
|
+
?\C-q => :ctrl_q,
|
27
|
+
?\C-r => :ctrl_r,
|
28
|
+
?\C-s => :ctrl_s,
|
29
|
+
?\C-t => :ctrl_t,
|
30
|
+
?\C-u => :ctrl_u,
|
31
|
+
?\C-v => :ctrl_v,
|
32
|
+
?\C-w => :ctrl_w,
|
33
|
+
?\C-x => :ctrl_x,
|
34
|
+
?\C-y => :ctrl_y,
|
35
|
+
?\C-z => :ctrl_z,
|
36
|
+
?\C-@ => :ctrl_space,
|
37
|
+
?\C-| => :ctrl_backslash, # both Ctrl-| & Ctrl-\
|
38
|
+
?\C-] => :ctrl_square_close,
|
39
|
+
"\e[1;5A" => :ctrl_up,
|
40
|
+
"\e[1;5B" => :ctrl_down,
|
41
|
+
"\e[1;5C" => :ctrl_right,
|
42
|
+
"\e[1;5D" => :ctrl_left
|
43
|
+
}
|
44
|
+
end
|
45
|
+
module_function :ctrl_keys
|
46
|
+
|
47
|
+
def keys
|
48
|
+
{
|
49
|
+
"\t" => :tab,
|
50
|
+
"\n" => :enter,
|
51
|
+
"\r" => :return,
|
52
|
+
"\e" => :escape,
|
53
|
+
" " => :space,
|
54
|
+
"\x7F" => :backspace,
|
55
|
+
"\e[1~" => :home,
|
56
|
+
"\e[2~" => :insert,
|
57
|
+
"\e[3~" => :delete,
|
58
|
+
"\e[3;2~" => :shift_delete,
|
59
|
+
"\e[3;5~" => :ctrl_delete,
|
60
|
+
"\e[4~" => :end,
|
61
|
+
"\e[5~" => :page_up,
|
62
|
+
"\e[6~" => :page_down,
|
63
|
+
"\e[7~" => :home, # xrvt
|
64
|
+
"\e[8~" => :end, # xrvt
|
65
|
+
|
66
|
+
"\e[A" => :up,
|
67
|
+
"\e[B" => :down,
|
68
|
+
"\e[C" => :right,
|
69
|
+
"\e[D" => :left,
|
70
|
+
"\e[E" => :clear,
|
71
|
+
"\e[H" => :home,
|
72
|
+
"\eOH" => :home,
|
73
|
+
"\e[F" => :end,
|
74
|
+
"\eOF" => :end,
|
75
|
+
"\e[Z" => :back_tab, # shift + tab
|
76
|
+
|
77
|
+
"\eOP" => :f1,
|
78
|
+
"\eOQ" => :f2,
|
79
|
+
"\eOR" => :f3,
|
80
|
+
"\eOS" => :f4,
|
81
|
+
"\e[[A" => :f1, # linux
|
82
|
+
"\e[[B" => :f2, # linux
|
83
|
+
"\e[[C" => :f3, # linux
|
84
|
+
"\e[[D" => :f4, # linux
|
85
|
+
"\e[[E" => :f5, # linux
|
86
|
+
"\e[11~" => :f1, # rxvt-unicode
|
87
|
+
"\e[12~" => :f2, # rxvt-unicode
|
88
|
+
"\e[13~" => :f3, # rxvt-unicode
|
89
|
+
"\e[14~" => :f4, # rxvt-unicode
|
90
|
+
"\e[15~" => :f5,
|
91
|
+
"\e[17~" => :f6,
|
92
|
+
"\e[18~" => :f7,
|
93
|
+
"\e[19~" => :f8,
|
94
|
+
"\e[20~" => :f9,
|
95
|
+
"\e[21~" => :f10,
|
96
|
+
"\e[23~" => :f11,
|
97
|
+
"\e[24~" => :f12,
|
98
|
+
"\e[25~" => :f13,
|
99
|
+
"\e[26~" => :f14,
|
100
|
+
"\e[28~" => :f15,
|
101
|
+
"\e[29~" => :f16,
|
102
|
+
"\e[31~" => :f17,
|
103
|
+
"\e[32~" => :f18,
|
104
|
+
"\e[33~" => :f19,
|
105
|
+
"\e[34~" => :f20,
|
106
|
+
# xterm
|
107
|
+
"\e[1;2P" => :f13,
|
108
|
+
"\e[2;2Q" => :f14,
|
109
|
+
"\e[1;2S" => :f16,
|
110
|
+
"\e[15;2~" => :f17,
|
111
|
+
"\e[17;2~" => :f18,
|
112
|
+
"\e[18;2~" => :f19,
|
113
|
+
"\e[19;2~" => :f20,
|
114
|
+
"\e[20;2~" => :f21,
|
115
|
+
"\e[21;2~" => :f22,
|
116
|
+
"\e[23;2~" => :f23,
|
117
|
+
"\e[24;2~" => :f24,
|
118
|
+
|
119
|
+
"\eOA" => :up,
|
120
|
+
"\eOB" => :down,
|
121
|
+
"\eOC" => :right,
|
122
|
+
"\eOD" => :left
|
123
|
+
}
|
124
|
+
end
|
125
|
+
module_function :keys
|
126
|
+
|
127
|
+
def win_keys
|
128
|
+
{
|
129
|
+
"\t" => :tab,
|
130
|
+
"\n" => :enter,
|
131
|
+
"\r" => :return,
|
132
|
+
"\e" => :escape,
|
133
|
+
" " => :space,
|
134
|
+
"\b" => :backspace,
|
135
|
+
[224, 71].pack('U*') => :home,
|
136
|
+
[224, 79].pack('U*') => :end,
|
137
|
+
[224, 82].pack('U*') => :insert,
|
138
|
+
[224, 83].pack('U*') => :delete,
|
139
|
+
[224, 73].pack('U*') => :page_up,
|
140
|
+
[224, 81].pack('U*') => :page_down,
|
141
|
+
|
142
|
+
[224, 72].pack('U*') => :up,
|
143
|
+
[224, 80].pack('U*') => :down,
|
144
|
+
[224, 77].pack('U*') => :right,
|
145
|
+
[224, 75].pack('U*') => :left,
|
146
|
+
[224, 83].pack('U*') => :clear,
|
147
|
+
|
148
|
+
"\x00;" => :f1,
|
149
|
+
"\x00<" => :f2,
|
150
|
+
"\x00" => :f3,
|
151
|
+
"\x00=" => :f4,
|
152
|
+
"\x00?" => :f5,
|
153
|
+
"\x00@" => :f6,
|
154
|
+
"\x00A" => :f7,
|
155
|
+
"\x00B" => :f8,
|
156
|
+
"\x00C" => :f9,
|
157
|
+
"\x00D" => :f10,
|
158
|
+
"\x00\x85" => :f11,
|
159
|
+
"\x00\x86" => :f12
|
160
|
+
}
|
161
|
+
end
|
162
|
+
module_function :win_keys
|
163
|
+
end # Keys
|
164
|
+
end # Reader
|
165
|
+
end # TTY
|