Class: SublimeDSL::SublimeText::Keyboard
- Inherits:
-
Object
- Object
- SublimeDSL::SublimeText::Keyboard
- Defined in:
- lib/sublime_dsl/sublime_text/keyboard.rb
Overview
A keyboard.
Defined Under Namespace
Classes: CharStroke, DSLReader, Key, KeyStroke, NullStroke
Constant Summary collapse
- SUBLIME_MODIFIERS =
%w(shift ctrl alt super)- SUBLIME_KEYS =
%w( escape f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 f13 f14 f15 f16 f17 f18 f19 f20 sysreq pause up down right left insert home end pageup pagedown backspace delete tab enter context_menu keypad0 keypad1 keypad2 keypad3 keypad4 keypad5 keypad6 keypad7 keypad8 keypad9 keypad_period keypad_divide keypad_multiply keypad_minus keypad_plus keypad_enter clear break browser_back browser_forward browser_refresh browser_stop browser_search browser_favorites browser_home ` 0 1 2 3 4 5 6 7 8 9 - = + a b c d e f g h i j k l m n o p q r s t u v w x y z [ ] \\ ; ' , . / space )- SUBLIME_ALIAS_MAP =
{ 'forward_slash' => '/', 'backquote' => '`', 'equals' => '=', 'plus' => '+', 'minus' => '-' }
- SUBLIME_ALIAS_RE =
/^(#{SUBLIME_ALIAS_MAP.keys.join('|')})$/
Instance Attribute Summary collapse
-
#keys ⇒ Object
readonly
Key instances.
-
#keystrokes_hash ⇒ Object
readonly
normalized spec => KeyStroke or CharStroke instance.
-
#modifiers ⇒ Object
readonly
Key instances.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#os ⇒ Object
Returns the value of attribute os.
Class Method Summary collapse
- .get(name, root) ⇒ Object
-
.sublime ⇒ Object
The standard Sublime Text keyboard.
Instance Method Summary collapse
-
#add_key(name) ⇒ Object
Create a Key
nameand adds the corresponding KeyStroke to this keyboard. - #add_keystroke(ks) ⇒ Object
- #add_modifier(name) ⇒ Object
-
#assign_default_key_event(keystroke) ⇒ Object
Assign the default key_event of a new keystroke (before its registration).
-
#ensure_keystroke(spec) ⇒ Object
Returns a KeyStroke or CharStroke for
spec, and adds it to the registered keystrokes if not already there. -
#initialize(name) ⇒ Keyboard
constructor
A new instance of Keyboard.
- #key(name) ⇒ Object
- #keystroke_for_sublime_spec(st_spec) ⇒ Object
- #keystrokes ⇒ Object
-
#map_char(options = {}) ⇒ Object
Map a keystroke to a chr_event.
-
#map_key(spec, st_spec) ⇒ Object
Assigns the key_event for the keystroke
spec. - #map_modifier(name, st_name) ⇒ Object
- #modifier(name) ⇒ Object
- #modifiers_index_hash ⇒ Object
Constructor Details
#initialize(name) ⇒ Keyboard
77 78 79 80 81 82 83 84 85 |
# File 'lib/sublime_dsl/sublime_text/keyboard.rb', line 77 def initialize(name) @name = name @os = nil @modifiers = [] @keys = [] @keystrokes_hash = {} # Vintage generic character add_keystroke CharStroke.new('<character>') end |
Instance Attribute Details
#keys ⇒ Object (readonly)
Key instances
74 75 76 |
# File 'lib/sublime_dsl/sublime_text/keyboard.rb', line 74 def keys @keys end |
#keystrokes_hash ⇒ Object (readonly)
normalized spec => KeyStroke or CharStroke instance
75 76 77 |
# File 'lib/sublime_dsl/sublime_text/keyboard.rb', line 75 def keystrokes_hash @keystrokes_hash end |
#modifiers ⇒ Object (readonly)
Key instances
74 75 76 |
# File 'lib/sublime_dsl/sublime_text/keyboard.rb', line 74 def modifiers @modifiers end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
73 74 75 |
# File 'lib/sublime_dsl/sublime_text/keyboard.rb', line 73 def name @name end |
#os ⇒ Object
Returns the value of attribute os.
73 74 75 |
# File 'lib/sublime_dsl/sublime_text/keyboard.rb', line 73 def os @os end |
Class Method Details
.get(name, root) ⇒ Object
62 63 64 65 66 67 68 69 70 71 |
# File 'lib/sublime_dsl/sublime_text/keyboard.rb', line 62 def self.get(name, root) file = nil Dir.chdir(root) do files = Dir['**/*.keyboard.rb'] file = SublimeText.order_config(files).last file or raise Error, "file '#{name}.keyboard.rb' not found" file = File.(file) end DSLReader.new(file)._keyboard end |
.sublime ⇒ Object
The standard Sublime Text keyboard.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/sublime_dsl/sublime_text/keyboard.rb', line 43 def self.sublime @sublime ||= begin kb = Keyboard.new('Sublime Text') SUBLIME_MODIFIERS.each { |name| kb.add_modifier name } SUBLIME_KEYS.each { |name| kb.add_key name } # map_char and map_key call this method while @sublime is not yet set unless @defining_sublime @defining_sublime = true # FIXME: space => key_event nil, but generates a key_event when modified, # because it's a character # => put it in SUBLIME_ALIAS_MAP, but remember it was named 'space' when # generating its to_s ('ctrl+ ' will generate problems...) kb.map_char 'space' => ' ', key_event: nil @defining_sublime = false end kb end end |
Instance Method Details
#add_key(name) ⇒ Object
Create a Key name and adds the corresponding KeyStroke to this keyboard.
-
If
nameis one character long, the KeyStroke generates a chr_eventnameand no key_event. -
Otherwise, the KeyStroke generates no chr_event, and a key_event
nameifnameis a Sublime Text key name.
124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/sublime_dsl/sublime_text/keyboard.rb', line 124 def add_key(name) k = Key.new(name) k.st_name = name if SUBLIME_KEYS.include?(name) @keys << k ks = KeyStroke.new([], k) if name.length == 1 ks.chr_event = name else ks.key_event = k.st_name end add_keystroke ks k end |
#add_keystroke(ks) ⇒ Object
175 176 177 |
# File 'lib/sublime_dsl/sublime_text/keyboard.rb', line 175 def add_keystroke(ks) @keystrokes_hash[ks.to_spec] = ks end |
#add_modifier(name) ⇒ Object
104 105 106 107 108 |
# File 'lib/sublime_dsl/sublime_text/keyboard.rb', line 104 def add_modifier(name) m = Key.new(name) m.st_name = name if SUBLIME_MODIFIERS.include?(name) @modifiers << m end |
#assign_default_key_event(keystroke) ⇒ Object
Assign the default key_event of a new keystroke (before its registration). It will be the modified key_event of a less specific keystroke.
For instance, if we register ‘shift+ctrl+keypad5’, and ‘shift+keypad5’ has key event ‘clear’, this assigns ‘ctrl+clear’. If there are several possibilities, the one(s) with the most modifiers are selected. If there are ex-aequo, the order of precedence is the order of registration of the modifiers.
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 |
# File 'lib/sublime_dsl/sublime_text/keyboard.rb', line 285 def assign_default_key_event(keystroke) # the ST keyboard: just register if self == Keyboard.sublime spec = keystroke.to_spec keystroke.key_event = spec if spec.length > 1 return end # we always have modifiers, as all non-modified keys are already registered keystroke.modifiers.empty? and raise Error, "bug: #{keystroke} is not registered" # if the key has a ST name, assume the ST equivalent if keystroke.key.st_name spec = keystroke.modifiers.map(&:st_name).join('+') << '+' << keystroke.key.st_name keystroke.key_event = spec return end # the candidates are the registered keystrokes for that key with all # modifiers included in the passed modifiers (so at least the keystroke # for the key itself) candidates = keystrokes_hash.values.select do |ks| ks.key == keystroke.key && ks.modifiers - keystroke.modifiers == [] end candidates.empty? and raise Error, "bug: nothing registered for #{keystroke}" if candidates.length > 1 # select the one(s) with the most modifiers max = 0 candidates.each do |ks| max = ks.modifiers.length if ks.modifiers.length > max end candidates.reject! { |ks| ks.modifiers.length < max } # apply modifier priority: # create the bit mask for each keystroke, # and then select the lowest one if candidates.length > 1 sort_array = candidates.map do |ks| mask = 0 ks.modifiers.each do |m| mask += (1 << modifiers_index_hash[m.name]) end [ks, mask] end candidates = sort_array.sort_by(&:last).map(&:first) end end # select the reference keystroke ref = candidates.first if ref.key_event.nil? keystroke.key_event = nil return end # apply the modifier delta versus the reference delta = keystroke.modifiers - ref.modifiers spec = delta.map(&:st_name).join('+') << '+' << ref.key_event keystroke.key_event = Keyboard.sublime.ensure_keystroke(spec).to_spec end |
#ensure_keystroke(spec) ⇒ Object
Returns a KeyStroke or CharStroke for spec, and adds it to the registered keystrokes if not already there. Raises an exception if spec is not valid.
-
If
specis one character long, returns a KeyStroke or CharStroke if found, otherwise creates a new CharStroke. -
If
specis more than one character long, the key has to exist, as well as the modifiers if any, otherwise an exception is raised. If the corresponding KeyStroke is not found, it will be created and registered.
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/sublime_dsl/sublime_text/keyboard.rb', line 217 def ensure_keystroke(spec) # split the specification # ctrl++ -> ['ctrl', '+'] # ctrl+num+ -> ['ctrl', 'num+'] *modifier_names, key_name = spec.split(/\+(?!$)/) # normalize the key name self == Keyboard.sublime and key_name.sub! SUBLIME_ALIAS_RE, SUBLIME_ALIAS_MAP # check & reorder the modifiers unless modifier_names.empty? sorted = [] modifier_names.each do |name| i = modifiers_index_hash[name] or raise Error, "invalid modifier #{name.inspect} for keyboard #{self.name}" sorted[i] = name end modifier_names = sorted.compact end # if there is a registered keystroke for this spec, return it std_spec = [*modifier_names, key_name].join('+') ks = keystrokes_hash[std_spec] return ks if ks # shift + character is not ok modifiers = modifier_names.map { |n| modifier(n) } modifiers.map(&:st_name) == ['shift'] && key_name.length == 1 and raise Error, "#{spec.to_source(true)} is invalid: specify the corresponding character" key = key(key_name) # The ST keyboard accepts any character as a valid key if self == Keyboard.sublime && key.nil? key_name.length == 1 or raise Error, "invalid key name in #{spec.to_source(true)}" key = add_key(key_name) return keystrokes_hash[key_name] if modifiers.empty? end if key # registered key ks = KeyStroke.new(modifiers, key) assign_default_key_event ks else # unregistered: has to be a character key_name.length == 1 or raise Error, "#{spec.inspect}: key #{key_name.inspect} is undefined" modifier_names.empty? or raise Error, "#{spec.inspect}: #{key_name.inspect} is not a key" ks = CharStroke.new(key_name) end add_keystroke ks ks end |
#key(name) ⇒ Object
100 101 102 |
# File 'lib/sublime_dsl/sublime_text/keyboard.rb', line 100 def key(name) keys.find { |k| k.name == name } end |
#keystroke_for_sublime_spec(st_spec) ⇒ Object
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/sublime_dsl/sublime_text/keyboard.rb', line 183 def keystroke_for_sublime_spec(st_spec) st_ks = Keyboard.sublime.ensure_keystroke(st_spec) st_spec = st_ks.to_spec # standardize # return the first one with a key event = the passed spec this_ks = keystrokes.find { |ks| ks.key_event == st_spec } return this_ks if this_ks # if one char, no problem return ensure_keystroke(st_spec) if st_spec.length == 1 || st_spec == '<character>' # not (yet?) registered: find a keystroke with the same key base_ks = keystrokes.find { |ks| ks.key && ks.key.st_name == st_ks.key.name } if base_ks this_spec = st_ks.modifiers.map(&:name).join('+') << '+' << base_ks.key.name this_ks = ensure_keystroke(this_spec) return this_ks end NullStroke.new(st_spec) end |
#keystrokes ⇒ Object
179 180 181 |
# File 'lib/sublime_dsl/sublime_text/keyboard.rb', line 179 def keystrokes keystrokes_hash.values end |
#map_char(options = {}) ⇒ Object
Map a keystroke to a chr_event. Optionally sets the key_event.
161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/sublime_dsl/sublime_text/keyboard.rb', line 161 def map_char( = {}) ks_name = .keys.first ks = ensure_keystroke(ks_name) ks.chr_event = [ks_name] if .has_key?(:key_event) st_spec = [:key_event] if st_spec st_ks = Keyboard.sublime.ensure_keystroke(st_spec) st_spec = st_ks.to_spec end ks.key_event = st_spec end end |
#map_key(spec, st_spec) ⇒ Object
Assigns the key_event for the keystroke spec. st_spec must be a valid ST keystroke, or nil if the keystroke is not seen by ST.
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/sublime_dsl/sublime_text/keyboard.rb', line 143 def map_key(spec, st_spec) ks = ensure_keystroke(spec) if st_spec.nil? ks.key_event = nil else st_ks = Keyboard.sublime.ensure_keystroke(st_spec) st_spec = st_ks.to_spec if ks.modifiers.empty? ks.key.st_name = st_spec ks.key_event = st_spec if st_spec.length > 1 else ks.key_event = st_spec end end end |
#map_modifier(name, st_name) ⇒ Object
110 111 112 113 114 |
# File 'lib/sublime_dsl/sublime_text/keyboard.rb', line 110 def map_modifier(name, st_name) m = modifier(name) or raise Error, "unknown modifier: '#{name}'" SUBLIME_MODIFIERS.include?(st_name) or raise Error, "invalid ST modifier: #{st_name}" m.st_name = st_name end |
#modifier(name) ⇒ Object
96 97 98 |
# File 'lib/sublime_dsl/sublime_text/keyboard.rb', line 96 def modifier(name) modifiers.find { |k| k.name == name } end |
#modifiers_index_hash ⇒ Object
353 354 355 356 357 358 359 |
# File 'lib/sublime_dsl/sublime_text/keyboard.rb', line 353 def modifiers_index_hash @modifiers_index_hash ||= begin h = {} modifiers.each_with_index { |m, i| h[m.name] = i } h end end |