tty-reader 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|