rbindkeys 0.0.1
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.
- data/.gitignore +23 -0
 - data/Gemfile +4 -0
 - data/LICENSE +22 -0
 - data/README.md +52 -0
 - data/Rakefile +11 -0
 - data/bin/rbindkeys +5 -0
 - data/lib/rbindkeys.rb +38 -0
 - data/lib/rbindkeys/bind_resolver.rb +58 -0
 - data/lib/rbindkeys/bind_set.rb +10 -0
 - data/lib/rbindkeys/bind_tree.rb +148 -0
 - data/lib/rbindkeys/cli.rb +103 -0
 - data/lib/rbindkeys/device.rb +25 -0
 - data/lib/rbindkeys/device_operator.rb +78 -0
 - data/lib/rbindkeys/fix_resolver.rb +26 -0
 - data/lib/rbindkeys/key_bind.rb +21 -0
 - data/lib/rbindkeys/key_event_handler.rb +243 -0
 - data/lib/rbindkeys/key_event_handler/configurer.rb +142 -0
 - data/lib/rbindkeys/log_utils.rb +51 -0
 - data/lib/rbindkeys/observer.rb +140 -0
 - data/lib/rbindkeys/version.rb +3 -0
 - data/lib/rbindkeys/virtual_device.rb +14 -0
 - data/lib/rbindkeys/window_matcher.rb +35 -0
 - data/rbindkeys.gemspec +26 -0
 - data/sample/emacs.rb +100 -0
 - data/sample/swap_left_ctrl_and_caps.rb +4 -0
 - data/spec/bind_resolver_spec.rb +101 -0
 - data/spec/bind_tree_bind_spec.rb +48 -0
 - data/spec/bind_tree_resolve_for_pressed_event_spec.rb +74 -0
 - data/spec/bind_tree_resolve_for_released_event_spec.rb +63 -0
 - data/spec/cli_spec.rb +81 -0
 - data/spec/device_operator_spec.rb +57 -0
 - data/spec/fix_resolver_spec.rb +57 -0
 - data/spec/key_event_handler/configurer_spec.rb +201 -0
 - data/spec/key_event_handler/handle_spec.rb +222 -0
 - metadata +190 -0
 
    
        data/.gitignore
    ADDED
    
    | 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            *.gem
         
     | 
| 
      
 2 
     | 
    
         
            +
            *.rbc
         
     | 
| 
      
 3 
     | 
    
         
            +
            *.o
         
     | 
| 
      
 4 
     | 
    
         
            +
            *.so
         
     | 
| 
      
 5 
     | 
    
         
            +
            *.dll
         
     | 
| 
      
 6 
     | 
    
         
            +
            *~
         
     | 
| 
      
 7 
     | 
    
         
            +
            .bundle
         
     | 
| 
      
 8 
     | 
    
         
            +
            .config
         
     | 
| 
      
 9 
     | 
    
         
            +
            .yardoc
         
     | 
| 
      
 10 
     | 
    
         
            +
            Gemfile.lock
         
     | 
| 
      
 11 
     | 
    
         
            +
            InstalledFiles
         
     | 
| 
      
 12 
     | 
    
         
            +
            Makefile
         
     | 
| 
      
 13 
     | 
    
         
            +
            _yardoc
         
     | 
| 
      
 14 
     | 
    
         
            +
            core
         
     | 
| 
      
 15 
     | 
    
         
            +
            coverage
         
     | 
| 
      
 16 
     | 
    
         
            +
            doc/
         
     | 
| 
      
 17 
     | 
    
         
            +
            lib/bundler/man
         
     | 
| 
      
 18 
     | 
    
         
            +
            pkg
         
     | 
| 
      
 19 
     | 
    
         
            +
            rdoc
         
     | 
| 
      
 20 
     | 
    
         
            +
            spec/reports
         
     | 
| 
      
 21 
     | 
    
         
            +
            test/tmp
         
     | 
| 
      
 22 
     | 
    
         
            +
            test/version_tmp
         
     | 
| 
      
 23 
     | 
    
         
            +
            tmp
         
     | 
    
        data/Gemfile
    ADDED
    
    
    
        data/LICENSE
    ADDED
    
    | 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Copyright (c) 2012 Keiichiro Ui
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            MIT License
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining
         
     | 
| 
      
 6 
     | 
    
         
            +
            a copy of this software and associated documentation files (the
         
     | 
| 
      
 7 
     | 
    
         
            +
            "Software"), to deal in the Software without restriction, including
         
     | 
| 
      
 8 
     | 
    
         
            +
            without limitation the rights to use, copy, modify, merge, publish,
         
     | 
| 
      
 9 
     | 
    
         
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         
     | 
| 
      
 10 
     | 
    
         
            +
            permit persons to whom the Software is furnished to do so, subject to
         
     | 
| 
      
 11 
     | 
    
         
            +
            the following conditions:
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be
         
     | 
| 
      
 14 
     | 
    
         
            +
            included in all copies or substantial portions of the Software.
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         
     | 
| 
      
 17 
     | 
    
         
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         
     | 
| 
      
 18 
     | 
    
         
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         
     | 
| 
      
 19 
     | 
    
         
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         
     | 
| 
      
 20 
     | 
    
         
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         
     | 
| 
      
 21 
     | 
    
         
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         
     | 
| 
      
 22 
     | 
    
         
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         
     | 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,52 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # rbindkeys
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            a key remapper, which is configurable in ruby, for Linux and X Window System
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ## Installation
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            Add this line to your application's Gemfile:
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            	gem 'rbindkeys'
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            And then execute:
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            	$ bundle
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            Or install it yourself as:
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            	$ gem install rbindkeys
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            ## Usage
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            1. `rbindkeys -e > ~/.rbindkeys.rb`
         
     | 
| 
      
 22 
     | 
    
         
            +
            2. edit `~.rbindkeys.rb`
         
     | 
| 
      
 23 
     | 
    
         
            +
            3. select a keyboard device (see `sudo rbindkeys --evdev-list`)
         
     | 
| 
      
 24 
     | 
    
         
            +
            4. `sudo rbindkeys /dev/input/event2` if you selected "/dev/input/event2"
         
     | 
| 
      
 25 
     | 
    
         
            +
               as a target keyboard
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            ## Contributing
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            1. Fork it
         
     | 
| 
      
 30 
     | 
    
         
            +
            2. Create your feature branch (`git checkout -b my-new-feature`)
         
     | 
| 
      
 31 
     | 
    
         
            +
            3. Commit your changes (`git commit -am 'Added some feature'`)
         
     | 
| 
      
 32 
     | 
    
         
            +
            4. Push to the branch (`git push origin my-new-feature`)
         
     | 
| 
      
 33 
     | 
    
         
            +
            5. Create new Pull Request
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            ## TODO
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            * write documents and publish on rubygem.org
         
     | 
| 
      
 38 
     | 
    
         
            +
            * a daemonize script
         
     | 
| 
      
 39 
     | 
    
         
            +
            * remove @two_storoke and add PrefixBindResolver class
         
     | 
| 
      
 40 
     | 
    
         
            +
            * change BindResolver on input method system
         
     | 
| 
      
 41 
     | 
    
         
            +
            * simplify config file (e.g. `bind_key [:ctrl, :m], :enter`, `bind_key "ctrl+m", "enter"` )
         
     | 
| 
      
 42 
     | 
    
         
            +
            * integrate ibus controller (e.g. `bind_key "alt-grave", "toggle_ibus"` )
         
     | 
| 
      
 43 
     | 
    
         
            +
            * notification when active a prefix key, changing ibus status, etc..
         
     | 
| 
      
 44 
     | 
    
         
            +
            * the LED manipulation does not work for bluetooth devices
         
     | 
| 
      
 45 
     | 
    
         
            +
            * fix bug
         
     | 
| 
      
 46 
     | 
    
         
            +
            	* the enter key cannot be release when `rbindkey` is executed
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            ## Other Configurable Key Remappers For Linux
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            * [x11keymacs](http://yashiromann.sakura.ne.jp/x11keymacs/index-en.html)
         
     | 
| 
      
 51 
     | 
    
         
            +
            * [xfumble](http://endoh-namazu.tierra.ne.jp/xfumble/)
         
     | 
| 
      
 52 
     | 
    
         
            +
            * [私家版 窓使いの憂鬱 Linux & Mac (Darwin) 対応版](http://www42.tok2.com/home/negidakude/)
         
     | 
    
        data/Rakefile
    ADDED
    
    
    
        data/bin/rbindkeys
    ADDED
    
    
    
        data/lib/rbindkeys.rb
    ADDED
    
    | 
         @@ -0,0 +1,38 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # -*- coding:undecided-unix; mode:ruby; -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'rbindkeys/version'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'rbindkeys/log_utils'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            require 'rbindkeys/key_bind'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'rbindkeys/bind_tree'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'rbindkeys/observer'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'rbindkeys/device'
         
     | 
| 
      
 11 
     | 
    
         
            +
            require 'rbindkeys/virtual_device'
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            require 'rbindkeys/device_operator'
         
     | 
| 
      
 14 
     | 
    
         
            +
            require 'rbindkeys/key_event_handler'
         
     | 
| 
      
 15 
     | 
    
         
            +
            require 'rbindkeys/window_matcher'
         
     | 
| 
      
 16 
     | 
    
         
            +
            require 'rbindkeys/bind_resolver'
         
     | 
| 
      
 17 
     | 
    
         
            +
            require 'rbindkeys/fix_resolver'
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            require 'rbindkeys/cli'
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            module Rbindkeys
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              class BindTree; end
         
     | 
| 
      
 24 
     | 
    
         
            +
              class Observer; end
         
     | 
| 
      
 25 
     | 
    
         
            +
              class Devicie; end
         
     | 
| 
      
 26 
     | 
    
         
            +
              class VirtualDevice; end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
              class DeviceOperator; end
         
     | 
| 
      
 29 
     | 
    
         
            +
              class WindowMatcher; end
         
     | 
| 
      
 30 
     | 
    
         
            +
              class KeyEventHandler; end
         
     | 
| 
      
 31 
     | 
    
         
            +
              class BindResolver; end
         
     | 
| 
      
 32 
     | 
    
         
            +
              class FixResolver; end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              class CLI; end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              class DuplicateNodeError < ArgumentError; end
         
     | 
| 
      
 37 
     | 
    
         
            +
              class UnknownKeyValue < Exception; end
         
     | 
| 
      
 38 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,58 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # -*- coding:utf-8; mode:ruby; -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Rbindkeys
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              class BindResolver
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                LOG = LogUtils.get_logger name
         
     | 
| 
      
 8 
     | 
    
         
            +
                DEFAULT_VALUE = :through
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                attr_reader :tree
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                # delegate if cannot resolved
         
     | 
| 
      
 13 
     | 
    
         
            +
                attr_reader :upper_resolver
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                # if this resolver is set by prefix key, then true
         
     | 
| 
      
 16 
     | 
    
         
            +
                # else, false
         
     | 
| 
      
 17 
     | 
    
         
            +
                attr_reader :two_stroke
         
     | 
| 
      
 18 
     | 
    
         
            +
                alias :two_stroke? :two_stroke
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                def initialize upper_resolver=:through, two_stroke=false
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @tree = {}
         
     | 
| 
      
 22 
     | 
    
         
            +
                  if upper_resolver.kind_of? Symbol
         
     | 
| 
      
 23 
     | 
    
         
            +
                    upper_resolver = FixResolver.instance upper_resolver
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @upper_resolver = upper_resolver
         
     | 
| 
      
 26 
     | 
    
         
            +
                  @two_stroke = two_stroke
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def bind input, output
         
     | 
| 
      
 30 
     | 
    
         
            +
                  @tree[input.last] ||= []
         
     | 
| 
      
 31 
     | 
    
         
            +
                  @tree[input.last].each do |b|
         
     | 
| 
      
 32 
     | 
    
         
            +
                    if b.input == input
         
     | 
| 
      
 33 
     | 
    
         
            +
                      raise DuplicateNodeError, "already this input(#{input.inspect}) was binded"
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  kb = KeyBind.new input, output
         
     | 
| 
      
 38 
     | 
    
         
            +
                  @tree[input.last] << kb # TODO implement a bubble insertion
         
     | 
| 
      
 39 
     | 
    
         
            +
                  @tree[input.last].sort!{|a,b| b.input.length <=> a.input.length}
         
     | 
| 
      
 40 
     | 
    
         
            +
                  kb
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                def resolve key_code, key_code_set
         
     | 
| 
      
 44 
     | 
    
         
            +
                  just_resolve(key_code, key_code_set) or
         
     | 
| 
      
 45 
     | 
    
         
            +
                    @upper_resolver.resolve(key_code, key_code_set)
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                def just_resolve key_code, key_code_set
         
     | 
| 
      
 49 
     | 
    
         
            +
                  arr = @tree[key_code]
         
     | 
| 
      
 50 
     | 
    
         
            +
                  arr.each do |kb|
         
     | 
| 
      
 51 
     | 
    
         
            +
                    sub = kb.input - key_code_set
         
     | 
| 
      
 52 
     | 
    
         
            +
                    sub.first == kb.input.last and
         
     | 
| 
      
 53 
     | 
    
         
            +
                      return kb
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end if not arr.nil?
         
     | 
| 
      
 55 
     | 
    
         
            +
                  nil
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
              end
         
     | 
| 
      
 58 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,148 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # -*- coding:utf-8; mode:ruby; -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Rbindkeys
         
     | 
| 
      
 4 
     | 
    
         
            +
              class BindTree
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                DEFAULT_DEFAULT_VALUE = :through
         
     | 
| 
      
 7 
     | 
    
         
            +
                AVAIVABLE_DEFAULT_VALUE = [:through, :ignore]
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                # a tree structure which that nodes are Fixnum(keycode) and
         
     | 
| 
      
 10 
     | 
    
         
            +
                # leaves are Leaf
         
     | 
| 
      
 11 
     | 
    
         
            +
                attr_reader :tree
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                attr_reader :main_tree
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                # active KeyBind
         
     | 
| 
      
 16 
     | 
    
         
            +
                # TODO create KeyEventHandler which exist between Observer and BindTree
         
     | 
| 
      
 17 
     | 
    
         
            +
                # TODO move out @active_key_binds to KeyEventHandler
         
     | 
| 
      
 18 
     | 
    
         
            +
                attr_reader :active_key_binds
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                # a value if no binds hit
         
     | 
| 
      
 21 
     | 
    
         
            +
                attr_reader :default_value
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                def initialize default_value=DEFAULT_DEFAULT_VALUE
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @tree = {}
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @active_key_binds = []
         
     | 
| 
      
 26 
     | 
    
         
            +
                  if AVAIVABLE_DEFAULT_VALUE.include? default_value
         
     | 
| 
      
 27 
     | 
    
         
            +
                    @default_value = default_value
         
     | 
| 
      
 28 
     | 
    
         
            +
                  else
         
     | 
| 
      
 29 
     | 
    
         
            +
                    raise ArgumentError, "expect #{AVAIVABLE_DEFAULT_VALUE.join('/')}"
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                # register an input-output pair
         
     | 
| 
      
 34 
     | 
    
         
            +
                # _input_: Array of (Array of) input keycodes
         
     | 
| 
      
 35 
     | 
    
         
            +
                # _output_: Array of send keycodes or Proc
         
     | 
| 
      
 36 
     | 
    
         
            +
                def bind input, output=nil
         
     | 
| 
      
 37 
     | 
    
         
            +
                  input = input.clone
         
     | 
| 
      
 38 
     | 
    
         
            +
                  new_input = []
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  if input.kind_of? Array and input[0].kind_of? Array
         
     | 
| 
      
 41 
     | 
    
         
            +
                    new_input = input
         
     | 
| 
      
 42 
     | 
    
         
            +
                    input = new_input.shift
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  tail_code = input.pop
         
     | 
| 
      
 46 
     | 
    
         
            +
                  input.sort!
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  subtree = @tree
         
     | 
| 
      
 49 
     | 
    
         
            +
                  input.each do |code|
         
     | 
| 
      
 50 
     | 
    
         
            +
                    if subtree.has_key? code and (not subtree[code].kind_of? Hash)
         
     | 
| 
      
 51 
     | 
    
         
            +
                      raise DuplicateNodeError, "already register an input:#{input}"
         
     | 
| 
      
 52 
     | 
    
         
            +
                    end
         
     | 
| 
      
 53 
     | 
    
         
            +
                    subtree[code] ||= {}
         
     | 
| 
      
 54 
     | 
    
         
            +
                    subtree = subtree[code]
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  if not new_input.empty?
         
     | 
| 
      
 58 
     | 
    
         
            +
                    if subtree.has_key?(tail_code) and
         
     | 
| 
      
 59 
     | 
    
         
            +
                        not (subtree[tail_code].kind_of?(Leaf) and
         
     | 
| 
      
 60 
     | 
    
         
            +
                             subtree[tail_code].payload.kind_of?(BindTree))
         
     | 
| 
      
 61 
     | 
    
         
            +
                      raise DuplicateNodeError, "already register an input:#{input}"
         
     | 
| 
      
 62 
     | 
    
         
            +
                    end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                    if new_input.length == 1
         
     | 
| 
      
 65 
     | 
    
         
            +
                      new_input = new_input.first
         
     | 
| 
      
 66 
     | 
    
         
            +
                    end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                    subtree[tail_code] ||= Leaf.new BindTree.new :ignore
         
     | 
| 
      
 69 
     | 
    
         
            +
                    subtree[tail_code].payload.bind new_input, output
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                  elsif subtree.has_key? tail_code
         
     | 
| 
      
 72 
     | 
    
         
            +
                    raise DuplicateNodeError, "already register an input:#{input}"
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  else
         
     | 
| 
      
 75 
     | 
    
         
            +
                    subtree[tail_code] = Leaf.new KeyBind.new input.push(tail_code), output
         
     | 
| 
      
 76 
     | 
    
         
            +
                  end
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                # called when event.value == 0
         
     | 
| 
      
 80 
     | 
    
         
            +
                def resolve_for_released_event event, pressed_keys
         
     | 
| 
      
 81 
     | 
    
         
            +
                  release_binds = []
         
     | 
| 
      
 82 
     | 
    
         
            +
                  @active_key_binds.reject! do |key_bind|
         
     | 
| 
      
 83 
     | 
    
         
            +
                    if key_bind.input.include? event.code
         
     | 
| 
      
 84 
     | 
    
         
            +
                      release_binds << key_bind
         
     | 
| 
      
 85 
     | 
    
         
            +
                      true
         
     | 
| 
      
 86 
     | 
    
         
            +
                    else
         
     | 
| 
      
 87 
     | 
    
         
            +
                      false
         
     | 
| 
      
 88 
     | 
    
         
            +
                    end
         
     | 
| 
      
 89 
     | 
    
         
            +
                  end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                  if release_binds.empty?
         
     | 
| 
      
 92 
     | 
    
         
            +
                    :through
         
     | 
| 
      
 93 
     | 
    
         
            +
                  else
         
     | 
| 
      
 94 
     | 
    
         
            +
                    release_binds
         
     | 
| 
      
 95 
     | 
    
         
            +
                  end
         
     | 
| 
      
 96 
     | 
    
         
            +
                end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                # called when event.value == 1
         
     | 
| 
      
 99 
     | 
    
         
            +
                def resolve_for_pressed_event event, pressed_keys
         
     | 
| 
      
 100 
     | 
    
         
            +
                  subtree = @tree
         
     | 
| 
      
 101 
     | 
    
         
            +
                  last_code = -1
         
     | 
| 
      
 102 
     | 
    
         
            +
                  pressed_keys.each do |code|
         
     | 
| 
      
 103 
     | 
    
         
            +
                    if last_code >= code
         
     | 
| 
      
 104 
     | 
    
         
            +
                      raise ArgumentError, "expect a sorted Array for 2nd arg (pressed_keys)"
         
     | 
| 
      
 105 
     | 
    
         
            +
                    end
         
     | 
| 
      
 106 
     | 
    
         
            +
                    last_code = code
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                    if subtree.has_key? code
         
     | 
| 
      
 109 
     | 
    
         
            +
                      subtree = subtree[code]
         
     | 
| 
      
 110 
     | 
    
         
            +
                    end
         
     | 
| 
      
 111 
     | 
    
         
            +
                  end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                  subtree = (subtree.kind_of?(Hash) and subtree[event.code])
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                  if not subtree or subtree.kind_of? Hash
         
     | 
| 
      
 116 
     | 
    
         
            +
                    return @default_value
         
     | 
| 
      
 117 
     | 
    
         
            +
                  elsif subtree.kind_of? Leaf
         
     | 
| 
      
 118 
     | 
    
         
            +
                    if subtree.payload.kind_of? KeyBind
         
     | 
| 
      
 119 
     | 
    
         
            +
                      @active_key_binds << subtree.payload
         
     | 
| 
      
 120 
     | 
    
         
            +
                      return subtree.payload
         
     | 
| 
      
 121 
     | 
    
         
            +
                    elsif subtree.payload.kind_of? BindTree
         
     | 
| 
      
 122 
     | 
    
         
            +
                      return subtree.payload
         
     | 
| 
      
 123 
     | 
    
         
            +
                    end
         
     | 
| 
      
 124 
     | 
    
         
            +
                  else
         
     | 
| 
      
 125 
     | 
    
         
            +
                    raise UnexpecedLeafError, "unexpeced Leaf: #{subtree.inspect}"
         
     | 
| 
      
 126 
     | 
    
         
            +
                  end
         
     | 
| 
      
 127 
     | 
    
         
            +
                end
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                # called when event.value == 2
         
     | 
| 
      
 130 
     | 
    
         
            +
                def resolve_for_pressing_event event, pressed_keys
         
     | 
| 
      
 131 
     | 
    
         
            +
                  if @active_key_binds.empty?
         
     | 
| 
      
 132 
     | 
    
         
            +
                    @default_value
         
     | 
| 
      
 133 
     | 
    
         
            +
                  else
         
     | 
| 
      
 134 
     | 
    
         
            +
                    @active_key_binds
         
     | 
| 
      
 135 
     | 
    
         
            +
                  end
         
     | 
| 
      
 136 
     | 
    
         
            +
                end
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                class Leaf
         
     | 
| 
      
 139 
     | 
    
         
            +
                  attr_reader :payload
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                  def initialize payload
         
     | 
| 
      
 142 
     | 
    
         
            +
                    @payload = payload
         
     | 
| 
      
 143 
     | 
    
         
            +
                  end
         
     | 
| 
      
 144 
     | 
    
         
            +
                end
         
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
                class UnexpecedLeafError < RuntimeError; end
         
     | 
| 
      
 147 
     | 
    
         
            +
              end
         
     | 
| 
      
 148 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,103 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # -*- coding:utf-8; mode:ruby; -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Rbindkeys
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              SUMMARY = 'key remapper for Linux which is configured in ruby'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              # a class is executed by bin/rbindkeys
         
     | 
| 
      
 8 
     | 
    
         
            +
              class CLI
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                EVDEVS = '/dev/input/event*'
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 13 
     | 
    
         
            +
                  require 'optparse'
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  # if @@cmd == :observe then CLI excecute to observe a given event device
         
     | 
| 
      
 16 
     | 
    
         
            +
                  # else if @@cmd == :ls then CLI list event devices
         
     | 
| 
      
 17 
     | 
    
         
            +
                  # (default: :observe)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @@cmd = :observe
         
     | 
| 
      
 19 
     | 
    
         
            +
                  def cmd; @@cmd end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  # a location of a config file (default: "~/.rbindkeys.rb")
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @@config = "#{ENV['HOME']}/.rbindkeys.rb"
         
     | 
| 
      
 23 
     | 
    
         
            +
                  def config; @@config end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  @@usage = SUMMARY
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  def main
         
     | 
| 
      
 28 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 29 
     | 
    
         
            +
                      parse_opt
         
     | 
| 
      
 30 
     | 
    
         
            +
                    rescue OptionParser::ParseError => e
         
     | 
| 
      
 31 
     | 
    
         
            +
                      puts "ERROR #{e.to_s}"
         
     | 
| 
      
 32 
     | 
    
         
            +
                      err
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                    method(@@cmd).call
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  def err code=1
         
     | 
| 
      
 39 
     | 
    
         
            +
                    puts @@usage
         
     | 
| 
      
 40 
     | 
    
         
            +
                    exit code
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  def parse_opt
         
     | 
| 
      
 44 
     | 
    
         
            +
                    opt = OptionParser.new <<BANNER
         
     | 
| 
      
 45 
     | 
    
         
            +
            #{SUMMARY}
         
     | 
| 
      
 46 
     | 
    
         
            +
            Usage: sudo #{$0} [--config file] #{EVDEVS}
         
     | 
| 
      
 47 
     | 
    
         
            +
               or: sudo #{$0} --evdev-list
         
     | 
| 
      
 48 
     | 
    
         
            +
            BANNER
         
     | 
| 
      
 49 
     | 
    
         
            +
                    opt.version = VERSION
         
     | 
| 
      
 50 
     | 
    
         
            +
                    opt.on '-l', '--evdev-list', 'a list of event devices' do
         
     | 
| 
      
 51 
     | 
    
         
            +
                      @@cmd = :ls
         
     | 
| 
      
 52 
     | 
    
         
            +
                    end
         
     | 
| 
      
 53 
     | 
    
         
            +
                    opt.on '-c VAL', '--config VAL', 'specifying your configure file' do |v|
         
     | 
| 
      
 54 
     | 
    
         
            +
                      @@config = v
         
     | 
| 
      
 55 
     | 
    
         
            +
                    end
         
     | 
| 
      
 56 
     | 
    
         
            +
                    opt.on '-e', '--print-example', 'print an example config' do |v|
         
     | 
| 
      
 57 
     | 
    
         
            +
                      @@cmd = :print_example
         
     | 
| 
      
 58 
     | 
    
         
            +
                    end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                    opt.parse! ARGV
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                    @@usage = opt.help
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                  def observe
         
     | 
| 
      
 66 
     | 
    
         
            +
                    if ARGV.length != 1
         
     | 
| 
      
 67 
     | 
    
         
            +
                      puts 'ERROR invalid arguments'
         
     | 
| 
      
 68 
     | 
    
         
            +
                      err
         
     | 
| 
      
 69 
     | 
    
         
            +
                    end
         
     | 
| 
      
 70 
     | 
    
         
            +
                    evdev = ARGV.first
         
     | 
| 
      
 71 
     | 
    
         
            +
                    Observer.new(@@config, evdev).start
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  def ls
         
     | 
| 
      
 75 
     | 
    
         
            +
                    require 'revdev'
         
     | 
| 
      
 76 
     | 
    
         
            +
                    Dir::glob(EVDEVS).sort do |a,b|
         
     | 
| 
      
 77 
     | 
    
         
            +
                      am = a.match(/[0-9]+$/)
         
     | 
| 
      
 78 
     | 
    
         
            +
                      bm = b.match(/[0-9]+$/)
         
     | 
| 
      
 79 
     | 
    
         
            +
                      ai = am[0] ? am[0].to_i : 0
         
     | 
| 
      
 80 
     | 
    
         
            +
                      bi = bm[0] ? bm[0].to_i : 0
         
     | 
| 
      
 81 
     | 
    
         
            +
                      ai <=> bi
         
     | 
| 
      
 82 
     | 
    
         
            +
                    end.each do |f|
         
     | 
| 
      
 83 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 84 
     | 
    
         
            +
                        e = Revdev::EventDevice.new f
         
     | 
| 
      
 85 
     | 
    
         
            +
                        puts "#{f}:	#{e.device_name} (#{e.device_id.hr_bustype})"
         
     | 
| 
      
 86 
     | 
    
         
            +
                      rescue => ex
         
     | 
| 
      
 87 
     | 
    
         
            +
                        puts ex
         
     | 
| 
      
 88 
     | 
    
         
            +
                      end
         
     | 
| 
      
 89 
     | 
    
         
            +
                    end
         
     | 
| 
      
 90 
     | 
    
         
            +
                  end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                  def print_example
         
     | 
| 
      
 93 
     | 
    
         
            +
                    dir = File.dirname File.expand_path __FILE__
         
     | 
| 
      
 94 
     | 
    
         
            +
                    dir = File.expand_path File.join dir, '..', '..', 'sample'
         
     | 
| 
      
 95 
     | 
    
         
            +
                    file = File.join dir, 'emacs.rb'
         
     | 
| 
      
 96 
     | 
    
         
            +
                    IO.foreach file do |line|
         
     | 
| 
      
 97 
     | 
    
         
            +
                      puts "# #{line}"
         
     | 
| 
      
 98 
     | 
    
         
            +
                    end
         
     | 
| 
      
 99 
     | 
    
         
            +
                  end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                end
         
     | 
| 
      
 102 
     | 
    
         
            +
              end # of class Runner
         
     | 
| 
      
 103 
     | 
    
         
            +
            end
         
     |