rkremap 0.2.0 → 0.3.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b9cb72d3bf69bf2d0641eb7856903d110f0a253d5377c2d97ea452a1f0fd5c13
4
- data.tar.gz: 1dd89d3569fc5396a6c314618bcc975e04b63b0f2a55d9c3dd8cd5497f1e2164
3
+ metadata.gz: 55d8872f73bd984afd69fdf3c17e53f39de16a4f8feef40bc851b6527e57aa17
4
+ data.tar.gz: 99c6a99b3fdd44e206d416eab361ca1ab4c9e4defc0d96bfa2fc0e563a5a1e4c
5
5
  SHA512:
6
- metadata.gz: 8cf20b635b0aa1584e81cc0317040931f62f011e004189e30428534c04456159cde7ac37c5f790cc1af06d396b9d60c36c4398a5d51947dcf99309eb3edb584b
7
- data.tar.gz: cde725ba50b0d5b2fd3daf837af9e1244a1cc5cb3d40f497d9dbf00e6655edc0e436dcdc94056b8bc9efa3887ec2419fd7e53b11e8289c142217be2dd577f8ef
6
+ metadata.gz: c9ad9908d2a602e2740748924e5cd83c1f6526eda164c389cde0b22d1b4462d74c7f5eba3809f2c353396500efe5a5447cb22302a0c8db9aaf4fbfa739f1c6a9
7
+ data.tar.gz: 936cef85543d1089d81323ddd4f11a7b4da2afb44d6f7d7c9921132182e300e963a73ad8e51f8e80a6cf879251caad0c5235cddc0cc73a51dc315f2b5a487744
data/README.md CHANGED
@@ -48,6 +48,15 @@ ThinkPad 本体のキーボードは `/dev/input/event3` だった。
48
48
 
49
49
  `true` に設定すると X のアプリ名等を取得できる。X 環境下でないなら `false` を設定する。
50
50
 
51
+ ### Rkremap#modifers
52
+
53
+ 修飾キーの一覧。これらのキーは単体で押されただけでは `start` ブロックを実行しない。
54
+
55
+ ### auto_detect
56
+
57
+ `true` の場合はキーボードデバイスの接続を自動検知する。
58
+ `new` 時にデバイスファイルが指定されない場合は `true` になる。
59
+
51
60
  ### Rkremap#start
52
61
 
53
62
  なにかキーを押されたらブロックを実行する。修飾キー単体ではブロックは実行されない。
@@ -0,0 +1,57 @@
1
+ # 変換/無変換キーを0.5秒以上押してるとALTキーとして扱う。
2
+ # 0.5秒以内でも変換/無変換キーを押しながら他のキーを押すとALTキーとして扱う。
3
+
4
+ require 'rkremap'
5
+ require 'tmtms_timer' # gem install tmtms_timer
6
+
7
+ include Rkremap::KeyCode
8
+
9
+ rk = Rkremap.new
10
+ rk.grab = true
11
+
12
+ timer = Tmtms::Timer.new
13
+ jobs = {
14
+ KEY_HENKAN => nil,
15
+ KEY_MUHENKAN => nil,
16
+ }
17
+
18
+ henkan_map = {
19
+ KEY_HENKAN => KEY_RIGHTMETA,
20
+ KEY_MUHENKAN => KEY_RIGHTMETA, # LEFTMETA だとデスクトップ環境のメニューが開いたりするため
21
+ }
22
+
23
+ rk.match(code: [KEY_HENKAN, KEY_MUHENKAN]) do |event|
24
+ if event.type == :press
25
+ job = timer.set(0.5) do
26
+ rk.synchronize do
27
+ rk.event(code: henkan_map[event.code], type: :press)
28
+ end
29
+ end
30
+ jobs[event.code] = job
31
+ elsif event.type == :release
32
+ if jobs[event.code]&.cancel
33
+ rk.key(event.code)
34
+ else
35
+ rk.event(code: henkan_map[event.code], type: :release)
36
+ end
37
+ end
38
+ event.skip
39
+ end
40
+
41
+ rk.match(type: :press) do
42
+ [KEY_HENKAN, KEY_MUHENKAN].each do |code|
43
+ if jobs[code]&.cancel
44
+ rk.event(code: henkan_map[code], type: :press)
45
+ end
46
+ end
47
+ end
48
+
49
+ def code2key(code)
50
+ Rkremap::CODE_KEY[code].to_s.sub(/\AKEY_/, '')
51
+ end
52
+
53
+ rk.start do |code, mod|
54
+ key = (mod.select{|_, v| v}.keys + [code]).map{|c| code2key(c)}.join('-')
55
+ puts key
56
+ rk.key(code, mod)
57
+ end
@@ -43,14 +43,20 @@ rk.start do |code, mod, app|
43
43
  next
44
44
  end
45
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})
46
+ # SUPER+[A-Z]/Enter を Ctrl+[A-Z]/Enter に変換
47
+ if (mod[KEY_LEFTMETA] || mod[KEY_RIGHTMETA]) && (Rkremap::CODE_KEY[code] =~ /\AKEY_[A-Z]\z/ || code == KEY_ENTER)
48
+ mod.merge!(mod_disable_meta, {KEY_LEFTCTRL => true})
49
49
  mod[KEY_LEFTCTRL] = true
50
50
  rk.key(code, mod)
51
51
  next
52
52
  end
53
53
 
54
+ # Alt + F, B は Ctrl + →, ← に変換
55
+ if (mod[KEY_LEFTALT] || mod[KEY_RIGHTALT]) && (code == KEY_F || code == KEY_B)
56
+ rk.key(code == KEY_F ? KEY_RIGHT : KEY_LEFT, mod.merge(mod_disable_alt, {KEY_LEFTCTRL => true}))
57
+ next
58
+ end
59
+
54
60
  # Ctrl は他のキーに変換
55
61
  if mod[KEY_LEFTCTRL] || mod[KEY_RIGHTCTRL]
56
62
  # Ctrl+K は行末まで削除
data/example/tmtms.rb CHANGED
@@ -1,96 +1,46 @@
1
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
2
 
13
3
  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
4
+ require 'tmtms_timer' # gem install tmtms_timer
37
5
 
38
- def pressed?
39
- @press
40
- end
41
- end
6
+ include Rkremap::KeyCode
42
7
 
43
8
  rk = Rkremap.new
44
9
  rk.grab = true
45
10
  rk.x11 = true
46
11
 
47
- # 変換/無変換キーを0.5秒以上押してるとALTキーとして扱う。
48
- # 0.5秒以内でも変換/無変換キーを押しながら他のキーを押すとALTキーとして扱う。
49
-
50
- state = {
51
- KEY_HENKAN => State.new,
52
- KEY_MUHENKAN => State.new,
12
+ timer = Tmtms::Timer.new
13
+ jobs = {
14
+ KEY_HENKAN => nil,
15
+ KEY_MUHENKAN => nil,
53
16
  }
54
-
55
17
  henkan_map = {
56
- KEY_HENKAN => KEY_RIGHTALT,
57
- KEY_MUHENKAN => KEY_LEFTALT,
18
+ KEY_HENKAN => KEY_RIGHTMETA,
19
+ KEY_MUHENKAN => KEY_RIGHTMETA, # LEFTMETA だとデスクトップ環境のメニューが開いたりするため
58
20
  }
59
21
 
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
22
+ rk.match(code: [KEY_HENKAN, KEY_MUHENKAN]) do |event|
23
+ if event.type == :press
24
+ job = timer.set(0.5) do
25
+ rk.synchronize do
26
+ rk.event(code: henkan_map[event.code], type: :press)
67
27
  end
68
28
  end
29
+ jobs[event.code] = job
30
+ elsif event.type == :release
31
+ if jobs[event.code]&.cancel
32
+ rk.key(event.code)
33
+ else
34
+ rk.event(code: henkan_map[event.code], type: :release)
35
+ end
69
36
  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
37
  event.skip
87
38
  end
88
39
 
89
40
  rk.match(type: :press) do
90
41
  [KEY_HENKAN, KEY_MUHENKAN].each do |code|
91
- if state[code].pressed?
42
+ if jobs[code]&.cancel
92
43
  rk.event(code: henkan_map[code], type: :press)
93
- state[code].converted = true
94
44
  end
95
45
  end
96
46
  end
@@ -149,26 +99,32 @@ rk.start do |code, mod, app|
149
99
  next
150
100
  end
151
101
 
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})
102
+ # SUPER+[A-Z]/Enter を Ctrl+[A-Z]/Enter に変換
103
+ if (mod[KEY_LEFTMETA] || mod[KEY_RIGHTMETA]) && (Rkremap::CODE_KEY[code] =~ /\AKEY_[A-Z]\z/ || code == KEY_ENTER)
104
+ mod.merge!(mod_disable_meta, {KEY_LEFTCTRL => true})
155
105
  mod[KEY_LEFTCTRL] = true
156
106
  rk.key(code, mod)
157
107
  next
158
108
  end
159
109
 
110
+ # Alt + F, B は Ctrl + →, ← に変換
111
+ if (mod[KEY_LEFTALT] || mod[KEY_RIGHTALT]) && (code == KEY_F || code == KEY_B)
112
+ rk.key(code == KEY_F ? KEY_RIGHT : KEY_LEFT, mod.merge(mod_disable_alt, {KEY_LEFTCTRL => true}))
113
+ next
114
+ end
115
+
160
116
  # Ctrl は他のキーに変換
161
117
  if mod[KEY_LEFTCTRL] || mod[KEY_RIGHTCTRL]
162
- # Ctrl+K は行末まで削除 (日本語変換時はそのまま)
118
+ # Ctrl+I/O はそのまま
119
+ if code == KEY_I || code == KEY_O
120
+ rk.key(code, mod)
121
+ next
122
+ end
123
+ # Ctrl+K は行末まで削除
163
124
  if code == KEY_K
164
- if File.exist?('/tmp/fcitx-enabled')
165
- rk.key(code, mod)
166
- next
167
- else
168
- rk.key(KEY_END, mod_disable_all.merge({KEY_LEFTSHIFT => true}))
169
- rk.key(KEY_X, mod_disable_all.merge({KEY_LEFTCTRL => true}))
170
- next
171
- end
125
+ rk.key(KEY_END, mod_disable_all.merge({KEY_LEFTSHIFT => true}))
126
+ rk.key(KEY_X, mod_disable_all.merge({KEY_LEFTCTRL => true}))
127
+ next
172
128
  end
173
129
  # 単純な変換
174
130
  if ctrl_map[code]
data/lib/rkremap/evdev.rb CHANGED
@@ -8,27 +8,49 @@ class Rkremap
8
8
  EVIOCGBIT_ANY = 2147566880 # EVIOCGBIT(0, 1)
9
9
  EVIOCGBIT_EV_KEY = 2153792801 # EVIOCGBIT(EV_KEY, (KEY_MAX-1)/8+1)
10
10
  EVIOCGRAB = 1074021776
11
+ EVIOCGNAME = 2164278534 # EVIOCGNAME(256)
11
12
 
12
13
  @io2evdev = {}
13
14
  def self.io2evdev
14
15
  @io2evdev
15
16
  end
16
17
 
18
+ @device_list = {}
19
+
17
20
  # @return [Array<Evdev>]
18
- def self.devices
19
- Dir.children("/dev/input").map do |dev|
20
- dev =~ /\Aevent\d+\z/ ? Evdev.new("/dev/input/#{dev}") : nil
21
+ def self.detect
22
+ devs = []
23
+ new_devs = Dir.children("/dev/input").map do |dev|
24
+ if dev =~ /\Aevent\d+\z/
25
+ path = "/dev/input/#{dev}"
26
+ devs.push path
27
+ next if @device_list[path]
28
+ @device_list[path] = true
29
+ Evdev.new(path)
30
+ end
21
31
  end.compact
32
+ (@device_list.keys - devs).each do |path|
33
+ @device_list.delete path
34
+ end
35
+ new_devs
36
+ end
37
+
38
+ def self.remove_device(evdev)
39
+ @io2evdev.delete evdev.io
40
+ @device_list.delete evdev.path
22
41
  end
23
42
 
24
43
  # @param inputs [Array<Evdev>]
44
+ # @param timeout [Numeric]
25
45
  # @return [Evdev]
26
- def self.select(inputs)
27
- h = inputs.map{|ev| [ev.io, ev]}.to_h
28
- r, = IO.select(inputs.map(&:io), nil, nil, nil)
29
- @io2evdev[r[0]]
46
+ def self.select(inputs, timeout)
47
+ r, = IO.select(inputs.map(&:io), nil, nil, timeout)
48
+ r && @io2evdev[r[0]]
30
49
  end
31
50
 
51
+ # @return [String]
52
+ attr_reader :path
53
+
32
54
  # @param path [String]
33
55
  def initialize(path)
34
56
  @path = path
@@ -37,6 +59,10 @@ class Rkremap
37
59
  @uinput = nil
38
60
  end
39
61
 
62
+ def eql?(other)
63
+ other.is_a?(Evdev) && self.path == other.path
64
+ end
65
+
40
66
  # @return [IO]
41
67
  def io
42
68
  return @io if @io
@@ -47,6 +73,7 @@ class Rkremap
47
73
 
48
74
  def close
49
75
  @io&.close
76
+ self.class.remove_device(self)
50
77
  end
51
78
 
52
79
  # @param key [Integer]
@@ -63,6 +90,9 @@ class Rkremap
63
90
  # @return [Boolean]
64
91
  def keyboard?
65
92
  buf = ' '
93
+ io.ioctl(EVIOCGNAME, buf)
94
+ return false if buf =~ /\Arkremap\0*\z/
95
+
66
96
  io.ioctl(EVIOCGBIT_ANY, buf)
67
97
  return false if buf.unpack1('C')[EV_KEY] == 0
68
98
  capable?(KeyCode::KEY_0) && capable?(KeyCode::KEY_9) &&
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Rkremap
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0.1"
5
5
  end
@@ -11,26 +11,26 @@ class Rkremap
11
11
 
12
12
  # @return [Integer] Window
13
13
  def focus_win
14
- win_buf = ' ' * X11.sizeof('Window')
15
- X11.XGetInputFocus(@display, win_buf, @buf)
16
- win_buf.unpack1('L')
14
+ win = X11::Window.malloc(Fiddle::RUBY_FREE)
15
+ X11.XGetInputFocus(@display, win, @buf)
16
+ win.window
17
17
  end
18
18
 
19
19
  # @return [Array<window, name, class>]
20
20
  def app_win(window)
21
21
  return @app_win[window] if @app_win[window]
22
- class_hint = X11::XClassHint.malloc
23
- parent = ' ' * X11.sizeof('Window')
24
- children = ' ' * X11.sizeof('void*')
22
+ class_hint = X11::XClassHint.malloc(Fiddle::RUBY_FREE)
23
+ parent = X11::Window.malloc(Fiddle::RUBY_FREE)
24
+ children = X11::Pointer.malloc(Fiddle::RUBY_FREE)
25
25
  win = window
26
26
  while win > 0
27
27
  class_hint.name = nil
28
28
  class_hint.class_name = nil
29
29
  X11.XGetClassHint(@display, win, class_hint)
30
30
  X11.XQueryTree(@display, win, @buf, parent, children, @buf)
31
- X11.XFree(Fiddle::Pointer[children].ptr)
31
+ X11.XFree(children.ptr)
32
32
  break unless class_hint.name.null? && class_hint.class_name.null?
33
- win = parent.unpack1('L')
33
+ win = parent.window
34
34
  end
35
35
  unless class_hint.name.null?
36
36
  win_name = class_hint.name.to_s
@@ -46,25 +46,27 @@ class Rkremap
46
46
  # @return [String]
47
47
  def app_title(window)
48
48
  win = app_win(window)[0]
49
- prop = X11::XTextProperty.malloc
50
- text_list = ' ' * X11.sizeof('void*')
49
+ prop = X11::XTextProperty.malloc(Fiddle::RUBY_FREE)
50
+ text_list = X11::Pointer.malloc(Fiddle::RUBY_FREE)
51
51
  X11.XGetWMName(@display, win, prop)
52
52
  X11.Xutf8TextPropertyToTextList(@display, prop, text_list, @buf)
53
- title = Fiddle::Pointer[text_list].ptr.ptr.to_s.force_encoding('utf-8')
54
- X11.XFreeStringList(Fiddle::Pointer[text_list].ptr)
53
+ title = text_list.ptr.ptr.to_s.force_encoding('utf-8')
54
+ X11.XFreeStringList(text_list.ptr)
55
55
  title
56
56
  end
57
57
  end
58
58
 
59
59
  module X11
60
60
  extend Fiddle::Importer
61
- dlload 'libX11.so'
61
+ dlload 'libX11.so.6'
62
62
  typealias 'XID', 'unsigned long'
63
63
  typealias 'Window', 'XID'
64
64
  typealias 'Status', 'int'
65
65
  typealias 'Atom', 'unsigned long'
66
- XClassHint = struct(['char *name', 'char *class_name'])
67
- XTextProperty = struct(['unsigned char *value', 'Atom encoding', 'int format', 'unsigned long nitems'])
66
+ Window = struct ['Window window']
67
+ Pointer = struct ['void *ptr']
68
+ XClassHint = struct ['char *name', 'char *class_name']
69
+ XTextProperty = struct ['unsigned char *value', 'Atom encoding', 'int format', 'unsigned long nitems']
68
70
 
69
71
  extern 'Display* XOpenDisplay(char*)'
70
72
  extern 'int XGetInputFocus(Display*, Window*, int*)'
data/lib/rkremap.rb CHANGED
@@ -17,11 +17,17 @@ class Rkremap
17
17
  attr_accessor :grab
18
18
  attr_accessor :modifiers
19
19
  attr_accessor :x11
20
+ attr_accessor :auto_detect
20
21
 
21
22
  # @param devices [Array<String>, String]
22
23
  def initialize(devices=nil)
23
- devices = Array(devices) if devices.is_a? String
24
- @inputs = devices ? devices.map{|d| Evdev.new(d)} : Evdev.devices.select(&:keyboard?)
24
+ if devices
25
+ devices = Array(devices)
26
+ @inputs = devices.map{|d| Evdev.new(d)}
27
+ else
28
+ @auto_detect = true
29
+ @inputs = Evdev.detect.select(&:keyboard?)
30
+ end
25
31
  raise 'Unable to detect keyboard device' if @inputs.empty?
26
32
  @uinput = Uinput.new
27
33
  @grab = false
@@ -43,13 +49,13 @@ class Rkremap
43
49
  end
44
50
 
45
51
  def start(&block)
46
- @mod_state = @modifiers.map{|m| [m, false]}.to_h
52
+ detect_device_loop if @auto_detect
53
+ @mod_state = @modifiers.map.to_h{|m| [m, false]}
47
54
  @winattr = WinAttr.new if @x11
48
55
  @inputs.each(&:grab) if @grab
49
56
  while true
50
57
  @keys = []
51
- input = Evdev.select(@inputs)
52
- time, type, code, value = input.read_event
58
+ time, type, code, value = read_event
53
59
  next if type != EV_KEY
54
60
  event = Event.new(time, code, value, @winattr)
55
61
  @events.each do |cond, b|
@@ -64,6 +70,32 @@ class Rkremap
64
70
  end
65
71
  end
66
72
 
73
+ def detect_device_loop
74
+ Thread.new do
75
+ while true
76
+ sleep 3
77
+ new_devs = Evdev.detect.select(&:keyboard?)
78
+ unless new_devs.empty?
79
+ new_devs.each(&:grab) if @grab
80
+ @inputs += new_devs
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ def read_event
87
+ while true
88
+ begin
89
+ input = Evdev.select(@inputs, 3)
90
+ next unless input
91
+ return input.read_event
92
+ rescue Errno::ENODEV
93
+ input.close rescue nil
94
+ @inputs.delete input
95
+ end
96
+ end
97
+ end
98
+
67
99
  def synchronize(&block)
68
100
  @mutex.synchronize(&block)
69
101
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rkremap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - TOMITA Masahiro
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-01-12 00:00:00.000000000 Z
11
+ date: 2022-07-18 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: key remapper
14
14
  email:
@@ -18,7 +18,7 @@ extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
20
  - README.md
21
- - example/henkan-alt.rb
21
+ - example/henkan-super.rb
22
22
  - example/keylogger.rb
23
23
  - example/mac-shortcut.rb
24
24
  - example/tmtms.rb
@@ -27,12 +27,12 @@ files:
27
27
  - lib/rkremap/keycode.rb
28
28
  - lib/rkremap/version.rb
29
29
  - lib/rkremap/winattr.rb
30
- homepage: https://github.com/tmtm/rkremap
30
+ homepage: https://gitlab.com/tmtms/rkremap
31
31
  licenses:
32
32
  - MIT
33
33
  metadata:
34
- homepage_uri: https://github.com/tmtm/rkremap
35
- source_code_uri: https://github.com/tmtm/rkremap
34
+ homepage_uri: https://gitlab.com/tmtms/rkremap
35
+ source_code_uri: https://gitlab.com/tmtms/rkremap
36
36
  documentation_uri: https://www.rubydoc.info/gems/rkremap
37
37
  rubygems_mfa_required: 'true'
38
38
  post_install_message:
@@ -50,7 +50,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
50
50
  - !ruby/object:Gem::Version
51
51
  version: '0'
52
52
  requirements: []
53
- rubygems_version: 3.3.3
53
+ rubygems_version: 3.3.7
54
54
  signing_key:
55
55
  specification_version: 4
56
56
  summary: key remapper
@@ -1,93 +0,0 @@
1
- # 変換/無変換キーを0.5秒以上押してるとALTキーとして扱う。
2
- # 0.5秒以内でも変換/無変換キーを押しながら他のキーを押すとALTキーとして扱う。
3
-
4
- require 'rkremap'
5
- include Rkremap::KeyCode
6
-
7
- rk = Rkremap.new
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