keyboard_map 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 73f42043d059844447e80fadb95e205f0322d878d6916adb150bb884422b9ea6
4
- data.tar.gz: 116ca240612ee19ceb90b8541364cae3fba201998c9cff9a74688959b8c2037d
3
+ metadata.gz: d26c9809ebcc1a3c96e7880a2ba11dcd661376271914d1835331b6b065a8c040
4
+ data.tar.gz: 45e5461eefa006f0e1babd9f3077943c545cfd82610225f9ff697426aeb4121c
5
5
  SHA512:
6
- metadata.gz: a95f1a9d85e9ee5313f2251801c64bf026f21b7fd5c2f18ba4f4627481c311b0f63bbfdbfe51db6b66b770ca154dcdc2dc6eff872dfb7e0ffc24f3b0adde1777
7
- data.tar.gz: be940b88650dd017a2bdb66b86e7c6f6e6b326830572c60249e4c00f0d3f393d7e5b3aa6e570df997ee077c37e7e138de9d2e3a30306497c6b65ecf4ed054632
6
+ metadata.gz: e3fcde7cb8fef76c77de741c35d2d0eb6dc70ac95ce27fe6a782506c67358e5a0fb16a0798a29778e4d898b8c985a732a0cb6ca1657fe7ffa07bd21b3de1b17b
7
+ data.tar.gz: 29708ba703f28777f05c86482e80af5265b947ac0499bd258896e4077e8af086328d9ec758b7507601f74f0780c1b2409dad005ac653d168b6e0e7cc8d6e8bfc
data/README.md CHANGED
@@ -2,16 +2,37 @@
2
2
 
3
3
  Process key-presses and map escape-sequences to symbols.
4
4
 
5
- Dealing with raw keyboard input is painful because something like cursor-up
6
- can return several different sequences depending on terminal, *and* because
7
- there is no terribly simple algorithm determining what represents the
8
- end of a single sequence. In fact some software relies on key-presses being
9
- slow enough to set a timeout and read character by character.
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
- TODO: Write usage instructions here
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. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
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 install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
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 https://github.com/vidarh/keyboard_map.
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 License](https://opensource.org/licenses/MIT).
105
+ The gem is available as open source under the terms of the [MIT
106
+ License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,51 @@
1
+
2
+ $: << File.dirname(__FILE__)+"/lib"
3
+ require 'io/console'
4
+ require_relative '../lib/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}\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", "~> 1.16"
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
@@ -1,3 +1,3 @@
1
1
  class KeyboardMap
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
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
- (modifiers.to_a.sort << key).join("_").to_sym
24
+ to_s.to_sym
21
25
  end
22
26
 
23
27
  def ==(ev)
@@ -49,16 +53,19 @@ class KeyboardMap
49
53
  "E" => :keypad_5,
50
54
  "F" => :end,
51
55
  "H" => :home,
52
- "P" => :f1,
56
+ "J" => :ctrl_end, # st reports this
57
+ "L" => :ctrl_insert, # st reports this
58
+ "P" => :delete,
53
59
  "Q" => :f2,
54
60
  "R" => :f3,
55
- "S" => :f4,
61
+ "S" => :f4
56
62
  }.freeze
57
63
 
58
64
  # \e[{parameter1}{;...}~ from parameter1 => key
59
65
  CSI_TILDE_MAP = {
60
66
  "2" => :insert,
61
67
  "3" => :delete,
68
+ "4" => :end, # st reports this
62
69
  "5" => :page_up,
63
70
  "6" => :page_down,
64
71
  "11" => :f1,
@@ -86,19 +93,30 @@ class KeyboardMap
86
93
  @@key_events[k]
87
94
  end
88
95
 
96
+ def event(key, *modifiers)
97
+ self.class.event(key,*modifiers)
98
+ end
99
+
89
100
  # Map of simple/non-parameterised escape sequences to symbols
90
101
  ESCAPE_MAP = {
91
102
  "\e[Z" => event(:tab,:shift),
92
103
  "\eOP" => :f1,
93
104
  "\eOQ" => :f2,
94
105
  "\eOR" => :f3,
95
- "\eOS" => :f4
106
+ "\eOS" => :f4,
107
+ "\e[M" => event(:delete,:ctrl), # st reports this
108
+ "\e[4h" => :insert # st reports this
96
109
  }.freeze
97
110
 
98
111
  CSI_FINAL_BYTE = 0x40..0x7e
99
112
 
100
113
  def meta(key)
101
- self.class.event(key,:meta)
114
+ mod = [:meta]
115
+ if key.ord < 32
116
+ mod << :ctrl
117
+ key = (key.ord+96).chr
118
+ end
119
+ self.class.event(key,*mod)
102
120
  end
103
121
 
104
122
  ESC = "\e"
@@ -109,9 +127,13 @@ class KeyboardMap
109
127
  @state = :text
110
128
  end
111
129
 
112
- def call(input)
130
+ def finish
131
+ run || (@state == :esc ? :esc : nil)
132
+ end
133
+
134
+ def call(input, opt = nil)
113
135
  @buf << input
114
- run
136
+ opt == :finished ? finish : run
115
137
  end
116
138
 
117
139
  def map_escape(seq)
@@ -184,7 +206,7 @@ class KeyboardMap
184
206
  elsif ch == "\t"
185
207
  @state = :text
186
208
  @tmp = ""
187
- return meta(:tab)
209
+ return event(:tab, :meta)
188
210
  elsif ch == "\e"
189
211
  return :esc
190
212
  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.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vidar Hokstad
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-11-11 00:00:00.000000000 Z
11
+ date: 2022-10-31 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: '1.16'
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: '1.16'
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