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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ad97855210bbcfc5569c0e179eccd55e03429b114b148c5222dede98f06d9a44
4
- data.tar.gz: d604867d99759803d8c1dedda23ac64f328f51a538015655e661db286f6cb5b7
3
+ metadata.gz: a5fb58fcf07cf9b6237370218b56f444f5c79295eba3f553e95313402fac23e5
4
+ data.tar.gz: 2d4723071b4131000e4a41fe7e8c6eab1d6de1ce3a6f5b0cb6e72c36d2eed08a
5
5
  SHA512:
6
- metadata.gz: 8bcdbdd51c0696d7622c8e6bb2ffb189db619c4e72d45b5019773908949750413322d6c695a89b7352e0dff715942d7d8b8816d841b7c59489f40f0fb3662858
7
- data.tar.gz: 822319cc6e5c2596d4ec04d86af0d14de91dc32a9a2142dccf8928454fb276c395bd918eb1ed026a0f362d908587468d16b9cb3bfeebd8645279d57716672012
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
- 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 '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", "~> 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.3"
2
+ VERSION = "0.2.3"
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)
@@ -69,13 +73,13 @@ class KeyboardMap
69
73
  "13" => :f3,
70
74
  "14" => :f4,
71
75
  "15" => :f5,
72
- "17" => :f6,
73
- "18" => :f7,
74
- "19" => :f8,
75
- "20" => :f9,
76
- "21" => :f10,
77
- "23" => :f11,
78
- "24" => :f12,
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
- self.class.event(key,:meta)
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 call(input)
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 meta(:tab)
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.1.3
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: 2022-10-02 00:00:00.000000000 Z
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: '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
@@ -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.1.4
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