rkremap 0.1.0
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 +7 -0
- data/README.md +90 -0
- data/example/henkan-alt.rb +93 -0
- data/example/keylogger.rb +16 -0
- data/example/mac-shortcut.rb +74 -0
- data/example/tmtms.rb +180 -0
- data/lib/rkremap/keycode.rb +509 -0
- data/lib/rkremap/version.rb +5 -0
- data/lib/rkremap/winattr.rb +95 -0
- data/lib/rkremap.rb +176 -0
- metadata +70 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: 945483dcd11240d5c54b359a15055219532f2f311275633503e7d485aa68917b
         | 
| 4 | 
            +
              data.tar.gz: d594c9b549696f964cde750094169ba7198c0ac9ab5f5dfc59a7936d9610a09d
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: a1412a373a0673172a9eba0449613ab9a76debf400b622977887031c294f8381a58a7c060ef6451e6264703690974aeddb305ce35619c07958a2b5a1239ecf12
         | 
| 7 | 
            +
              data.tar.gz: 619ee1de0814c2542c2a4f347dca7c48e640590a01ff58f2b7362ed80ef447acaf1576df2a2a659eaac95c9a7ec0a8f52d732d8024356613fbef43f055b16dd2
         | 
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,90 @@ | |
| 1 | 
            +
            # Rkremap
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Linux でキー割り当てを変更するプログラムを作るためのライブラリ。
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            ## Installation
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            ```
         | 
| 8 | 
            +
            % gem install rkremap
         | 
| 9 | 
            +
            ```
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            ## Usage
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            ライブラリなのでプログラムを自分で作る必要がある。具体的な使い方は `example/*.rb` を見ればよい。
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            `/dev/input/event*` と `/dev/uinput` に対する権限が必要。`sudo` 等で `root` 権限で動かすのが良いかも。
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            ユーザーを `input` グループに所属させると `/dev/input/event*` を読み取る権限をつけられるけど、そのユーザーはすべての入力デバイスの入力を読み取ることができるようになってしまうので、セキュリティ的にはビミョーなところ。
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            `input` グループでも `/dev/uinput` に権限はないけど、`/etc/udev/rules.d/input.rules` ファイルを
         | 
| 20 | 
            +
            ```
         | 
| 21 | 
            +
            KERNEL=="uinput", GROUP="input"
         | 
| 22 | 
            +
            ```
         | 
| 23 | 
            +
            という内容で作れば `/dev/uinput` のグループを `input` にできるっぽい。
         | 
| 24 | 
            +
             | 
| 25 | 
            +
             | 
| 26 | 
            +
            ### `Rkremap.new`
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            引数に `/dev/input/event*` を指定する。キーボードデバイス以外を指定してもたぶん無意味。
         | 
| 29 | 
            +
            キーボードのデバイスファイル名を調べるには
         | 
| 30 | 
            +
            ```
         | 
| 31 | 
            +
            cat /proc/bus/input/devices
         | 
| 32 | 
            +
            ```
         | 
| 33 | 
            +
            とかすればわかるかもしれない。または
         | 
| 34 | 
            +
            ```
         | 
| 35 | 
            +
            sudo evtest /dev/input/eventX
         | 
| 36 | 
            +
            ```
         | 
| 37 | 
            +
            とかして何かキーを押して出力があればそれ。
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            ThinkPad 本体のキーボードは `/dev/input/event3` だった。
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            ### Rkremap#grab
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            `true` に設定するとキーイベントを奪う。キーイベントを見るだけでいいなら `false` を設定する。
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            ### Rkremap#x11
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            `true` に設定すると X のアプリ名等を取得できる。X 環境下でないなら `false` を設定する。
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            ### Rkremap#start
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            なにかキーを押されたらブロックを実行する。修飾キー単体ではブロックは実行されない。
         | 
| 52 | 
            +
            ブロックの引数はキーコード(`Integer`)と修飾キー(`Hash`)と `Rkremap::App`。
         | 
| 53 | 
            +
            `Rkremap::App#class_name` でアプリのクラス名、`Rkremap::App#title` でアプリのタイトルを取得できる。
         | 
| 54 | 
            +
             | 
| 55 | 
            +
            ### Rkremap#match
         | 
| 56 | 
            +
             | 
| 57 | 
            +
            キーイベントが引数に適合するとブロックを実行する。ブロック引数は Event オブジェクト。
         | 
| 58 | 
            +
            `Event#skip` するとこのイベントはスキップされる。
         | 
| 59 | 
            +
             | 
| 60 | 
            +
            ### Rkremap#key
         | 
| 61 | 
            +
             | 
| 62 | 
            +
            キーを押したことにする。引数はキーコード(`Integer`)と修飾キー(`Hash`)。
         | 
| 63 | 
            +
             | 
| 64 | 
            +
            ### Rkremap#event
         | 
| 65 | 
            +
             | 
| 66 | 
            +
            キーイベントを発生させる。`code` 引数はキーコード(`Integer`)。`type` 引数はイベントタイプ(`Symbol`)で `:press`, `:release`。
         | 
| 67 | 
            +
             | 
| 68 | 
            +
            ### Rkremap#synchronize
         | 
| 69 | 
            +
             | 
| 70 | 
            +
            `start` や `match` のブロックは同時に実行されないようにするため Mutex を使用している。このメソッドで同じ Mutex を用いた排他制御を行う。
         | 
| 71 | 
            +
             | 
| 72 | 
            +
            ### Rkremap::CODE_KEY
         | 
| 73 | 
            +
             | 
| 74 | 
            +
            コードからキー名のシンボルに変換するための Hash。
         | 
| 75 | 
            +
             | 
| 76 | 
            +
            ## 参考
         | 
| 77 | 
            +
             | 
| 78 | 
            +
            * [mooz/xkeysnail: Yet another keyboard remapping tool for X environment](https://github.com/mooz/xkeysnail)
         | 
| 79 | 
            +
              * [xkeysnail - もうひとつの Linux 向けキーリマッパ - Qiita](https://qiita.com/mooz@github/items/c5f25f27847333dd0b37)
         | 
| 80 | 
            +
            * [k0kubun/xremap: Dynamic key remapper for X11 and Wayland](https://github.com/k0kubun/xremap)
         | 
| 81 | 
            +
              * [Linux向けの最強のキーリマッパーを作った - k0kubun's blog](https://k0kubun.hatenablog.com/entry/xkremap)
         | 
| 82 | 
            +
            * [kui/rbindkeys: key remap with ruby](https://github.com/kui/rbindkeys)
         | 
| 83 | 
            +
              * [Ruby で設定できる Linux 環境向けキーリマッパー作った — 電卓片手に](http://k-ui.jp/blog/2012/06/06/rbindkeys-configurable-key-remapper-in-ruby/)
         | 
| 84 | 
            +
            * [Linux の入力デバイスをカスタマイズ - Qiita](https://qiita.com/propella/items/a73fc333c95d14d06835)
         | 
| 85 | 
            +
            * [Linux Input Subsystemの使い方](http://www.tatapa.org/~takuo/input_subsystem/input_subsystem.html)
         | 
| 86 | 
            +
            * [1. Linux Input Subsystem userspace API — The Linux Kernel documentation](https://www.kernel.org/doc/html/v4.12/input/input_uapi.html)
         | 
| 87 | 
            +
             | 
| 88 | 
            +
            ## License
         | 
| 89 | 
            +
             | 
| 90 | 
            +
             MIT license
         | 
| @@ -0,0 +1,93 @@ | |
| 1 | 
            +
            # 変換/無変換キーを0.5秒以上押してるとALTキーとして扱う。
         | 
| 2 | 
            +
            # 0.5秒以内でも変換/無変換キーを押しながら他のキーを押すとALTキーとして扱う。
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require 'rkremap'
         | 
| 5 | 
            +
            include Rkremap::KeyCode
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            rk = Rkremap.new('/dev/input/event3')
         | 
| 8 | 
            +
            rk.grab = true
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            class State
         | 
| 11 | 
            +
              attr_accessor :converted
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              def initialize
         | 
| 14 | 
            +
                @press = nil
         | 
| 15 | 
            +
                @converted = false
         | 
| 16 | 
            +
                @thread = nil
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              def press(thread)
         | 
| 20 | 
            +
                @press = true
         | 
| 21 | 
            +
                @converted = false
         | 
| 22 | 
            +
                @thread = thread
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              def release
         | 
| 26 | 
            +
                @press = false
         | 
| 27 | 
            +
                @converted = false
         | 
| 28 | 
            +
                @thread.kill
         | 
| 29 | 
            +
                @thread = nil
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              def pressed?
         | 
| 33 | 
            +
                @press
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            state = {
         | 
| 38 | 
            +
              KEY_HENKAN => State.new,
         | 
| 39 | 
            +
              KEY_MUHENKAN => State.new,
         | 
| 40 | 
            +
            }
         | 
| 41 | 
            +
             | 
| 42 | 
            +
            MAP = {
         | 
| 43 | 
            +
              KEY_HENKAN => KEY_RIGHTALT,
         | 
| 44 | 
            +
              KEY_MUHENKAN => KEY_LEFTALT,
         | 
| 45 | 
            +
            }
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            rk.match(code: [KEY_HENKAN, KEY_MUHENKAN], type: :press) do |event|
         | 
| 48 | 
            +
              thr = Thread.new(event.code) do |code|
         | 
| 49 | 
            +
                sleep 0.5
         | 
| 50 | 
            +
                rk.synchronize do
         | 
| 51 | 
            +
                  if state[code].pressed?
         | 
| 52 | 
            +
                    rk.event(code: MAP[code], type: :press)
         | 
| 53 | 
            +
                    state[code].converted = true
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
              state[event.code].press(thr)
         | 
| 58 | 
            +
              event.skip
         | 
| 59 | 
            +
            end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            rk.match(code: [KEY_HENKAN, KEY_MUHENKAN], type: :release) do |event|
         | 
| 62 | 
            +
              if state[event.code].converted
         | 
| 63 | 
            +
                rk.event(code: MAP[event.code], type: :release)
         | 
| 64 | 
            +
                event.skip
         | 
| 65 | 
            +
              else
         | 
| 66 | 
            +
                rk.event(code: event.code, type: :press)
         | 
| 67 | 
            +
                rk.event(code: event.code, type: :release)
         | 
| 68 | 
            +
              end
         | 
| 69 | 
            +
              state[event.code].release
         | 
| 70 | 
            +
            end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
            rk.match(code: [KEY_HENKAN, KEY_MUHENKAN], type: :repeat) do |event|
         | 
| 73 | 
            +
              event.skip
         | 
| 74 | 
            +
            end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
            rk.match(type: :press) do
         | 
| 77 | 
            +
              [KEY_HENKAN, KEY_MUHENKAN].each do |code|
         | 
| 78 | 
            +
                if state[code].pressed?
         | 
| 79 | 
            +
                  rk.event(code: MAP[code], type: :press)
         | 
| 80 | 
            +
                  state[code].converted = true
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
              end
         | 
| 83 | 
            +
            end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
            def code2key(code)
         | 
| 86 | 
            +
              Rkremap::CODE_KEY[code].to_s.sub(/\AKEY_/, '')
         | 
| 87 | 
            +
            end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
            rk.start do |code, mod|
         | 
| 90 | 
            +
              key = (mod.select{|_, v| v}.keys + [code]).map{|c| code2key(c)}.join('-')
         | 
| 91 | 
            +
              puts key
         | 
| 92 | 
            +
              rk.key(code, mod)
         | 
| 93 | 
            +
            end
         | 
| @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            # 押されたキーを記録
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'rkremap'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            def code2key(code)
         | 
| 6 | 
            +
              Rkremap::CODE_KEY[code].to_s.sub(/\AKEY_/, '')
         | 
| 7 | 
            +
            end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            rk = Rkremap.new('/dev/input/event3')
         | 
| 10 | 
            +
            rk.grab = false
         | 
| 11 | 
            +
            rk.x11 = true
         | 
| 12 | 
            +
            rk.start do |code, mod, app|
         | 
| 13 | 
            +
              key = (mod.select{|_, v| v}.keys + [code]).map{|c| code2key(c)}.join('-')
         | 
| 14 | 
            +
              key << " at #{app.title} [#{app.class_name}]" if rk.x11
         | 
| 15 | 
            +
              puts key
         | 
| 16 | 
            +
            end
         | 
| @@ -0,0 +1,74 @@ | |
| 1 | 
            +
            # Mac のショートカット風
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'rkremap'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            include Rkremap::KeyCode
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            ctrl_map = {
         | 
| 8 | 
            +
              KEY_A => KEY_HOME,
         | 
| 9 | 
            +
              KEY_E => KEY_END,
         | 
| 10 | 
            +
              KEY_B => KEY_LEFT,
         | 
| 11 | 
            +
              KEY_F => KEY_RIGHT,
         | 
| 12 | 
            +
              KEY_N => KEY_DOWN,
         | 
| 13 | 
            +
              KEY_P => KEY_UP,
         | 
| 14 | 
            +
              KEY_D => KEY_DELETE,
         | 
| 15 | 
            +
              KEY_H => KEY_BACKSPACE,
         | 
| 16 | 
            +
              KEY_I => KEY_TAB,
         | 
| 17 | 
            +
            }
         | 
| 18 | 
            +
            mod_disable_ctrl = {
         | 
| 19 | 
            +
              KEY_LEFTCTRL => false,
         | 
| 20 | 
            +
              KEY_RIGHTCTRL => false,
         | 
| 21 | 
            +
            }
         | 
| 22 | 
            +
            mod_disable_shift = {
         | 
| 23 | 
            +
              KEY_LEFTSHIFT => false,
         | 
| 24 | 
            +
              KEY_RIGHTSHIFT => false,
         | 
| 25 | 
            +
            }
         | 
| 26 | 
            +
            mod_disable_alt = {
         | 
| 27 | 
            +
              KEY_LEFTALT => false,
         | 
| 28 | 
            +
              KEY_RIGHTALT => false,
         | 
| 29 | 
            +
            }
         | 
| 30 | 
            +
            mod_disable_meta = {
         | 
| 31 | 
            +
              KEY_LEFTMETA => false,
         | 
| 32 | 
            +
              KEY_RIGHTMETA => false,
         | 
| 33 | 
            +
            }
         | 
| 34 | 
            +
            mod_disable_all = {}.merge(mod_disable_ctrl, mod_disable_shift, mod_disable_alt, mod_disable_meta)
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            rk = Rkremap.new("/dev/input/event3")
         | 
| 37 | 
            +
            rk.grab = true
         | 
| 38 | 
            +
            rk.x11 = true
         | 
| 39 | 
            +
            rk.start do |code, mod, app|
         | 
| 40 | 
            +
              # Emacs や端末等ではそのまま
         | 
| 41 | 
            +
              if app.class_name == 'Emacs' || app.class_name =~ /terminal/i || app.class_name == 'VirtualBox Machine'
         | 
| 42 | 
            +
                rk.key(code, mod)
         | 
| 43 | 
            +
                next
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              # ALT+[A-Z]/Enter を Ctrl+[A-Z]/Enter に変換
         | 
| 47 | 
            +
              if (mod[KEY_LEFTALT] || mod[KEY_RIGHTALT]) && (Rkremap::CODE_KEY[code] =~ /\AKEY_[A-Z]\z/ || code == KEY_ENTER)
         | 
| 48 | 
            +
                mod.merge!(mod_disable_alt, {KEY_LEFTCTRL => true})
         | 
| 49 | 
            +
                mod[KEY_LEFTCTRL] = true
         | 
| 50 | 
            +
                rk.key(code, mod)
         | 
| 51 | 
            +
                next
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              # Ctrl は他のキーに変換
         | 
| 55 | 
            +
              if mod[KEY_LEFTCTRL] || mod[KEY_RIGHTCTRL]
         | 
| 56 | 
            +
                # Ctrl+K は行末まで削除
         | 
| 57 | 
            +
                if code == KEY_K
         | 
| 58 | 
            +
                  rk.key(KEY_END, mod_disable_all.merge({KEY_LEFTSHIFT => true}))
         | 
| 59 | 
            +
                  rk.key(KEY_X, mod_disable_all.merge({KEY_LEFTCTRL => true}))
         | 
| 60 | 
            +
                  next
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
                # 単純な変換
         | 
| 63 | 
            +
                if ctrl_map[code]
         | 
| 64 | 
            +
                  rk.key(ctrl_map[code], mod_disable_ctrl)
         | 
| 65 | 
            +
                  next
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
                # その他の Ctrl+[A-Z] は無視
         | 
| 68 | 
            +
                if Rkremap::CODE_KEY[code] =~ /\AKEY_[A-Z]\z/
         | 
| 69 | 
            +
                  next
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
              rk.key(code, mod)
         | 
| 74 | 
            +
            end
         | 
    
        data/example/tmtms.rb
    ADDED
    
    | @@ -0,0 +1,180 @@ | |
| 1 | 
            +
            # tmtms 用
         | 
| 2 | 
            +
            #
         | 
| 3 | 
            +
            # fcitx が有効な場合に /tmp/fcitx-enabled ファイルを作るスクリプトを動かしておく:
         | 
| 4 | 
            +
            #     while :; do
         | 
| 5 | 
            +
            #       if [ $(fcitx-remote) -eq 2 ]; then
         | 
| 6 | 
            +
            #         touch /tmp/fcitx-enabled
         | 
| 7 | 
            +
            #       else
         | 
| 8 | 
            +
            #         rm -f /tmp/fcitx-enabled
         | 
| 9 | 
            +
            #       fi
         | 
| 10 | 
            +
            #       sleep 0.1
         | 
| 11 | 
            +
            #     done
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            require 'rkremap'
         | 
| 14 | 
            +
            include Rkremap::KeyCode
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            class State
         | 
| 17 | 
            +
              attr_accessor :converted
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              def initialize
         | 
| 20 | 
            +
                @press = nil
         | 
| 21 | 
            +
                @converted = false
         | 
| 22 | 
            +
                @thread = nil
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              def press(thread)
         | 
| 26 | 
            +
                @press = true
         | 
| 27 | 
            +
                @converted = false
         | 
| 28 | 
            +
                @thread = thread
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              def release
         | 
| 32 | 
            +
                @press = false
         | 
| 33 | 
            +
                @converted = false
         | 
| 34 | 
            +
                @thread.kill
         | 
| 35 | 
            +
                @thread = nil
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              def pressed?
         | 
| 39 | 
            +
                @press
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
            end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            rk = Rkremap.new("/dev/input/event3")
         | 
| 44 | 
            +
            rk.grab = true
         | 
| 45 | 
            +
            rk.x11 = true
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            # 変換/無変換キーを0.5秒以上押してるとALTキーとして扱う。
         | 
| 48 | 
            +
            # 0.5秒以内でも変換/無変換キーを押しながら他のキーを押すとALTキーとして扱う。
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            state = {
         | 
| 51 | 
            +
              KEY_HENKAN => State.new,
         | 
| 52 | 
            +
              KEY_MUHENKAN => State.new,
         | 
| 53 | 
            +
            }
         | 
| 54 | 
            +
             | 
| 55 | 
            +
            henkan_map = {
         | 
| 56 | 
            +
              KEY_HENKAN => KEY_RIGHTALT,
         | 
| 57 | 
            +
              KEY_MUHENKAN => KEY_LEFTALT,
         | 
| 58 | 
            +
            }
         | 
| 59 | 
            +
             | 
| 60 | 
            +
            rk.match(code: [KEY_HENKAN, KEY_MUHENKAN], type: :press) do |event|
         | 
| 61 | 
            +
              thr = Thread.new(event.code) do |code|
         | 
| 62 | 
            +
                sleep 0.5
         | 
| 63 | 
            +
                rk.synchronize do
         | 
| 64 | 
            +
                  if state[code].pressed?
         | 
| 65 | 
            +
                    rk.event(code: henkan_map[code], type: :press)
         | 
| 66 | 
            +
                    state[code].converted = true
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
              state[event.code].press(thr)
         | 
| 71 | 
            +
              event.skip
         | 
| 72 | 
            +
            end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
            rk.match(code: [KEY_HENKAN, KEY_MUHENKAN], type: :release) do |event|
         | 
| 75 | 
            +
              if state[event.code].converted
         | 
| 76 | 
            +
                rk.event(code: henkan_map[event.code], type: :release)
         | 
| 77 | 
            +
                event.skip
         | 
| 78 | 
            +
              else
         | 
| 79 | 
            +
                rk.event(code: event.code, type: :press)
         | 
| 80 | 
            +
                rk.event(code: event.code, type: :release)
         | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
              state[event.code].release
         | 
| 83 | 
            +
            end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
            rk.match(code: [KEY_HENKAN, KEY_MUHENKAN], type: :repeat) do |event|
         | 
| 86 | 
            +
              event.skip
         | 
| 87 | 
            +
            end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
            rk.match(type: :press) do
         | 
| 90 | 
            +
              [KEY_HENKAN, KEY_MUHENKAN].each do |code|
         | 
| 91 | 
            +
                if state[code].pressed?
         | 
| 92 | 
            +
                  rk.event(code: henkan_map[code], type: :press)
         | 
| 93 | 
            +
                  state[code].converted = true
         | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
              end
         | 
| 96 | 
            +
            end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
            # CAPSLOCK は CTRL に変換
         | 
| 99 | 
            +
            rk.match(code: KEY_CAPSLOCK) do |event|
         | 
| 100 | 
            +
              rk.event(code: KEY_LEFTCTRL, type: event.type)
         | 
| 101 | 
            +
              event.skip
         | 
| 102 | 
            +
            end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
            ctrl_map = {
         | 
| 105 | 
            +
              KEY_A => KEY_HOME,
         | 
| 106 | 
            +
              KEY_E => KEY_END,
         | 
| 107 | 
            +
              KEY_B => KEY_LEFT,
         | 
| 108 | 
            +
              KEY_F => KEY_RIGHT,
         | 
| 109 | 
            +
              KEY_N => KEY_DOWN,
         | 
| 110 | 
            +
              KEY_P => KEY_UP,
         | 
| 111 | 
            +
              KEY_D => KEY_DELETE,
         | 
| 112 | 
            +
              KEY_H => KEY_BACKSPACE,
         | 
| 113 | 
            +
              KEY_I => KEY_TAB,
         | 
| 114 | 
            +
            }
         | 
| 115 | 
            +
            mod_disable_ctrl = {
         | 
| 116 | 
            +
              KEY_LEFTCTRL => false,
         | 
| 117 | 
            +
              KEY_RIGHTCTRL => false,
         | 
| 118 | 
            +
            }
         | 
| 119 | 
            +
            mod_disable_shift = {
         | 
| 120 | 
            +
              KEY_LEFTSHIFT => false,
         | 
| 121 | 
            +
              KEY_RIGHTSHIFT => false,
         | 
| 122 | 
            +
            }
         | 
| 123 | 
            +
            mod_disable_alt = {
         | 
| 124 | 
            +
              KEY_LEFTALT => false,
         | 
| 125 | 
            +
              KEY_RIGHTALT => false,
         | 
| 126 | 
            +
            }
         | 
| 127 | 
            +
            mod_disable_meta = {
         | 
| 128 | 
            +
              KEY_LEFTMETA => false,
         | 
| 129 | 
            +
              KEY_RIGHTMETA => false,
         | 
| 130 | 
            +
            }
         | 
| 131 | 
            +
            mod_disable_all = {}.merge(mod_disable_ctrl, mod_disable_shift, mod_disable_alt, mod_disable_meta)
         | 
| 132 | 
            +
             | 
| 133 | 
            +
            key_map = {
         | 
| 134 | 
            +
              KEY_YEN => KEY_BACKSLASH,
         | 
| 135 | 
            +
              KEY_BACKSLASH => KEY_GRAVE,
         | 
| 136 | 
            +
              KEY_GRAVE => KEY_ESC,
         | 
| 137 | 
            +
            }
         | 
| 138 | 
            +
             | 
| 139 | 
            +
            rk.start do |code, mod, app|
         | 
| 140 | 
            +
              # JISキーボードを英語配列にしたときに一部キーを変える
         | 
| 141 | 
            +
              code = key_map[code] || code
         | 
| 142 | 
            +
              if code == KEY_RO
         | 
| 143 | 
            +
                code = mod[KEY_LEFTSHIFT] || mod[KEY_RIGHTSHIFT] ? KEY_MINUS : KEY_BACKSLASH
         | 
| 144 | 
            +
              end
         | 
| 145 | 
            +
             | 
| 146 | 
            +
              # Emacs や端末等ではそのまま
         | 
| 147 | 
            +
              if app.class_name == 'Emacs' || app.class_name =~ /terminal/i || app.class_name == 'VirtualBox Machine'
         | 
| 148 | 
            +
                rk.key(code, mod)
         | 
| 149 | 
            +
                next
         | 
| 150 | 
            +
              end
         | 
| 151 | 
            +
             | 
| 152 | 
            +
              # ALT+[A-Z]/Enter を Ctrl+[A-Z]/Enter に変換
         | 
| 153 | 
            +
              if (mod[KEY_LEFTALT] || mod[KEY_RIGHTALT]) && (Rkremap::CODE_KEY[code] =~ /\AKEY_[A-Z]\z/ || code == KEY_ENTER)
         | 
| 154 | 
            +
                mod.merge!(mod_disable_alt, {KEY_LEFTCTRL => true})
         | 
| 155 | 
            +
                mod[KEY_LEFTCTRL] = true
         | 
| 156 | 
            +
                rk.key(code, mod)
         | 
| 157 | 
            +
                next
         | 
| 158 | 
            +
              end
         | 
| 159 | 
            +
             | 
| 160 | 
            +
              # Ctrl は他のキーに変換
         | 
| 161 | 
            +
              if mod[KEY_LEFTCTRL] || mod[KEY_RIGHTCTRL]
         | 
| 162 | 
            +
                # Ctrl+K は行末まで削除 (日本語変換時はそのまま)
         | 
| 163 | 
            +
                if code == KEY_K && !File.exist?('/tmp/fcitx-enabled')
         | 
| 164 | 
            +
                  rk.key(KEY_END, mod_disable_all.merge({KEY_LEFTSHIFT => true}))
         | 
| 165 | 
            +
                  rk.key(KEY_X, mod_disable_all.merge({KEY_LEFTCTRL => true}))
         | 
| 166 | 
            +
                  next
         | 
| 167 | 
            +
                end
         | 
| 168 | 
            +
                # 単純な変換
         | 
| 169 | 
            +
                if ctrl_map[code]
         | 
| 170 | 
            +
                  rk.key(ctrl_map[code], mod_disable_ctrl)
         | 
| 171 | 
            +
                  next
         | 
| 172 | 
            +
                end
         | 
| 173 | 
            +
                # その他の Ctrl+[A-Z] は無視
         | 
| 174 | 
            +
                if Rkremap::CODE_KEY[code] =~ /\AKEY_[A-Z]\z/
         | 
| 175 | 
            +
                  next
         | 
| 176 | 
            +
                end
         | 
| 177 | 
            +
              end
         | 
| 178 | 
            +
             | 
| 179 | 
            +
              rk.key(code, mod)
         | 
| 180 | 
            +
            end
         | 
| @@ -0,0 +1,509 @@ | |
| 1 | 
            +
            class Rkremap
         | 
| 2 | 
            +
              module KeyCode
         | 
| 3 | 
            +
                # generated from /usr/include/linux/input-event-codes.h
         | 
| 4 | 
            +
                KEY_RESERVED                 = 0
         | 
| 5 | 
            +
                KEY_ESC                      = 1
         | 
| 6 | 
            +
                KEY_1                        = 2
         | 
| 7 | 
            +
                KEY_2                        = 3
         | 
| 8 | 
            +
                KEY_3                        = 4
         | 
| 9 | 
            +
                KEY_4                        = 5
         | 
| 10 | 
            +
                KEY_5                        = 6
         | 
| 11 | 
            +
                KEY_6                        = 7
         | 
| 12 | 
            +
                KEY_7                        = 8
         | 
| 13 | 
            +
                KEY_8                        = 9
         | 
| 14 | 
            +
                KEY_9                        = 10
         | 
| 15 | 
            +
                KEY_0                        = 11
         | 
| 16 | 
            +
                KEY_MINUS                    = 12
         | 
| 17 | 
            +
                KEY_EQUAL                    = 13
         | 
| 18 | 
            +
                KEY_BACKSPACE                = 14
         | 
| 19 | 
            +
                KEY_TAB                      = 15
         | 
| 20 | 
            +
                KEY_Q                        = 16
         | 
| 21 | 
            +
                KEY_W                        = 17
         | 
| 22 | 
            +
                KEY_E                        = 18
         | 
| 23 | 
            +
                KEY_R                        = 19
         | 
| 24 | 
            +
                KEY_T                        = 20
         | 
| 25 | 
            +
                KEY_Y                        = 21
         | 
| 26 | 
            +
                KEY_U                        = 22
         | 
| 27 | 
            +
                KEY_I                        = 23
         | 
| 28 | 
            +
                KEY_O                        = 24
         | 
| 29 | 
            +
                KEY_P                        = 25
         | 
| 30 | 
            +
                KEY_LEFTBRACE                = 26
         | 
| 31 | 
            +
                KEY_RIGHTBRACE               = 27
         | 
| 32 | 
            +
                KEY_ENTER                    = 28
         | 
| 33 | 
            +
                KEY_LEFTCTRL                 = 29
         | 
| 34 | 
            +
                KEY_A                        = 30
         | 
| 35 | 
            +
                KEY_S                        = 31
         | 
| 36 | 
            +
                KEY_D                        = 32
         | 
| 37 | 
            +
                KEY_F                        = 33
         | 
| 38 | 
            +
                KEY_G                        = 34
         | 
| 39 | 
            +
                KEY_H                        = 35
         | 
| 40 | 
            +
                KEY_J                        = 36
         | 
| 41 | 
            +
                KEY_K                        = 37
         | 
| 42 | 
            +
                KEY_L                        = 38
         | 
| 43 | 
            +
                KEY_SEMICOLON                = 39
         | 
| 44 | 
            +
                KEY_APOSTROPHE               = 40
         | 
| 45 | 
            +
                KEY_GRAVE                    = 41
         | 
| 46 | 
            +
                KEY_LEFTSHIFT                = 42
         | 
| 47 | 
            +
                KEY_BACKSLASH                = 43
         | 
| 48 | 
            +
                KEY_Z                        = 44
         | 
| 49 | 
            +
                KEY_X                        = 45
         | 
| 50 | 
            +
                KEY_C                        = 46
         | 
| 51 | 
            +
                KEY_V                        = 47
         | 
| 52 | 
            +
                KEY_B                        = 48
         | 
| 53 | 
            +
                KEY_N                        = 49
         | 
| 54 | 
            +
                KEY_M                        = 50
         | 
| 55 | 
            +
                KEY_COMMA                    = 51
         | 
| 56 | 
            +
                KEY_DOT                      = 52
         | 
| 57 | 
            +
                KEY_SLASH                    = 53
         | 
| 58 | 
            +
                KEY_RIGHTSHIFT               = 54
         | 
| 59 | 
            +
                KEY_KPASTERISK               = 55
         | 
| 60 | 
            +
                KEY_LEFTALT                  = 56
         | 
| 61 | 
            +
                KEY_SPACE                    = 57
         | 
| 62 | 
            +
                KEY_CAPSLOCK                 = 58
         | 
| 63 | 
            +
                KEY_F1                       = 59
         | 
| 64 | 
            +
                KEY_F2                       = 60
         | 
| 65 | 
            +
                KEY_F3                       = 61
         | 
| 66 | 
            +
                KEY_F4                       = 62
         | 
| 67 | 
            +
                KEY_F5                       = 63
         | 
| 68 | 
            +
                KEY_F6                       = 64
         | 
| 69 | 
            +
                KEY_F7                       = 65
         | 
| 70 | 
            +
                KEY_F8                       = 66
         | 
| 71 | 
            +
                KEY_F9                       = 67
         | 
| 72 | 
            +
                KEY_F10                      = 68
         | 
| 73 | 
            +
                KEY_NUMLOCK                  = 69
         | 
| 74 | 
            +
                KEY_SCROLLLOCK               = 70
         | 
| 75 | 
            +
                KEY_KP7                      = 71
         | 
| 76 | 
            +
                KEY_KP8                      = 72
         | 
| 77 | 
            +
                KEY_KP9                      = 73
         | 
| 78 | 
            +
                KEY_KPMINUS                  = 74
         | 
| 79 | 
            +
                KEY_KP4                      = 75
         | 
| 80 | 
            +
                KEY_KP5                      = 76
         | 
| 81 | 
            +
                KEY_KP6                      = 77
         | 
| 82 | 
            +
                KEY_KPPLUS                   = 78
         | 
| 83 | 
            +
                KEY_KP1                      = 79
         | 
| 84 | 
            +
                KEY_KP2                      = 80
         | 
| 85 | 
            +
                KEY_KP3                      = 81
         | 
| 86 | 
            +
                KEY_KP0                      = 82
         | 
| 87 | 
            +
                KEY_KPDOT                    = 83
         | 
| 88 | 
            +
                KEY_ZENKAKUHANKAKU           = 85
         | 
| 89 | 
            +
                KEY_102ND                    = 86
         | 
| 90 | 
            +
                KEY_F11                      = 87
         | 
| 91 | 
            +
                KEY_F12                      = 88
         | 
| 92 | 
            +
                KEY_RO                       = 89
         | 
| 93 | 
            +
                KEY_KATAKANA                 = 90
         | 
| 94 | 
            +
                KEY_HIRAGANA                 = 91
         | 
| 95 | 
            +
                KEY_HENKAN                   = 92
         | 
| 96 | 
            +
                KEY_KATAKANAHIRAGANA         = 93
         | 
| 97 | 
            +
                KEY_MUHENKAN                 = 94
         | 
| 98 | 
            +
                KEY_KPJPCOMMA                = 95
         | 
| 99 | 
            +
                KEY_KPENTER                  = 96
         | 
| 100 | 
            +
                KEY_RIGHTCTRL                = 97
         | 
| 101 | 
            +
                KEY_KPSLASH                  = 98
         | 
| 102 | 
            +
                KEY_SYSRQ                    = 99
         | 
| 103 | 
            +
                KEY_RIGHTALT                 = 100
         | 
| 104 | 
            +
                KEY_LINEFEED                 = 101
         | 
| 105 | 
            +
                KEY_HOME                     = 102
         | 
| 106 | 
            +
                KEY_UP                       = 103
         | 
| 107 | 
            +
                KEY_PAGEUP                   = 104
         | 
| 108 | 
            +
                KEY_LEFT                     = 105
         | 
| 109 | 
            +
                KEY_RIGHT                    = 106
         | 
| 110 | 
            +
                KEY_END                      = 107
         | 
| 111 | 
            +
                KEY_DOWN                     = 108
         | 
| 112 | 
            +
                KEY_PAGEDOWN                 = 109
         | 
| 113 | 
            +
                KEY_INSERT                   = 110
         | 
| 114 | 
            +
                KEY_DELETE                   = 111
         | 
| 115 | 
            +
                KEY_MACRO                    = 112
         | 
| 116 | 
            +
                KEY_MUTE                     = 113
         | 
| 117 | 
            +
                KEY_VOLUMEDOWN               = 114
         | 
| 118 | 
            +
                KEY_VOLUMEUP                 = 115
         | 
| 119 | 
            +
                KEY_POWER                    = 116 # SC System Power Down
         | 
| 120 | 
            +
                KEY_KPEQUAL                  = 117
         | 
| 121 | 
            +
                KEY_KPPLUSMINUS              = 118
         | 
| 122 | 
            +
                KEY_PAUSE                    = 119
         | 
| 123 | 
            +
                KEY_SCALE                    = 120 # AL Compiz Scale (Expose)
         | 
| 124 | 
            +
                KEY_KPCOMMA                  = 121
         | 
| 125 | 
            +
                KEY_HANGEUL                  = 122
         | 
| 126 | 
            +
                KEY_HANGUEL                  = KEY_HANGEUL
         | 
| 127 | 
            +
                KEY_HANJA                    = 123
         | 
| 128 | 
            +
                KEY_YEN                      = 124
         | 
| 129 | 
            +
                KEY_LEFTMETA                 = 125
         | 
| 130 | 
            +
                KEY_RIGHTMETA                = 126
         | 
| 131 | 
            +
                KEY_COMPOSE                  = 127
         | 
| 132 | 
            +
                KEY_STOP                     = 128 # AC Stop
         | 
| 133 | 
            +
                KEY_AGAIN                    = 129
         | 
| 134 | 
            +
                KEY_PROPS                    = 130 # AC Properties
         | 
| 135 | 
            +
                KEY_UNDO                     = 131 # AC Undo
         | 
| 136 | 
            +
                KEY_FRONT                    = 132
         | 
| 137 | 
            +
                KEY_COPY                     = 133 # AC Copy
         | 
| 138 | 
            +
                KEY_OPEN                     = 134 # AC Open
         | 
| 139 | 
            +
                KEY_PASTE                    = 135 # AC Paste
         | 
| 140 | 
            +
                KEY_FIND                     = 136 # AC Search
         | 
| 141 | 
            +
                KEY_CUT                      = 137 # AC Cut
         | 
| 142 | 
            +
                KEY_HELP                     = 138 # AL Integrated Help Center
         | 
| 143 | 
            +
                KEY_MENU                     = 139 # Menu (show menu)
         | 
| 144 | 
            +
                KEY_CALC                     = 140 # AL Calculator
         | 
| 145 | 
            +
                KEY_SETUP                    = 141
         | 
| 146 | 
            +
                KEY_SLEEP                    = 142 # SC System Sleep
         | 
| 147 | 
            +
                KEY_WAKEUP                   = 143 # System Wake Up
         | 
| 148 | 
            +
                KEY_FILE                     = 144 # AL Local Machine Browser
         | 
| 149 | 
            +
                KEY_SENDFILE                 = 145
         | 
| 150 | 
            +
                KEY_DELETEFILE               = 146
         | 
| 151 | 
            +
                KEY_XFER                     = 147
         | 
| 152 | 
            +
                KEY_PROG1                    = 148
         | 
| 153 | 
            +
                KEY_PROG2                    = 149
         | 
| 154 | 
            +
                KEY_WWW                      = 150 # AL Internet Browser
         | 
| 155 | 
            +
                KEY_MSDOS                    = 151
         | 
| 156 | 
            +
                KEY_COFFEE                   = 152 # AL Terminal Lock/Screensaver
         | 
| 157 | 
            +
                KEY_SCREENLOCK               = KEY_COFFEE
         | 
| 158 | 
            +
                KEY_ROTATE_DISPLAY           = 153 # Display orientation for e.g. tablets
         | 
| 159 | 
            +
                KEY_DIRECTION                = KEY_ROTATE_DISPLAY
         | 
| 160 | 
            +
                KEY_CYCLEWINDOWS             = 154
         | 
| 161 | 
            +
                KEY_MAIL                     = 155
         | 
| 162 | 
            +
                KEY_BOOKMARKS                = 156 # AC Bookmarks
         | 
| 163 | 
            +
                KEY_COMPUTER                 = 157
         | 
| 164 | 
            +
                KEY_BACK                     = 158 # AC Back
         | 
| 165 | 
            +
                KEY_FORWARD                  = 159 # AC Forward
         | 
| 166 | 
            +
                KEY_CLOSECD                  = 160
         | 
| 167 | 
            +
                KEY_EJECTCD                  = 161
         | 
| 168 | 
            +
                KEY_EJECTCLOSECD             = 162
         | 
| 169 | 
            +
                KEY_NEXTSONG                 = 163
         | 
| 170 | 
            +
                KEY_PLAYPAUSE                = 164
         | 
| 171 | 
            +
                KEY_PREVIOUSSONG             = 165
         | 
| 172 | 
            +
                KEY_STOPCD                   = 166
         | 
| 173 | 
            +
                KEY_RECORD                   = 167
         | 
| 174 | 
            +
                KEY_REWIND                   = 168
         | 
| 175 | 
            +
                KEY_PHONE                    = 169 # Media Select Telephone
         | 
| 176 | 
            +
                KEY_ISO                      = 170
         | 
| 177 | 
            +
                KEY_CONFIG                   = 171 # AL Consumer Control Configuration
         | 
| 178 | 
            +
                KEY_HOMEPAGE                 = 172 # AC Home
         | 
| 179 | 
            +
                KEY_REFRESH                  = 173 # AC Refresh
         | 
| 180 | 
            +
                KEY_EXIT                     = 174 # AC Exit
         | 
| 181 | 
            +
                KEY_MOVE                     = 175
         | 
| 182 | 
            +
                KEY_EDIT                     = 176
         | 
| 183 | 
            +
                KEY_SCROLLUP                 = 177
         | 
| 184 | 
            +
                KEY_SCROLLDOWN               = 178
         | 
| 185 | 
            +
                KEY_KPLEFTPAREN              = 179
         | 
| 186 | 
            +
                KEY_KPRIGHTPAREN             = 180
         | 
| 187 | 
            +
                KEY_NEW                      = 181 # AC New
         | 
| 188 | 
            +
                KEY_REDO                     = 182 # AC Redo/Repeat
         | 
| 189 | 
            +
                KEY_F13                      = 183
         | 
| 190 | 
            +
                KEY_F14                      = 184
         | 
| 191 | 
            +
                KEY_F15                      = 185
         | 
| 192 | 
            +
                KEY_F16                      = 186
         | 
| 193 | 
            +
                KEY_F17                      = 187
         | 
| 194 | 
            +
                KEY_F18                      = 188
         | 
| 195 | 
            +
                KEY_F19                      = 189
         | 
| 196 | 
            +
                KEY_F20                      = 190
         | 
| 197 | 
            +
                KEY_F21                      = 191
         | 
| 198 | 
            +
                KEY_F22                      = 192
         | 
| 199 | 
            +
                KEY_F23                      = 193
         | 
| 200 | 
            +
                KEY_F24                      = 194
         | 
| 201 | 
            +
                KEY_PLAYCD                   = 200
         | 
| 202 | 
            +
                KEY_PAUSECD                  = 201
         | 
| 203 | 
            +
                KEY_PROG3                    = 202
         | 
| 204 | 
            +
                KEY_PROG4                    = 203
         | 
| 205 | 
            +
                KEY_DASHBOARD                = 204 # AL Dashboard
         | 
| 206 | 
            +
                KEY_SUSPEND                  = 205
         | 
| 207 | 
            +
                KEY_CLOSE                    = 206 # AC Close
         | 
| 208 | 
            +
                KEY_PLAY                     = 207
         | 
| 209 | 
            +
                KEY_FASTFORWARD              = 208
         | 
| 210 | 
            +
                KEY_BASSBOOST                = 209
         | 
| 211 | 
            +
                KEY_PRINT                    = 210 # AC Print
         | 
| 212 | 
            +
                KEY_HP                       = 211
         | 
| 213 | 
            +
                KEY_CAMERA                   = 212
         | 
| 214 | 
            +
                KEY_SOUND                    = 213
         | 
| 215 | 
            +
                KEY_QUESTION                 = 214
         | 
| 216 | 
            +
                KEY_EMAIL                    = 215
         | 
| 217 | 
            +
                KEY_CHAT                     = 216
         | 
| 218 | 
            +
                KEY_SEARCH                   = 217
         | 
| 219 | 
            +
                KEY_CONNECT                  = 218
         | 
| 220 | 
            +
                KEY_FINANCE                  = 219 # AL Checkbook/Finance
         | 
| 221 | 
            +
                KEY_SPORT                    = 220
         | 
| 222 | 
            +
                KEY_SHOP                     = 221
         | 
| 223 | 
            +
                KEY_ALTERASE                 = 222
         | 
| 224 | 
            +
                KEY_CANCEL                   = 223 # AC Cancel
         | 
| 225 | 
            +
                KEY_BRIGHTNESSDOWN           = 224
         | 
| 226 | 
            +
                KEY_BRIGHTNESSUP             = 225
         | 
| 227 | 
            +
                KEY_MEDIA                    = 226
         | 
| 228 | 
            +
                KEY_SWITCHVIDEOMODE          = 227 # Cycle between available video
         | 
| 229 | 
            +
                KEY_KBDILLUMTOGGLE           = 228
         | 
| 230 | 
            +
                KEY_KBDILLUMDOWN             = 229
         | 
| 231 | 
            +
                KEY_KBDILLUMUP               = 230
         | 
| 232 | 
            +
                KEY_SEND                     = 231 # AC Send
         | 
| 233 | 
            +
                KEY_REPLY                    = 232 # AC Reply
         | 
| 234 | 
            +
                KEY_FORWARDMAIL              = 233 # AC Forward Msg
         | 
| 235 | 
            +
                KEY_SAVE                     = 234 # AC Save
         | 
| 236 | 
            +
                KEY_DOCUMENTS                = 235
         | 
| 237 | 
            +
                KEY_BATTERY                  = 236
         | 
| 238 | 
            +
                KEY_BLUETOOTH                = 237
         | 
| 239 | 
            +
                KEY_WLAN                     = 238
         | 
| 240 | 
            +
                KEY_UWB                      = 239
         | 
| 241 | 
            +
                KEY_UNKNOWN                  = 240
         | 
| 242 | 
            +
                KEY_VIDEO_NEXT               = 241 # drive next video source
         | 
| 243 | 
            +
                KEY_VIDEO_PREV               = 242 # drive previous video source
         | 
| 244 | 
            +
                KEY_BRIGHTNESS_CYCLE         = 243 # brightness up,     after max is min
         | 
| 245 | 
            +
                KEY_BRIGHTNESS_AUTO          = 244 # Set Auto Brightness: manual
         | 
| 246 | 
            +
                KEY_BRIGHTNESS_ZERO          = KEY_BRIGHTNESS_AUTO
         | 
| 247 | 
            +
                KEY_DISPLAY_OFF              = 245 # display device to off state
         | 
| 248 | 
            +
                KEY_WWAN                     = 246 # Wireless WAN (LTE, UMTS, GSM, etc.)
         | 
| 249 | 
            +
                KEY_WIMAX                    = KEY_WWAN
         | 
| 250 | 
            +
                KEY_RFKILL                   = 247 # Key that controls all radios
         | 
| 251 | 
            +
                KEY_MICMUTE                  = 248 # Mute / unmute the microphone
         | 
| 252 | 
            +
                KEY_OK                       = 0x160
         | 
| 253 | 
            +
                KEY_SELECT                   = 0x161
         | 
| 254 | 
            +
                KEY_GOTO                     = 0x162
         | 
| 255 | 
            +
                KEY_CLEAR                    = 0x163
         | 
| 256 | 
            +
                KEY_POWER2                   = 0x164
         | 
| 257 | 
            +
                KEY_OPTION                   = 0x165
         | 
| 258 | 
            +
                KEY_INFO                     = 0x166 # AL OEM Features/Tips/Tutorial
         | 
| 259 | 
            +
                KEY_TIME                     = 0x167
         | 
| 260 | 
            +
                KEY_VENDOR                   = 0x168
         | 
| 261 | 
            +
                KEY_ARCHIVE                  = 0x169
         | 
| 262 | 
            +
                KEY_PROGRAM                  = 0x16a # Media Select Program Guide
         | 
| 263 | 
            +
                KEY_CHANNEL                  = 0x16b
         | 
| 264 | 
            +
                KEY_FAVORITES                = 0x16c
         | 
| 265 | 
            +
                KEY_EPG                      = 0x16d
         | 
| 266 | 
            +
                KEY_PVR                      = 0x16e # Media Select Home
         | 
| 267 | 
            +
                KEY_MHP                      = 0x16f
         | 
| 268 | 
            +
                KEY_LANGUAGE                 = 0x170
         | 
| 269 | 
            +
                KEY_TITLE                    = 0x171
         | 
| 270 | 
            +
                KEY_SUBTITLE                 = 0x172
         | 
| 271 | 
            +
                KEY_ANGLE                    = 0x173
         | 
| 272 | 
            +
                KEY_FULL_SCREEN              = 0x174 # AC View Toggle
         | 
| 273 | 
            +
                KEY_ZOOM                     = KEY_FULL_SCREEN
         | 
| 274 | 
            +
                KEY_MODE                     = 0x175
         | 
| 275 | 
            +
                KEY_KEYBOARD                 = 0x176
         | 
| 276 | 
            +
                KEY_ASPECT_RATIO             = 0x177 # HUTRR37: Aspect
         | 
| 277 | 
            +
                KEY_SCREEN                   = KEY_ASPECT_RATIO
         | 
| 278 | 
            +
                KEY_PC                       = 0x178 # Media Select Computer
         | 
| 279 | 
            +
                KEY_TV                       = 0x179 # Media Select TV
         | 
| 280 | 
            +
                KEY_TV2                      = 0x17a # Media Select Cable
         | 
| 281 | 
            +
                KEY_VCR                      = 0x17b # Media Select VCR
         | 
| 282 | 
            +
                KEY_VCR2                     = 0x17c # VCR Plus
         | 
| 283 | 
            +
                KEY_SAT                      = 0x17d # Media Select Satellite
         | 
| 284 | 
            +
                KEY_SAT2                     = 0x17e
         | 
| 285 | 
            +
                KEY_CD                       = 0x17f # Media Select CD
         | 
| 286 | 
            +
                KEY_TAPE                     = 0x180 # Media Select Tape
         | 
| 287 | 
            +
                KEY_RADIO                    = 0x181
         | 
| 288 | 
            +
                KEY_TUNER                    = 0x182 # Media Select Tuner
         | 
| 289 | 
            +
                KEY_PLAYER                   = 0x183
         | 
| 290 | 
            +
                KEY_TEXT                     = 0x184
         | 
| 291 | 
            +
                KEY_DVD                      = 0x185 # Media Select DVD
         | 
| 292 | 
            +
                KEY_AUX                      = 0x186
         | 
| 293 | 
            +
                KEY_MP3                      = 0x187
         | 
| 294 | 
            +
                KEY_AUDIO                    = 0x188 # AL Audio Browser
         | 
| 295 | 
            +
                KEY_VIDEO                    = 0x189 # AL Movie Browser
         | 
| 296 | 
            +
                KEY_DIRECTORY                = 0x18a
         | 
| 297 | 
            +
                KEY_LIST                     = 0x18b
         | 
| 298 | 
            +
                KEY_MEMO                     = 0x18c # Media Select Messages
         | 
| 299 | 
            +
                KEY_CALENDAR                 = 0x18d
         | 
| 300 | 
            +
                KEY_RED                      = 0x18e
         | 
| 301 | 
            +
                KEY_GREEN                    = 0x18f
         | 
| 302 | 
            +
                KEY_YELLOW                   = 0x190
         | 
| 303 | 
            +
                KEY_BLUE                     = 0x191
         | 
| 304 | 
            +
                KEY_CHANNELUP                = 0x192 # Channel Increment
         | 
| 305 | 
            +
                KEY_CHANNELDOWN              = 0x193 # Channel Decrement
         | 
| 306 | 
            +
                KEY_FIRST                    = 0x194
         | 
| 307 | 
            +
                KEY_LAST                     = 0x195 # Recall Last
         | 
| 308 | 
            +
                KEY_AB                       = 0x196
         | 
| 309 | 
            +
                KEY_NEXT                     = 0x197
         | 
| 310 | 
            +
                KEY_RESTART                  = 0x198
         | 
| 311 | 
            +
                KEY_SLOW                     = 0x199
         | 
| 312 | 
            +
                KEY_SHUFFLE                  = 0x19a
         | 
| 313 | 
            +
                KEY_BREAK                    = 0x19b
         | 
| 314 | 
            +
                KEY_PREVIOUS                 = 0x19c
         | 
| 315 | 
            +
                KEY_DIGITS                   = 0x19d
         | 
| 316 | 
            +
                KEY_TEEN                     = 0x19e
         | 
| 317 | 
            +
                KEY_TWEN                     = 0x19f
         | 
| 318 | 
            +
                KEY_VIDEOPHONE               = 0x1a0 # Media Select Video Phone
         | 
| 319 | 
            +
                KEY_GAMES                    = 0x1a1 # Media Select Games
         | 
| 320 | 
            +
                KEY_ZOOMIN                   = 0x1a2 # AC Zoom In
         | 
| 321 | 
            +
                KEY_ZOOMOUT                  = 0x1a3 # AC Zoom Out
         | 
| 322 | 
            +
                KEY_ZOOMRESET                = 0x1a4 # AC Zoom
         | 
| 323 | 
            +
                KEY_WORDPROCESSOR            = 0x1a5 # AL Word Processor
         | 
| 324 | 
            +
                KEY_EDITOR                   = 0x1a6 # AL Text Editor
         | 
| 325 | 
            +
                KEY_SPREADSHEET              = 0x1a7 # AL Spreadsheet
         | 
| 326 | 
            +
                KEY_GRAPHICSEDITOR           = 0x1a8 # AL Graphics Editor
         | 
| 327 | 
            +
                KEY_PRESENTATION             = 0x1a9 # AL Presentation App
         | 
| 328 | 
            +
                KEY_DATABASE                 = 0x1aa # AL Database App
         | 
| 329 | 
            +
                KEY_NEWS                     = 0x1ab # AL Newsreader
         | 
| 330 | 
            +
                KEY_VOICEMAIL                = 0x1ac # AL Voicemail
         | 
| 331 | 
            +
                KEY_ADDRESSBOOK              = 0x1ad # AL Contacts/Address Book
         | 
| 332 | 
            +
                KEY_MESSENGER                = 0x1ae # AL Instant Messaging
         | 
| 333 | 
            +
                KEY_DISPLAYTOGGLE            = 0x1af # Turn display (LCD) on and off
         | 
| 334 | 
            +
                KEY_BRIGHTNESS_TOGGLE        = KEY_DISPLAYTOGGLE
         | 
| 335 | 
            +
                KEY_SPELLCHECK               = 0x1b0   # AL Spell Check
         | 
| 336 | 
            +
                KEY_LOGOFF                   = 0x1b1   # AL Logoff
         | 
| 337 | 
            +
                KEY_DOLLAR                   = 0x1b2
         | 
| 338 | 
            +
                KEY_EURO                     = 0x1b3
         | 
| 339 | 
            +
                KEY_FRAMEBACK                = 0x1b4 # Consumer - transport controls
         | 
| 340 | 
            +
                KEY_FRAMEFORWARD             = 0x1b5
         | 
| 341 | 
            +
                KEY_CONTEXT_MENU             = 0x1b6 # GenDesc - system context menu
         | 
| 342 | 
            +
                KEY_MEDIA_REPEAT             = 0x1b7 # Consumer - transport control
         | 
| 343 | 
            +
                KEY_10CHANNELSUP             = 0x1b8 # 10 channels up (10+)
         | 
| 344 | 
            +
                KEY_10CHANNELSDOWN           = 0x1b9 # 10 channels down (10-)
         | 
| 345 | 
            +
                KEY_IMAGES                   = 0x1ba # AL Image Browser
         | 
| 346 | 
            +
                KEY_NOTIFICATION_CENTER      = 0x1bc # Show/hide the notification center
         | 
| 347 | 
            +
                KEY_PICKUP_PHONE             = 0x1bd # Answer incoming call
         | 
| 348 | 
            +
                KEY_HANGUP_PHONE             = 0x1be # Decline incoming call
         | 
| 349 | 
            +
                KEY_DEL_EOL                  = 0x1c0
         | 
| 350 | 
            +
                KEY_DEL_EOS                  = 0x1c1
         | 
| 351 | 
            +
                KEY_INS_LINE                 = 0x1c2
         | 
| 352 | 
            +
                KEY_DEL_LINE                 = 0x1c3
         | 
| 353 | 
            +
                KEY_FN                       = 0x1d0
         | 
| 354 | 
            +
                KEY_FN_ESC                   = 0x1d1
         | 
| 355 | 
            +
                KEY_FN_F1                    = 0x1d2
         | 
| 356 | 
            +
                KEY_FN_F2                    = 0x1d3
         | 
| 357 | 
            +
                KEY_FN_F3                    = 0x1d4
         | 
| 358 | 
            +
                KEY_FN_F4                    = 0x1d5
         | 
| 359 | 
            +
                KEY_FN_F5                    = 0x1d6
         | 
| 360 | 
            +
                KEY_FN_F6                    = 0x1d7
         | 
| 361 | 
            +
                KEY_FN_F7                    = 0x1d8
         | 
| 362 | 
            +
                KEY_FN_F8                    = 0x1d9
         | 
| 363 | 
            +
                KEY_FN_F9                    = 0x1da
         | 
| 364 | 
            +
                KEY_FN_F10                   = 0x1db
         | 
| 365 | 
            +
                KEY_FN_F11                   = 0x1dc
         | 
| 366 | 
            +
                KEY_FN_F12                   = 0x1dd
         | 
| 367 | 
            +
                KEY_FN_1                     = 0x1de
         | 
| 368 | 
            +
                KEY_FN_2                     = 0x1df
         | 
| 369 | 
            +
                KEY_FN_D                     = 0x1e0
         | 
| 370 | 
            +
                KEY_FN_E                     = 0x1e1
         | 
| 371 | 
            +
                KEY_FN_F                     = 0x1e2
         | 
| 372 | 
            +
                KEY_FN_S                     = 0x1e3
         | 
| 373 | 
            +
                KEY_FN_B                     = 0x1e4
         | 
| 374 | 
            +
                KEY_FN_RIGHT_SHIFT           = 0x1e5
         | 
| 375 | 
            +
                KEY_BRL_DOT1                 = 0x1f1
         | 
| 376 | 
            +
                KEY_BRL_DOT2                 = 0x1f2
         | 
| 377 | 
            +
                KEY_BRL_DOT3                 = 0x1f3
         | 
| 378 | 
            +
                KEY_BRL_DOT4                 = 0x1f4
         | 
| 379 | 
            +
                KEY_BRL_DOT5                 = 0x1f5
         | 
| 380 | 
            +
                KEY_BRL_DOT6                 = 0x1f6
         | 
| 381 | 
            +
                KEY_BRL_DOT7                 = 0x1f7
         | 
| 382 | 
            +
                KEY_BRL_DOT8                 = 0x1f8
         | 
| 383 | 
            +
                KEY_BRL_DOT9                 = 0x1f9
         | 
| 384 | 
            +
                KEY_BRL_DOT10                = 0x1fa
         | 
| 385 | 
            +
                KEY_NUMERIC_0                = 0x200 # used by phones,  remote controls,
         | 
| 386 | 
            +
                KEY_NUMERIC_1                = 0x201 # and other keypads
         | 
| 387 | 
            +
                KEY_NUMERIC_2                = 0x202
         | 
| 388 | 
            +
                KEY_NUMERIC_3                = 0x203
         | 
| 389 | 
            +
                KEY_NUMERIC_4                = 0x204
         | 
| 390 | 
            +
                KEY_NUMERIC_5                = 0x205
         | 
| 391 | 
            +
                KEY_NUMERIC_6                = 0x206
         | 
| 392 | 
            +
                KEY_NUMERIC_7                = 0x207
         | 
| 393 | 
            +
                KEY_NUMERIC_8                = 0x208
         | 
| 394 | 
            +
                KEY_NUMERIC_9                = 0x209
         | 
| 395 | 
            +
                KEY_NUMERIC_STAR             = 0x20a
         | 
| 396 | 
            +
                KEY_NUMERIC_POUND            = 0x20b
         | 
| 397 | 
            +
                KEY_NUMERIC_A                = 0x20c # Phone key A - HUT Telephony 0xb9
         | 
| 398 | 
            +
                KEY_NUMERIC_B                = 0x20d
         | 
| 399 | 
            +
                KEY_NUMERIC_C                = 0x20e
         | 
| 400 | 
            +
                KEY_NUMERIC_D                = 0x20f
         | 
| 401 | 
            +
                KEY_CAMERA_FOCUS             = 0x210
         | 
| 402 | 
            +
                KEY_WPS_BUTTON               = 0x211 # WiFi Protected Setup key
         | 
| 403 | 
            +
                KEY_TOUCHPAD_TOGGLE          = 0x212 # Request switch touchpad on or off
         | 
| 404 | 
            +
                KEY_TOUCHPAD_ON              = 0x213
         | 
| 405 | 
            +
                KEY_TOUCHPAD_OFF             = 0x214
         | 
| 406 | 
            +
                KEY_CAMERA_ZOOMIN            = 0x215
         | 
| 407 | 
            +
                KEY_CAMERA_ZOOMOUT           = 0x216
         | 
| 408 | 
            +
                KEY_CAMERA_UP                = 0x217
         | 
| 409 | 
            +
                KEY_CAMERA_DOWN              = 0x218
         | 
| 410 | 
            +
                KEY_CAMERA_LEFT              = 0x219
         | 
| 411 | 
            +
                KEY_CAMERA_RIGHT             = 0x21a
         | 
| 412 | 
            +
                KEY_ATTENDANT_ON             = 0x21b
         | 
| 413 | 
            +
                KEY_ATTENDANT_OFF            = 0x21c
         | 
| 414 | 
            +
                KEY_ATTENDANT_TOGGLE         = 0x21d # Attendant call on or off
         | 
| 415 | 
            +
                KEY_LIGHTS_TOGGLE            = 0x21e # Reading light on or off
         | 
| 416 | 
            +
                KEY_ALS_TOGGLE               = 0x230 # Ambient light sensor
         | 
| 417 | 
            +
                KEY_ROTATE_LOCK_TOGGLE       = 0x231 # Display rotation lock
         | 
| 418 | 
            +
                KEY_BUTTONCONFIG             = 0x240 # AL Button Configuration
         | 
| 419 | 
            +
                KEY_TASKMANAGER              = 0x241 # AL Task/Project Manager
         | 
| 420 | 
            +
                KEY_JOURNAL                  = 0x242 # AL Log/Journal/Timecard
         | 
| 421 | 
            +
                KEY_CONTROLPANEL             = 0x243 # AL Control Panel
         | 
| 422 | 
            +
                KEY_APPSELECT                = 0x244 # AL Select Task/Application
         | 
| 423 | 
            +
                KEY_SCREENSAVER              = 0x245 # AL Screen Saver
         | 
| 424 | 
            +
                KEY_VOICECOMMAND             = 0x246 # Listening Voice Command
         | 
| 425 | 
            +
                KEY_ASSISTANT                = 0x247 # AL Context-aware desktop assistant
         | 
| 426 | 
            +
                KEY_KBD_LAYOUT_NEXT          = 0x248 # AC Next Keyboard Layout Select
         | 
| 427 | 
            +
                KEY_EMOJI_PICKER             = 0x249 # Show/hide emoji picker (HUTRR101)
         | 
| 428 | 
            +
                KEY_BRIGHTNESS_MIN           = 0x250 # Set Brightness to Minimum
         | 
| 429 | 
            +
                KEY_BRIGHTNESS_MAX           = 0x251 # Set Brightness to Maximum
         | 
| 430 | 
            +
                KEY_KBDINPUTASSIST_PREV      = 0x260
         | 
| 431 | 
            +
                KEY_KBDINPUTASSIST_NEXT      = 0x261
         | 
| 432 | 
            +
                KEY_KBDINPUTASSIST_PREVGROUP = 0x262
         | 
| 433 | 
            +
                KEY_KBDINPUTASSIST_NEXTGROUP = 0x263
         | 
| 434 | 
            +
                KEY_KBDINPUTASSIST_ACCEPT    = 0x264
         | 
| 435 | 
            +
                KEY_KBDINPUTASSIST_CANCEL    = 0x265
         | 
| 436 | 
            +
                KEY_RIGHT_UP                 = 0x266
         | 
| 437 | 
            +
                KEY_RIGHT_DOWN               = 0x267
         | 
| 438 | 
            +
                KEY_LEFT_UP                  = 0x268
         | 
| 439 | 
            +
                KEY_LEFT_DOWN                = 0x269
         | 
| 440 | 
            +
                KEY_ROOT_MENU                = 0x26a # Show Device's Root Menu
         | 
| 441 | 
            +
                KEY_MEDIA_TOP_MENU           = 0x26b
         | 
| 442 | 
            +
                KEY_NUMERIC_11               = 0x26c
         | 
| 443 | 
            +
                KEY_NUMERIC_12               = 0x26d
         | 
| 444 | 
            +
                KEY_AUDIO_DESC               = 0x26e
         | 
| 445 | 
            +
                KEY_3D_MODE                  = 0x26f
         | 
| 446 | 
            +
                KEY_NEXT_FAVORITE            = 0x270
         | 
| 447 | 
            +
                KEY_STOP_RECORD              = 0x271
         | 
| 448 | 
            +
                KEY_PAUSE_RECORD             = 0x272
         | 
| 449 | 
            +
                KEY_VOD                      = 0x273 # Video on Demand
         | 
| 450 | 
            +
                KEY_UNMUTE                   = 0x274
         | 
| 451 | 
            +
                KEY_FASTREVERSE              = 0x275
         | 
| 452 | 
            +
                KEY_SLOWREVERSE              = 0x276
         | 
| 453 | 
            +
                KEY_DATA                     = 0x277
         | 
| 454 | 
            +
                KEY_ONSCREEN_KEYBOARD        = 0x278
         | 
| 455 | 
            +
                KEY_PRIVACY_SCREEN_TOGGLE    = 0x279
         | 
| 456 | 
            +
                KEY_SELECTIVE_SCREENSHOT     = 0x27a
         | 
| 457 | 
            +
                KEY_MACRO1                   = 0x290
         | 
| 458 | 
            +
                KEY_MACRO2                   = 0x291
         | 
| 459 | 
            +
                KEY_MACRO3                   = 0x292
         | 
| 460 | 
            +
                KEY_MACRO4                   = 0x293
         | 
| 461 | 
            +
                KEY_MACRO5                   = 0x294
         | 
| 462 | 
            +
                KEY_MACRO6                   = 0x295
         | 
| 463 | 
            +
                KEY_MACRO7                   = 0x296
         | 
| 464 | 
            +
                KEY_MACRO8                   = 0x297
         | 
| 465 | 
            +
                KEY_MACRO9                   = 0x298
         | 
| 466 | 
            +
                KEY_MACRO10                  = 0x299
         | 
| 467 | 
            +
                KEY_MACRO11                  = 0x29a
         | 
| 468 | 
            +
                KEY_MACRO12                  = 0x29b
         | 
| 469 | 
            +
                KEY_MACRO13                  = 0x29c
         | 
| 470 | 
            +
                KEY_MACRO14                  = 0x29d
         | 
| 471 | 
            +
                KEY_MACRO15                  = 0x29e
         | 
| 472 | 
            +
                KEY_MACRO16                  = 0x29f
         | 
| 473 | 
            +
                KEY_MACRO17                  = 0x2a0
         | 
| 474 | 
            +
                KEY_MACRO18                  = 0x2a1
         | 
| 475 | 
            +
                KEY_MACRO19                  = 0x2a2
         | 
| 476 | 
            +
                KEY_MACRO20                  = 0x2a3
         | 
| 477 | 
            +
                KEY_MACRO21                  = 0x2a4
         | 
| 478 | 
            +
                KEY_MACRO22                  = 0x2a5
         | 
| 479 | 
            +
                KEY_MACRO23                  = 0x2a6
         | 
| 480 | 
            +
                KEY_MACRO24                  = 0x2a7
         | 
| 481 | 
            +
                KEY_MACRO25                  = 0x2a8
         | 
| 482 | 
            +
                KEY_MACRO26                  = 0x2a9
         | 
| 483 | 
            +
                KEY_MACRO27                  = 0x2aa
         | 
| 484 | 
            +
                KEY_MACRO28                  = 0x2ab
         | 
| 485 | 
            +
                KEY_MACRO29                  = 0x2ac
         | 
| 486 | 
            +
                KEY_MACRO30                  = 0x2ad
         | 
| 487 | 
            +
                KEY_MACRO_RECORD_START       = 0x2b0
         | 
| 488 | 
            +
                KEY_MACRO_RECORD_STOP        = 0x2b1
         | 
| 489 | 
            +
                KEY_MACRO_PRESET_CYCLE       = 0x2b2
         | 
| 490 | 
            +
                KEY_MACRO_PRESET1            = 0x2b3
         | 
| 491 | 
            +
                KEY_MACRO_PRESET2            = 0x2b4
         | 
| 492 | 
            +
                KEY_MACRO_PRESET3            = 0x2b5
         | 
| 493 | 
            +
                KEY_KBD_LCD_MENU1            = 0x2b8
         | 
| 494 | 
            +
                KEY_KBD_LCD_MENU2            = 0x2b9
         | 
| 495 | 
            +
                KEY_KBD_LCD_MENU3            = 0x2ba
         | 
| 496 | 
            +
                KEY_KBD_LCD_MENU4            = 0x2bb
         | 
| 497 | 
            +
                KEY_KBD_LCD_MENU5            = 0x2bc
         | 
| 498 | 
            +
                KEY_MIN_INTERESTING          = KEY_MUTE
         | 
| 499 | 
            +
                KEY_MAX                      = 0x2ff
         | 
| 500 | 
            +
                KEY_CNT                      = (KEY_MAX+1)
         | 
| 501 | 
            +
              end
         | 
| 502 | 
            +
             | 
| 503 | 
            +
              CODE_KEY = {}
         | 
| 504 | 
            +
              KeyCode.constants.each do |k|
         | 
| 505 | 
            +
                next unless k =~ /\AKEY_/
         | 
| 506 | 
            +
                code = KeyCode.const_get(k)
         | 
| 507 | 
            +
                CODE_KEY[code] = k unless CODE_KEY[code]
         | 
| 508 | 
            +
              end
         | 
| 509 | 
            +
            end
         | 
| @@ -0,0 +1,95 @@ | |
| 1 | 
            +
            require 'ffi'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module FFI
         | 
| 4 | 
            +
              typedef :pointer, :Display
         | 
| 5 | 
            +
              typedef :ulong, :XID
         | 
| 6 | 
            +
              typedef :XID, :Window
         | 
| 7 | 
            +
              typedef :int, :Status
         | 
| 8 | 
            +
              typedef :ulong, :Atom
         | 
| 9 | 
            +
            end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            class Rkremap
         | 
| 12 | 
            +
              # アプリの name, class, title を取得する
         | 
| 13 | 
            +
              class WinAttr
         | 
| 14 | 
            +
                def initialize
         | 
| 15 | 
            +
                  @app_win = {}
         | 
| 16 | 
            +
                  @display = X11.XOpenDisplay(nil) or raise "Cannot open display: #{ENV['DISPLAY']}"
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def focus_win
         | 
| 20 | 
            +
                  win = FFI::MemoryPointer.new(:Window)
         | 
| 21 | 
            +
                  revert_to = FFI::MemoryPointer.new(:int)
         | 
| 22 | 
            +
                  X11.XGetInputFocus(@display, win, revert_to)
         | 
| 23 | 
            +
                  win.read(:Window)
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                # @return [Array<window, name, class>]
         | 
| 27 | 
            +
                def app_win(window)
         | 
| 28 | 
            +
                  return @app_win[window] if @app_win[window]
         | 
| 29 | 
            +
                  class_hint = XClassHint.new
         | 
| 30 | 
            +
                  root = FFI::MemoryPointer.new(:Window)
         | 
| 31 | 
            +
                  parent = FFI::MemoryPointer.new(:Window)
         | 
| 32 | 
            +
                  children = FFI::MemoryPointer.new(:pointer)
         | 
| 33 | 
            +
                  nchildren = FFI::MemoryPointer.new(:int)
         | 
| 34 | 
            +
                  win = window
         | 
| 35 | 
            +
                  while win > 0
         | 
| 36 | 
            +
                    X11.XGetClassHint(@display, win, class_hint)
         | 
| 37 | 
            +
                    X11.XQueryTree(@display, win, root, parent, children, nchildren)
         | 
| 38 | 
            +
                    X11.XFree(children.read_pointer)
         | 
| 39 | 
            +
                    break unless class_hint[:name].null? && class_hint[:class].null?
         | 
| 40 | 
            +
                    win = parent.read(:Window)
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
                  unless class_hint[:name].null?
         | 
| 43 | 
            +
                    win_name = class_hint[:name].read_string
         | 
| 44 | 
            +
                    X11.XFree(class_hint[:name])
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
                  unless class_hint[:class].null?
         | 
| 47 | 
            +
                    win_class = class_hint[:class].read_string
         | 
| 48 | 
            +
                    X11.XFree(class_hint[:class])
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
                  @app_win[window] = [win, win_name, win_class]
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                # @return [String]
         | 
| 54 | 
            +
                def app_title(window)
         | 
| 55 | 
            +
                  win = app_win(window)[0]
         | 
| 56 | 
            +
                  prop = XTextProperty.new
         | 
| 57 | 
            +
                  text_list = FFI::MemoryPointer.new(:pointer)
         | 
| 58 | 
            +
                  count = FFI::MemoryPointer.new(:int)
         | 
| 59 | 
            +
                  X11.XGetWMName(@display, win, prop)
         | 
| 60 | 
            +
                  X11.Xutf8TextPropertyToTextList(@display, prop, text_list, count)
         | 
| 61 | 
            +
                  title = text_list.read(:pointer).read(:string)&.force_encoding('utf-8')
         | 
| 62 | 
            +
                  X11.XFreeStringList(text_list.read(:pointer))
         | 
| 63 | 
            +
                  title
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              class XClassHint < FFI::Struct
         | 
| 68 | 
            +
                layout(
         | 
| 69 | 
            +
                  :name, :pointer,
         | 
| 70 | 
            +
                  :class, :pointer,
         | 
| 71 | 
            +
                )
         | 
| 72 | 
            +
              end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
              class XTextProperty < FFI::Struct
         | 
| 75 | 
            +
                layout(
         | 
| 76 | 
            +
                  :value, :pointer,
         | 
| 77 | 
            +
                  :encoding, :Atom,
         | 
| 78 | 
            +
                  :format, :int,
         | 
| 79 | 
            +
                  :nitems, :ulong,
         | 
| 80 | 
            +
                )
         | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
              module X11
         | 
| 84 | 
            +
                extend FFI::Library
         | 
| 85 | 
            +
                ffi_lib 'X11'
         | 
| 86 | 
            +
                attach_function :XOpenDisplay, [:string], :Display
         | 
| 87 | 
            +
                attach_function :XGetInputFocus, [:Display, :pointer, :pointer], :int
         | 
| 88 | 
            +
                attach_function :XGetClassHint, [:Display, :Window, XClassHint.by_ref], :int
         | 
| 89 | 
            +
                attach_function :XQueryTree, [:Display, :Window, :pointer, :pointer, :pointer, :pointer], :Status
         | 
| 90 | 
            +
                attach_function :XGetWMName, [:Display, :Window, XTextProperty.by_ref], :void
         | 
| 91 | 
            +
                attach_function :Xutf8TextPropertyToTextList, [:Display, XTextProperty.by_ref, :pointer, :pointer], :int
         | 
| 92 | 
            +
                attach_function :XFree, [:pointer], :int
         | 
| 93 | 
            +
                attach_function :XFreeStringList, [:pointer], :void
         | 
| 94 | 
            +
              end
         | 
| 95 | 
            +
            end
         | 
    
        data/lib/rkremap.rb
    ADDED
    
    | @@ -0,0 +1,176 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require_relative "rkremap/version"
         | 
| 4 | 
            +
            require_relative 'rkremap/keycode'
         | 
| 5 | 
            +
            require_relative 'rkremap/winattr'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            class Rkremap
         | 
| 8 | 
            +
              include KeyCode
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              # ioctl constants
         | 
| 11 | 
            +
              EVIOCGRAB = 1074021776
         | 
| 12 | 
            +
              UI_SET_EVBIT = 1074025828
         | 
| 13 | 
            +
              UI_SET_KEYBIT = 1074025829
         | 
| 14 | 
            +
              UI_DEV_SETUP = 1079792899
         | 
| 15 | 
            +
              UI_DEV_CREATE = 21761
         | 
| 16 | 
            +
              EV_KEY = 1
         | 
| 17 | 
            +
              EV_SYN = 0
         | 
| 18 | 
            +
              SYN_REPORT = 0
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              EVENT_TYPE_VALUE = {
         | 
| 21 | 
            +
                release: 0,
         | 
| 22 | 
            +
                press:   1,
         | 
| 23 | 
            +
                repeat:  2,
         | 
| 24 | 
            +
              }
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              attr_accessor :grab
         | 
| 27 | 
            +
              attr_accessor :modifiers
         | 
| 28 | 
            +
              attr_accessor :x11
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              # @param device [String]
         | 
| 31 | 
            +
              def initialize(device)
         | 
| 32 | 
            +
                @input = File.open(device)
         | 
| 33 | 
            +
                @uinput = File.open('/dev/uinput', 'w')
         | 
| 34 | 
            +
                setup_uinput
         | 
| 35 | 
            +
                @grab = false
         | 
| 36 | 
            +
                @x11 = false
         | 
| 37 | 
            +
                @modifiers = [
         | 
| 38 | 
            +
                  KEY_LEFTCTRL,  KEY_RIGHTCTRL,
         | 
| 39 | 
            +
                  KEY_LEFTSHIFT, KEY_RIGHTSHIFT,
         | 
| 40 | 
            +
                  KEY_LEFTALT,   KEY_RIGHTALT,
         | 
| 41 | 
            +
                  KEY_LEFTMETA,  KEY_RIGHTMETA,
         | 
| 42 | 
            +
                ]
         | 
| 43 | 
            +
                @events = []
         | 
| 44 | 
            +
                @mutex = Mutex.new
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              # @param code [Integer]
         | 
| 48 | 
            +
              # @param type [Symbol] :press / :release / :repeat
         | 
| 49 | 
            +
              def match(code: nil, type: nil, &block)
         | 
| 50 | 
            +
                @events.push [{code: code, type: type}, block]
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              def start(&block)
         | 
| 54 | 
            +
                @mod_state = @modifiers.map{|m| [m, false]}.to_h
         | 
| 55 | 
            +
                @winattr = WinAttr.new if @x11
         | 
| 56 | 
            +
                @input.ioctl(EVIOCGRAB, 1) if @grab
         | 
| 57 | 
            +
                while true
         | 
| 58 | 
            +
                  @keys = []
         | 
| 59 | 
            +
                  raw = @input.sysread(24)
         | 
| 60 | 
            +
                  sec, usec, type, code, value = raw.unpack('Q!Q!SSl')
         | 
| 61 | 
            +
                  next if type != EV_KEY
         | 
| 62 | 
            +
                  time = Time.at(sec, usec)
         | 
| 63 | 
            +
                  event = Event.new(time, code, value, @winattr)
         | 
| 64 | 
            +
                  @events.each do |cond, b|
         | 
| 65 | 
            +
                    synchronize{ b.call event } if event.match?(**cond)
         | 
| 66 | 
            +
                    break if event.skipped
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
                  next if event.skipped
         | 
| 69 | 
            +
                  synchronize{ proc_event(code, value, event) }
         | 
| 70 | 
            +
                  @keys.each do |c, mod, app|
         | 
| 71 | 
            +
                    synchronize{ block.call(c, mod, app) } if block
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
              def synchronize(&block)
         | 
| 77 | 
            +
                @mutex.synchronize(&block)
         | 
| 78 | 
            +
              end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
              # @param code [Integer]
         | 
| 81 | 
            +
              # @param type [Symbol] :press / :release / :repeat
         | 
| 82 | 
            +
              # @param ev [Rkmap::Event]
         | 
| 83 | 
            +
              def event(code: nil, type: nil, event: nil)
         | 
| 84 | 
            +
                value = EVENT_TYPE_VALUE[type] or raise "invalid type: #{type.inspect}"
         | 
| 85 | 
            +
                proc_event(code, value, event)
         | 
| 86 | 
            +
              end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
              # @param code [Integer]
         | 
| 89 | 
            +
              # @param mod [Hash] {MOD_KEY => true, ...}
         | 
| 90 | 
            +
              def key(code, mod={})
         | 
| 91 | 
            +
                mod_diff(mod).each do |mcode, state|
         | 
| 92 | 
            +
                  write_event(mcode, state ? 1 : 0)
         | 
| 93 | 
            +
                end
         | 
| 94 | 
            +
                write_event(code, 1)
         | 
| 95 | 
            +
                write_event(code, 0)
         | 
| 96 | 
            +
                mod_diff(mod).each do |mcode, _|
         | 
| 97 | 
            +
                  write_event(mcode, @mod_state[mcode] ? 1 : 0)
         | 
| 98 | 
            +
                end
         | 
| 99 | 
            +
              end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
              private
         | 
| 102 | 
            +
             | 
| 103 | 
            +
              def setup_uinput
         | 
| 104 | 
            +
                @uinput.ioctl(UI_SET_EVBIT, EV_KEY)
         | 
| 105 | 
            +
                KEY_CNT.times{|k| @uinput.ioctl(UI_SET_KEYBIT, k)}
         | 
| 106 | 
            +
                bustype = 0x03    # BUS_USB
         | 
| 107 | 
            +
                vendor = 0x1234   # てきとー
         | 
| 108 | 
            +
                product = 0x5678  # てきとー
         | 
| 109 | 
            +
                version = 1       # てきとー
         | 
| 110 | 
            +
                name = 'rkremap'
         | 
| 111 | 
            +
                ff_efects_max = 0
         | 
| 112 | 
            +
                setup = [bustype, vendor, product, version, name, ff_efects_max].pack("SSSSZ80L") # struct uinput_setup
         | 
| 113 | 
            +
                @uinput.ioctl(UI_DEV_SETUP, setup)
         | 
| 114 | 
            +
                @uinput.ioctl(UI_DEV_CREATE)
         | 
| 115 | 
            +
              end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
              def proc_event(code, value, event)
         | 
| 118 | 
            +
                if @mod_state.include?(code)
         | 
| 119 | 
            +
                  @mod_state[code] = value != 0
         | 
| 120 | 
            +
                  write_event(code, value)
         | 
| 121 | 
            +
                elsif value != 0
         | 
| 122 | 
            +
                  @keys.push [code, @mod_state.dup, App.new(event&.win, @winattr)]
         | 
| 123 | 
            +
                end
         | 
| 124 | 
            +
              end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
              def mod_diff(mod)
         | 
| 127 | 
            +
                mod.select{|k, v| @mod_state[k] != v}
         | 
| 128 | 
            +
              end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
              # @param code [Integer]
         | 
| 131 | 
            +
              # @param value [Integer] 0:release / 1:press / 2:repeat
         | 
| 132 | 
            +
              def write_event(code, value)
         | 
| 133 | 
            +
                @uinput.syswrite(['', EV_KEY, code, value].pack('a16SSl'))
         | 
| 134 | 
            +
                @uinput.syswrite(['', EV_SYN, SYN_REPORT, 0].pack('a16SSl'))
         | 
| 135 | 
            +
              end
         | 
| 136 | 
            +
             | 
| 137 | 
            +
              class Event
         | 
| 138 | 
            +
                attr_reader :time
         | 
| 139 | 
            +
                attr_reader :code
         | 
| 140 | 
            +
                attr_reader :type
         | 
| 141 | 
            +
                attr_reader :win
         | 
| 142 | 
            +
                attr_reader :skipped
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                def initialize(time, code, value, winattr)
         | 
| 145 | 
            +
                  @time = time
         | 
| 146 | 
            +
                  @code = code
         | 
| 147 | 
            +
                  @value = value
         | 
| 148 | 
            +
                  @type = value == 1 ? :press : value == 0 ? :release : :repeat
         | 
| 149 | 
            +
                  @win = winattr&.focus_win
         | 
| 150 | 
            +
                  @skipped = false
         | 
| 151 | 
            +
                end
         | 
| 152 | 
            +
             | 
| 153 | 
            +
                def match?(code: nil, type: nil)
         | 
| 154 | 
            +
                  (code.nil? || Array(code).include?(@code)) && (type.nil? || Array(type).include?(@type))
         | 
| 155 | 
            +
                end
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                def skip
         | 
| 158 | 
            +
                  @skipped = true
         | 
| 159 | 
            +
                end
         | 
| 160 | 
            +
              end
         | 
| 161 | 
            +
             | 
| 162 | 
            +
              class App
         | 
| 163 | 
            +
                def initialize(win, winattr)
         | 
| 164 | 
            +
                  @win = win
         | 
| 165 | 
            +
                  @winattr = winattr
         | 
| 166 | 
            +
                end
         | 
| 167 | 
            +
             | 
| 168 | 
            +
                def class_name
         | 
| 169 | 
            +
                  @winattr.app_win(@win)[2] if @winattr && @win
         | 
| 170 | 
            +
                end
         | 
| 171 | 
            +
             | 
| 172 | 
            +
                def title
         | 
| 173 | 
            +
                  @winattr.app_title(@win) if @winattr && @win
         | 
| 174 | 
            +
                end
         | 
| 175 | 
            +
              end
         | 
| 176 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,70 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: rkremap
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.1.0
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - TOMITA Masahiro
         | 
| 8 | 
            +
            autorequire:
         | 
| 9 | 
            +
            bindir: exe
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2022-01-10 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: ffi
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - "~>"
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: '1.0'
         | 
| 20 | 
            +
              type: :runtime
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - "~>"
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: '1.0'
         | 
| 27 | 
            +
            description: key remapper
         | 
| 28 | 
            +
            email:
         | 
| 29 | 
            +
            - tommy@tmtm.org
         | 
| 30 | 
            +
            executables: []
         | 
| 31 | 
            +
            extensions: []
         | 
| 32 | 
            +
            extra_rdoc_files: []
         | 
| 33 | 
            +
            files:
         | 
| 34 | 
            +
            - README.md
         | 
| 35 | 
            +
            - example/henkan-alt.rb
         | 
| 36 | 
            +
            - example/keylogger.rb
         | 
| 37 | 
            +
            - example/mac-shortcut.rb
         | 
| 38 | 
            +
            - example/tmtms.rb
         | 
| 39 | 
            +
            - lib/rkremap.rb
         | 
| 40 | 
            +
            - lib/rkremap/keycode.rb
         | 
| 41 | 
            +
            - lib/rkremap/version.rb
         | 
| 42 | 
            +
            - lib/rkremap/winattr.rb
         | 
| 43 | 
            +
            homepage: https://github.com/tmtm/rkremap
         | 
| 44 | 
            +
            licenses:
         | 
| 45 | 
            +
            - MIT
         | 
| 46 | 
            +
            metadata:
         | 
| 47 | 
            +
              homepage_uri: https://github.com/tmtm/rkremap
         | 
| 48 | 
            +
              source_code_uri: https://github.com/tmtm/rkremap
         | 
| 49 | 
            +
              documentation_uri: https://www.rubydoc.info/gems/rkremap
         | 
| 50 | 
            +
              rubygems_mfa_required: 'true'
         | 
| 51 | 
            +
            post_install_message:
         | 
| 52 | 
            +
            rdoc_options: []
         | 
| 53 | 
            +
            require_paths:
         | 
| 54 | 
            +
            - lib
         | 
| 55 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 56 | 
            +
              requirements:
         | 
| 57 | 
            +
              - - ">="
         | 
| 58 | 
            +
                - !ruby/object:Gem::Version
         | 
| 59 | 
            +
                  version: 2.6.0
         | 
| 60 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 61 | 
            +
              requirements:
         | 
| 62 | 
            +
              - - ">="
         | 
| 63 | 
            +
                - !ruby/object:Gem::Version
         | 
| 64 | 
            +
                  version: '0'
         | 
| 65 | 
            +
            requirements: []
         | 
| 66 | 
            +
            rubygems_version: 3.3.3
         | 
| 67 | 
            +
            signing_key:
         | 
| 68 | 
            +
            specification_version: 4
         | 
| 69 | 
            +
            summary: key remapper
         | 
| 70 | 
            +
            test_files: []
         |