keyboard_map 0.1.3 → 0.2.3
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/README.md +69 -10
- data/example/example.rb +51 -0
- data/keyboard_map.gemspec +1 -1
- data/lib/keyboard_map/version.rb +1 -1
- data/lib/keyboard_map.rb +34 -14
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a5fb58fcf07cf9b6237370218b56f444f5c79295eba3f553e95313402fac23e5
|
4
|
+
data.tar.gz: 2d4723071b4131000e4a41fe7e8c6eab1d6de1ce3a6f5b0cb6e72c36d2eed08a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e50d81647cbe0dcb32888cae9750f0c6f61c0e0b4ea72a61b8d1654ba26593665124f9a81b65e4d664c09acf608e09ace48c4922eb8fe750e45efe5ed0798e5
|
7
|
+
data.tar.gz: 0c4d9666605e5030e71de431bc49cfb4df5a775756188e2304d2b1d555fa75375004d0c135d1d785b87d68ccb515590ccbfba4fe1408e5bcd09ac3968ed01836
|
data/README.md
CHANGED
@@ -2,16 +2,37 @@
|
|
2
2
|
|
3
3
|
Process key-presses and map escape-sequences to symbols.
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
E.g instead of getting ASCII 0x03 you'll get `:ctrl_c`
|
6
|
+
|
7
|
+
Dealing with raw keyboard input is painful because something like
|
8
|
+
cursor-up can return several different sequences depending on terminal,
|
9
|
+
*and* because there is no terribly simple algorithm determining what
|
10
|
+
represents the end of a single sequence. In fact some software relies on
|
11
|
+
key-presses being slow enough to set a timeout and read character by
|
12
|
+
character.
|
10
13
|
|
11
14
|
KeyboardMap allows you to handle the reads in whichever way you prefer.
|
12
15
|
It simply provides a simple state machine that will return an array of
|
13
16
|
the keyboard events found so far.
|
14
17
|
|
18
|
+
### Current state
|
19
|
+
|
20
|
+
This is currently usable and I rely on it daily in my personal editor,
|
21
|
+
which uses this gem for keyboard processing.
|
22
|
+
|
23
|
+
However there are many missing sequences (PR's welcome), and it's likely
|
24
|
+
that it will misreport sequences for certain terminals (PR's also
|
25
|
+
welcome), so use with some caution.
|
26
|
+
|
27
|
+
Eventually it's likely it will need to deal with termcaps etc., but at
|
28
|
+
the moment I'm "cheating" and relying on the fact that most modern
|
29
|
+
terminals support a mostly shared subset of VT100.
|
30
|
+
|
31
|
+
You can use the example in examples/example.rb to get an idea of what
|
32
|
+
your terminal returns for a given keyboard sequence. If you run into
|
33
|
+
problems, please include the output from that when filing an issue,
|
34
|
+
combined with your *expected* result.
|
35
|
+
|
15
36
|
## Installation
|
16
37
|
|
17
38
|
Add this line to your application's Gemfile:
|
@@ -30,18 +51,56 @@ Or install it yourself as:
|
|
30
51
|
|
31
52
|
## Usage
|
32
53
|
|
33
|
-
|
54
|
+
See a full example in `examples/example.rb`, but the basics:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
require 'bundler'
|
58
|
+
require 'io/console'
|
59
|
+
require 'keyboard_map'
|
60
|
+
|
61
|
+
kb = KeyboardMap.new
|
62
|
+
|
63
|
+
IO.console.raw do # You want to get individual keypresses.
|
64
|
+
loop do
|
65
|
+
ch = $stdin.getc
|
66
|
+
|
67
|
+
# events can include zero or more events.
|
68
|
+
# Zero events will happen if the character
|
69
|
+
# is part of a compound sequence
|
70
|
+
|
71
|
+
events = kb.call(ch)
|
72
|
+
events.each do |e|
|
73
|
+
# Process events here.
|
74
|
+
p e
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
```
|
79
|
+
|
80
|
+
### But I want to catch "Esc"
|
81
|
+
|
82
|
+
If you're sure you've read a complete sequence, you can do this
|
83
|
+
by passing :finished as a second argument to call, or by calling the
|
84
|
+
`#finish` method. You can see this done in `examples/example.rb`
|
34
85
|
|
35
86
|
## Development
|
36
87
|
|
37
|
-
After checking out the repo, run `bin/setup` to install dependencies.
|
88
|
+
After checking out the repo, run `bin/setup` to install dependencies.
|
89
|
+
Then, run `rake spec` to run the tests. You can also run `bin/console`
|
90
|
+
for an interactive prompt that will allow you to experiment.
|
38
91
|
|
39
|
-
To install this gem onto your local machine, run `bundle exec rake
|
92
|
+
To install this gem onto your local machine, run `bundle exec rake
|
93
|
+
install`. To release a new version, update the version number in
|
94
|
+
`version.rb`, and then run `bundle exec rake release`, which will create
|
95
|
+
a git tag for the version, push git commits and tags, and push the `.gem`
|
96
|
+
file to [rubygems.org](https://rubygems.org).
|
40
97
|
|
41
98
|
## Contributing
|
42
99
|
|
43
|
-
Bug reports and pull requests are welcome on GitHub at
|
100
|
+
Bug reports and pull requests are welcome on GitHub at
|
101
|
+
https://github.com/vidarh/keyboard_map.
|
44
102
|
|
45
103
|
## License
|
46
104
|
|
47
|
-
The gem is available as open source under the terms of the [MIT
|
105
|
+
The gem is available as open source under the terms of the [MIT
|
106
|
+
License](https://opensource.org/licenses/MIT).
|
data/example/example.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
|
2
|
+
$: << File.dirname(__FILE__)+"/../lib"
|
3
|
+
require 'io/console'
|
4
|
+
require 'keyboard_map'
|
5
|
+
|
6
|
+
kb = KeyboardMap.new
|
7
|
+
|
8
|
+
puts "'q' to quit"
|
9
|
+
|
10
|
+
at_exit do
|
11
|
+
STDOUT.print "\e[?2004l" #Disable bracketed paste
|
12
|
+
STDOUT.print "\e[?1000l" #Disable mouse reporting
|
13
|
+
end
|
14
|
+
|
15
|
+
STDOUT.print "\e[?2004h" # Enable bracketed paste
|
16
|
+
STDOUT.print "\e[?1000h" # Enable mouse reporting
|
17
|
+
STDOUT.print "\e[?1006h" # Enable extended reporting
|
18
|
+
|
19
|
+
IO.console.raw do
|
20
|
+
loop do
|
21
|
+
# We use a non-blocking read of multiple characters
|
22
|
+
# in the hope of the read returning a complete sequence,
|
23
|
+
# which allows us to assume a singular ESC is a single press of
|
24
|
+
# the Esc key.
|
25
|
+
#
|
26
|
+
# If you don't need/care about Esc, you can replace the below
|
27
|
+
# with ch = $stdin.getc and omit the `:finished` argument passed to
|
28
|
+
# `call` below.
|
29
|
+
#
|
30
|
+
begin
|
31
|
+
ch = $stdin.read_nonblock(32)
|
32
|
+
rescue IO::WaitReadable
|
33
|
+
IO.select([$stdin])
|
34
|
+
retry
|
35
|
+
end
|
36
|
+
print "\rRaw: #{ch.inspect} first char: #{ch[0].ord}\n\r"
|
37
|
+
r = kb.call(ch, :finished)
|
38
|
+
r.each do |ev|
|
39
|
+
case ev
|
40
|
+
when KeyboardMap::Event
|
41
|
+
puts "Event: #{ev.inspect}"
|
42
|
+
print "\r"
|
43
|
+
puts "Symbol: #{ev.to_sym}"
|
44
|
+
else
|
45
|
+
print "Text: #{ev}\n\r"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
print "\r"
|
49
|
+
break if r.first == "q"
|
50
|
+
end
|
51
|
+
end
|
data/keyboard_map.gemspec
CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
24
|
spec.require_paths = ["lib"]
|
25
25
|
|
26
|
-
spec.add_development_dependency "bundler", "~>
|
26
|
+
spec.add_development_dependency "bundler", "~> 2"
|
27
27
|
spec.add_development_dependency "rake", "~> 10.0"
|
28
28
|
spec.add_development_dependency "rspec", "~> 3.0"
|
29
29
|
end
|
data/lib/keyboard_map/version.rb
CHANGED
data/lib/keyboard_map.rb
CHANGED
@@ -5,7 +5,7 @@ require "keyboard_map/version"
|
|
5
5
|
require 'set'
|
6
6
|
|
7
7
|
class KeyboardMap
|
8
|
-
attr_reader :buf
|
8
|
+
attr_reader :buf, :state
|
9
9
|
|
10
10
|
class Event
|
11
11
|
attr_reader :modifiers,:key, :args
|
@@ -16,8 +16,12 @@ class KeyboardMap
|
|
16
16
|
@args = args
|
17
17
|
end
|
18
18
|
|
19
|
+
def to_s
|
20
|
+
(modifiers.to_a.sort << key).join("_")
|
21
|
+
end
|
22
|
+
|
19
23
|
def to_sym
|
20
|
-
|
24
|
+
to_s.to_sym
|
21
25
|
end
|
22
26
|
|
23
27
|
def ==(ev)
|
@@ -69,13 +73,13 @@ class KeyboardMap
|
|
69
73
|
"13" => :f3,
|
70
74
|
"14" => :f4,
|
71
75
|
"15" => :f5,
|
72
|
-
"
|
73
|
-
"
|
74
|
-
"
|
75
|
-
"
|
76
|
-
"
|
77
|
-
"
|
78
|
-
"
|
76
|
+
"16" => :f6,
|
77
|
+
"17" => :f7,
|
78
|
+
"18" => :f8,
|
79
|
+
"19" => :f9,
|
80
|
+
"20" => :f10,
|
81
|
+
"21" => :f11,
|
82
|
+
"22" => :f12,
|
79
83
|
"200" => :start_paste,
|
80
84
|
"201" => :end_paste,
|
81
85
|
}.freeze
|
@@ -89,6 +93,10 @@ class KeyboardMap
|
|
89
93
|
@@key_events[k]
|
90
94
|
end
|
91
95
|
|
96
|
+
def event(key, *modifiers)
|
97
|
+
self.class.event(key,*modifiers)
|
98
|
+
end
|
99
|
+
|
92
100
|
# Map of simple/non-parameterised escape sequences to symbols
|
93
101
|
ESCAPE_MAP = {
|
94
102
|
"\e[Z" => event(:tab,:shift),
|
@@ -97,13 +105,21 @@ class KeyboardMap
|
|
97
105
|
"\eOR" => :f3,
|
98
106
|
"\eOS" => :f4,
|
99
107
|
"\e[M" => event(:delete,:ctrl), # st reports this
|
100
|
-
"\e[4h" => :insert # st reports this
|
108
|
+
"\e[4h" => :insert, # st reports this
|
109
|
+
"\e\x7f" => event(:backspace, :meta),
|
101
110
|
}.freeze
|
102
111
|
|
103
112
|
CSI_FINAL_BYTE = 0x40..0x7e
|
104
113
|
|
105
114
|
def meta(key)
|
106
|
-
|
115
|
+
mod = [:meta]
|
116
|
+
if SINGLE_KEY_EVENT[key]
|
117
|
+
key = SINGLE_KEY_EVENT[key]
|
118
|
+
elsif key.ord < 32
|
119
|
+
mod << :ctrl
|
120
|
+
key = (key.ord+96).chr
|
121
|
+
end
|
122
|
+
self.class.event(key,*mod)
|
107
123
|
end
|
108
124
|
|
109
125
|
ESC = "\e"
|
@@ -114,9 +130,13 @@ class KeyboardMap
|
|
114
130
|
@state = :text
|
115
131
|
end
|
116
132
|
|
117
|
-
def
|
133
|
+
def finish
|
134
|
+
run || (@state == :esc ? :esc : nil)
|
135
|
+
end
|
136
|
+
|
137
|
+
def call(input, opt = nil)
|
118
138
|
@buf << input
|
119
|
-
run
|
139
|
+
opt == :finished ? finish : run
|
120
140
|
end
|
121
141
|
|
122
142
|
def map_escape(seq)
|
@@ -189,7 +209,7 @@ class KeyboardMap
|
|
189
209
|
elsif ch == "\t"
|
190
210
|
@state = :text
|
191
211
|
@tmp = ""
|
192
|
-
return
|
212
|
+
return event(:tab, :meta)
|
193
213
|
elsif ch == "\e"
|
194
214
|
return :esc
|
195
215
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: keyboard_map
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vidar Hokstad
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '2'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -68,6 +68,7 @@ files:
|
|
68
68
|
- Rakefile
|
69
69
|
- bin/console
|
70
70
|
- bin/setup
|
71
|
+
- example/example.rb
|
71
72
|
- keyboard_map.gemspec
|
72
73
|
- lib/keyboard_map.rb
|
73
74
|
- lib/keyboard_map/version.rb
|
@@ -90,7 +91,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
90
91
|
- !ruby/object:Gem::Version
|
91
92
|
version: '0'
|
92
93
|
requirements: []
|
93
|
-
rubygems_version: 3.
|
94
|
+
rubygems_version: 3.4.10
|
94
95
|
signing_key:
|
95
96
|
specification_version: 4
|
96
97
|
summary: Read characters from the console and map special keys to symbols
|