rkremap 0.5.0 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2052faf03d55e5ca684ee7c991fe42ecb187f2294376216e333d9aced2a45188
4
- data.tar.gz: cc901a01fec47fcafc320ea355c5ea71dd8cc8e54c05f4f7774f02beda3ab328
3
+ metadata.gz: 590e1e170524210ac70556095262d1cda5a7a94330d2aaa2927a644a96a431d0
4
+ data.tar.gz: 97f670607504cac0b34b8e128711eabf8f8a7000edf122350deaf7409d481315
5
5
  SHA512:
6
- metadata.gz: dad24b3679af4213746a787811812afe8791d4964eba2ea018debffb94f7558dec29915a9be18e3aa1952a6817ea6ec823045c0ab8ae45afc9d22649f8c90374
7
- data.tar.gz: 6dbef790e758293b32891d2aabd4cc939b3259b55b5c6d5ed297d2a96ffe9feaeb657675c98b16cd3c73480f3d6f0b35e98f12fadd0d0f41a3020cca894cf069
6
+ metadata.gz: b9932e445cb887e0a4ee4e7b48c9b29767bee3a44936d99e5eb34e6f873a7c0ce24a1edbdea10da5985744ac29c6871d284896c2497ff0ce82407bb8e16eacdf
7
+ data.tar.gz: 8f88809a29fa4d7a407807ddd11c8e570258fcb8f760cf4b285c2e35314e61cd18de0c43516d143a63cfc3f71d778fa5e07e97c5eb204ba5687338572f186545
data/README.md CHANGED
@@ -66,9 +66,10 @@ rkremap.exclude = /touchpad/i
66
66
 
67
67
  正規表現を設定するとデバイス名がマッチした場合にデバイスを grab する。
68
68
 
69
- ### Rkremap#x11
69
+ ### Rkremap#window_system
70
70
 
71
- `true` に設定すると X のアプリ名等を取得できる。X 環境下でないなら `false` を設定する。
71
+ `"x11"` に設定すると X のアプリ名等を取得できる。Wayland 環境では動かない。
72
+ `"kde"`, `"kwin"` に設定すると KDE/Kubuntu 環境でアプリメオ等を取得できる。Wayland 環境でも動作する。
72
73
 
73
74
  ### Rkremap#modifers
74
75
 
@@ -16,8 +16,10 @@ rk.remap(hold: 0.5, map: {
16
16
 
17
17
  # マウスボタンイベントはそのまま
18
18
  rk.match(device: :mouse) do |event|
19
- rk.event(code: event.code, type: event.type)
20
- event.skip
19
+ unless Rkremap::CODE_KEY[event.code] =~ /^KEY_/
20
+ rk.event(code: event.code, type: event.type)
21
+ event.skip
22
+ end
21
23
  end
22
24
 
23
25
  rk.start do |code, mod|
data/example/hoge.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'rkremap'
2
+
3
+ include Rkremap::KeyCode
4
+
5
+ rk = Rkremap.new(*ARGV, mouse: false, exclude: /\AELAN0676/i)
6
+ rk.grab = true
7
+
8
+ rk.remap(KEY_CAPSLOCK => KEY_LEFTCTRL, KEY_MUHENKAN => KEY_LEFTMETA, KEY_HENKAN => KEY_RIGHTMETA)
9
+ rk.remap(KEY_LEFTMETA => [KEY_LEFTSHIFT, KEY_LEFTCTRL])
10
+ rk.match{|ev| rk.event(code: ev.code, type: ev.value); ev.skip }
11
+ rk.start
data/example/tmtms.rb CHANGED
@@ -4,13 +4,9 @@ require 'rkremap'
4
4
 
5
5
  include Rkremap::KeyCode
6
6
 
7
- rk = Rkremap.new(*ARGV, mouse: true, exclude: /\AELAN0676/i)
7
+ rk = Rkremap.new(*ARGV, mouse: true, exclude: /\AELAN0676|\ALenovo TrackPoint Keyboard II/i)
8
8
  rk.grab = true
9
- rk.x11 = true
10
-
11
- # rkremap がシステムに認識されたら中ボタンスクロールを有効にする
12
- sleep 0.1 until system "xinput | grep -q rkremap"
13
- system "xinput set-prop pointer:rkremap 'libinput Scroll Method Enabled' 0 0 1"
9
+ rk.window_system = 'kde'
14
10
 
15
11
  # HENKAN, MUHENKAN を 0.5秒以上押したら SUPER とする
16
12
  rk.remap(hold: 0.5, map: {
@@ -20,8 +16,10 @@ rk.remap(hold: 0.5, map: {
20
16
 
21
17
  # マウスボタンイベントはそのまま
22
18
  rk.match(device: :mouse) do |event|
23
- rk.event(code: event.code, type: event.type)
24
- event.skip
19
+ unless Rkremap::CODE_KEY[event.code] =~ /^KEY_/
20
+ rk.event(code: event.code, type: event.type)
21
+ event.skip
22
+ end
25
23
  end
26
24
 
27
25
  # CAPSLOCK は CTRL に変換
@@ -55,12 +53,26 @@ mod_disable_meta = {
55
53
  }
56
54
  mod_disable_all = {}.merge(mod_disable_ctrl, mod_disable_shift, mod_disable_alt, mod_disable_meta)
57
55
 
58
- # Emacs や VirtualBox ではそのまま
59
- rk.match(app: /Emacs|VirtualBox Machine/) do |event|
56
+ # VirtualBox
57
+ rk.match(app: /VirtualBox Machine/) do |event|
60
58
  rk.event(code: event.code, type: event.type)
61
59
  event.skip
62
60
  end
63
61
 
62
+ # Emacs
63
+ rk.match(app: {class_name: 'Emacs'}) do |event, mod|
64
+ # 修飾キーが Super だけの場合は Alt として扱う。ただしキーが TAB の場合は除く。
65
+ mod_enabled = mod.select{_2}.keys
66
+ if !mod_enabled.empty? && mod_enabled.all?{_1 == KEY_LEFTMETA || _1 == KEY_RIGHTMETA} && event.code != KEY_TAB
67
+ rk.with_modifier(mod_disable_meta.merge(KEY_LEFTALT => true)) do
68
+ rk.event(code: event.code, type: event.type)
69
+ end
70
+ else
71
+ rk.event(code: event.code, type: event.type)
72
+ end
73
+ event.skip
74
+ end
75
+
64
76
  # 端末
65
77
  rk.match(app: /terminal/i) do |event, mod|
66
78
  # Super+Ctrl はそのまま
@@ -83,6 +95,16 @@ rk.match(app: /terminal/i) do |event, mod|
83
95
  event.skip
84
96
  end
85
97
 
98
+ # Firefox で Super+Ctrl+C は Alt+Ctrl+C に変換
99
+ rk.match(app: {class_name: 'firefox'}) do |event, mod|
100
+ if (mod[KEY_LEFTMETA] || mod[KEY_RIGHTMETA]) && (mod[KEY_LEFTCTRL] || mod[KEY_RIGHTCTRL]) && event.code == KEY_C
101
+ rk.with_modifier(mod_disable_meta.merge(KEY_LEFTCTRL => true, KEY_LEFTALT => true)) do
102
+ rk.event(code: event.code, type: event.type)
103
+ end
104
+ event.skip
105
+ end
106
+ end
107
+
86
108
  # その他のウィンドウ
87
109
  ctrl_map = {
88
110
  KEY_A => KEY_HOME,
@@ -108,6 +130,11 @@ rk.start do |code, mod|
108
130
  rk.key(code, mod.merge(mod_disable_meta, KEY_LEFTCTRL => true))
109
131
  next
110
132
  end
133
+ # Super+[←→] を Alt+[←→] に変換
134
+ if (mod[KEY_LEFTMETA] || mod[KEY_RIGHTMETA]) && (Rkremap::CODE_KEY[code] =~ /\AKEY_(LEFT|RIGHT)\z/)
135
+ rk.key(code, mod.merge(mod_disable_meta, KEY_LEFTALT => true))
136
+ next
137
+ end
111
138
 
112
139
  # Alt + F, B は Ctrl + →, ← に変換
113
140
  if (mod[KEY_LEFTALT] || mod[KEY_RIGHTALT]) && (code == KEY_F || code == KEY_B)
data/lib/rkremap/evdev.rb CHANGED
@@ -16,6 +16,7 @@ class Rkremap
16
16
  @capa = nil
17
17
  @uinput = nil
18
18
  @grab = false
19
+ io
19
20
  end
20
21
 
21
22
  def inspect
@@ -35,7 +36,7 @@ class Rkremap
35
36
  # @return [String]
36
37
  def name
37
38
  return @name if @name
38
- buf = ''
39
+ buf = +''
39
40
  io.ioctl(EVIOCGNAME, buf)
40
41
  @name = buf.sub(/\0+$/, '')
41
42
  end
@@ -61,7 +62,7 @@ class Rkremap
61
62
  @is_keyboard = false
62
63
  return false if name =~ /\Arkremap\0*\z/
63
64
 
64
- buf = ''
65
+ buf = +''
65
66
  io.ioctl(EVIOCGBIT_ANY, buf)
66
67
  return false if buf.unpack1('C')[EV_KEY] == 0
67
68
  @is_keyboard = capable?(KeyCode::KEY_0) && capable?(KeyCode::KEY_9) &&
@@ -74,7 +75,7 @@ class Rkremap
74
75
  @is_mouse = false
75
76
  return false if name =~ /\Arkremap\0*\z/
76
77
 
77
- buf = ''
78
+ buf = +''
78
79
  io.ioctl(EVIOCGBIT_ANY, buf)
79
80
  return false if buf.unpack1('C')[EV_KEY] == 0
80
81
  @is_mouse = capable?(KeyCode::BTN_MOUSE)
@@ -56,6 +56,8 @@ class Rkremap
56
56
  stat = 'ignored'
57
57
  end
58
58
  puts "detect: #{ev.name} (#{ev.path}) #{stat}" if $VERBOSE
59
+ rescue => e
60
+ warn "#{e}: #{path}"
59
61
  end
60
62
  end
61
63
 
data/lib/rkremap/event.rb CHANGED
@@ -23,11 +23,15 @@ class Rkremap
23
23
  end
24
24
 
25
25
  def inspect
26
- "#<Rkremap::Event: #{code}(#{CODE_KEY[code]}) #{value} #{device.inspect}>"
26
+ if ev_type == EV_KEY
27
+ "#<Rkremap::Event: #{code}(#{CODE_KEY[code]}) #{value} #{device.inspect}>"
28
+ else
29
+ "#<Rkremap::Event: type: #{ev_type}>"
30
+ end
27
31
  end
28
32
 
29
33
  def type
30
- @type ||= value == 1 ? :press : value == 0 ? :release : :repeat
34
+ value == 1 ? :press : value == 0 ? :release : :repeat
31
35
  end
32
36
 
33
37
  def match?(device:, code:, type:, app:)
data/lib/rkremap/remap.rb CHANGED
@@ -1,5 +1,9 @@
1
1
  class Rkremap
2
2
  class Remap
3
+ def self.timer
4
+ @timer ||= Tmtms::Timer.new
5
+ end
6
+
3
7
  # @param map [Hash] from => to
4
8
  # @param hold [Numeric] seconds
5
9
  def initialize(rk, map:, hold:)
@@ -26,6 +30,10 @@ class Rkremap
26
30
  end
27
31
  end
28
32
 
33
+ @rk.match(code: keycodes, type: :repeat) do |event|
34
+ event.skip
35
+ end
36
+
29
37
  @rk.match(code: keycodes, type: :release) do |event|
30
38
  if @pressed[event.code]
31
39
  @rk.event(code: @pressed[event.code], type: :release)
@@ -39,13 +47,12 @@ class Rkremap
39
47
  # @param hold [Numeric] seconds
40
48
  def setup_holding_event(map, hold)
41
49
  keycodes = map.keys.flatten
42
- timer = Tmtms::Timer.new
43
50
  jobs = map.transform_values{nil}
44
51
 
45
52
  @rk.match(code: keycodes, type: :press) do |event|
46
53
  map.each do |from, to|
47
54
  if from == event.code
48
- jobs[event.code] = timer.set(hold) do
55
+ jobs[event.code] = Remap.timer.set(hold) do
49
56
  @rk.synchronize{ make_press_event(to) }
50
57
  end
51
58
  event.skip
@@ -59,12 +66,17 @@ class Rkremap
59
66
  end
60
67
 
61
68
  @rk.match(code: keycodes, type: :release) do |event|
62
- if jobs[event.code]&.cancel
63
- @rk.key(event.code)
64
- elsif map[event.code]
65
- @rk.event(code: map[event.code], type: :release)
69
+ code = event.code
70
+ if jobs[code]
71
+ if jobs[code].cancel
72
+ event.value = 1
73
+ @rk.append_event(Event.new(event.device, event.time, event.ev_type, event.code, 0))
74
+ elsif map[code]
75
+ event.code = map[code]
76
+ @pressed[code] = nil
77
+ end
78
+ jobs[code] = nil
66
79
  end
67
- event.skip
68
80
  end
69
81
 
70
82
  @rk.match(type: :press) do
@@ -89,17 +101,21 @@ class Rkremap
89
101
  # @param to [Integer, Array<Integer>]
90
102
  # @param event [Rkremap::Event, nil]
91
103
  def make_press_event(to, event=nil)
92
- Array(to).each do |key|
104
+ to = Array(to)
105
+ f = true
106
+ to.each do |key|
93
107
  @pressed[event.code] = key if event
94
108
  if @rk.modifiers.include? key
95
109
  @rk.event(code: key, type: :press)
96
- event&.skip
97
110
  elsif event
98
111
  event.code = key
112
+ f = false
99
113
  else
100
- @rk.key(code: key, type: :press)
114
+ @rk.key(key)
115
+ f = false
101
116
  end
102
117
  end
118
+ event&.skip if f
103
119
  end
104
120
  end
105
121
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Rkremap
4
- VERSION = "0.5.0"
4
+ VERSION = "0.6.0"
5
5
  end
@@ -1,83 +1,19 @@
1
1
  require 'fiddle/import'
2
+ require_relative 'winattr_x11'
3
+ require_relative 'winattr_kde'
2
4
 
3
5
  class Rkremap
4
6
  # アプリの name, class, title を取得する
5
7
  class WinAttr
6
- def initialize
7
- @app_win = {}
8
- @display = X11.XOpenDisplay(nil) or raise "Cannot open display: #{ENV['DISPLAY']}"
9
- @buf = ' '*8
10
- end
11
-
12
- # @return [Integer] Window
13
- def focus_win
14
- win = X11::Window.malloc(Fiddle::RUBY_FREE)
15
- X11.XGetInputFocus(@display, win, @buf)
16
- win.window
17
- end
18
-
19
- # @return [Array<window, name, class>]
20
- def app_win(window)
21
- return @app_win[window] if @app_win[window]
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
- win = window
26
- while win > 0
27
- class_hint.name = nil
28
- class_hint.class_name = nil
29
- X11.XGetClassHint(@display, win, class_hint)
30
- X11.XQueryTree(@display, win, @buf, parent, children, @buf)
31
- X11.XFree(children.ptr)
32
- break unless class_hint.name.null? && class_hint.class_name.null?
33
- win = parent.window
34
- end
35
- unless class_hint.name.null?
36
- win_name = class_hint.name.to_s
37
- X11.XFree(class_hint.name)
38
- end
39
- unless class_hint.class_name.null?
40
- win_class = class_hint.class_name.to_s
41
- X11.XFree(class_hint.class_name)
8
+ def self.for(win_system)
9
+ case win_system.to_s
10
+ when 'x11'
11
+ WinAttrX11.new
12
+ when 'kde', 'kwin', 'kubuntu'
13
+ WinAttrKDE.new
14
+ else
15
+ raise "unknown system: #{win_system}"
42
16
  end
43
- @app_win[window] = [win, win_name, win_class]
44
17
  end
45
-
46
- # @return [String]
47
- def app_title(window)
48
- win = app_win(window)[0]
49
- return '' if win == 0
50
- prop = X11::XTextProperty.malloc(Fiddle::RUBY_FREE)
51
- text_list = X11::Pointer.malloc(Fiddle::RUBY_FREE)
52
- X11.XGetWMName(@display, win, prop)
53
- X11.Xutf8TextPropertyToTextList(@display, prop, text_list, @buf)
54
- ptr = text_list.ptr
55
- return '' if ptr.null?
56
- title = ptr.ptr.to_s.force_encoding('utf-8')
57
- X11.XFreeStringList(text_list.ptr)
58
- title
59
- end
60
- end
61
-
62
- module X11
63
- extend Fiddle::Importer
64
- dlload 'libX11.so.6'
65
- typealias 'XID', 'unsigned long'
66
- typealias 'Window', 'XID'
67
- typealias 'Status', 'int'
68
- typealias 'Atom', 'unsigned long'
69
- Window = struct ['Window window']
70
- Pointer = struct ['void *ptr']
71
- XClassHint = struct ['char *name', 'char *class_name']
72
- XTextProperty = struct ['unsigned char *value', 'Atom encoding', 'int format', 'unsigned long nitems']
73
-
74
- extern 'Display* XOpenDisplay(char*)'
75
- extern 'int XGetInputFocus(Display*, Window*, int*)'
76
- extern 'int XGetClassHint(Display*, Window, XClassHint*)'
77
- extern 'Status XQueryTree(Display*, Window, Window*, Window*, Window**, unsigned int*)'
78
- extern 'Status XGetWMName(Display*, Window, XTextProperty*)'
79
- extern 'int Xutf8TextPropertyToTextList(Display*, XTextProperty*, char***, int*)'
80
- extern 'int XFree(void*)'
81
- extern 'void XFreeStringList(char**)'
82
18
  end
83
19
  end
@@ -0,0 +1,67 @@
1
+ require 'dbus'
2
+
3
+ class Rkremap
4
+ class WinAttrKDE
5
+ attr_reader :focus_win
6
+
7
+ def initialize
8
+ @app_win = {}
9
+
10
+ bus = DBus.session_bus
11
+ kwin_service = bus.service('org.kde.KWin')
12
+ kwin_scripting = kwin_service.object('/Scripting')
13
+ kwin_scripting.introspect
14
+ full_path = File.expand_path('./kwin_script.js', __dir__)
15
+ if kwin_scripting.isScriptLoaded(full_path)[0]
16
+ kwin_scripting.unloadScript(full_path)
17
+ end
18
+ kwin_scripting.loadScript(full_path)
19
+ kwin_scripting.start
20
+
21
+ create_service
22
+ end
23
+
24
+ def class_name(window)
25
+ @app_win[window][:resource_class]
26
+ end
27
+
28
+ def app_title(win_id)
29
+ @app_win[win_id][:caption]
30
+ end
31
+
32
+ def set(id, caption, resource_name, resource_class)
33
+ @app_win[id] = {caption: caption, resource_name: resource_name, resource_class: resource_class}
34
+ @focus_win = id
35
+ end
36
+
37
+ def remove(id)
38
+ @app_win.delete id
39
+ end
40
+
41
+ def create_service
42
+ winattr = self
43
+
44
+ bus = DBus.session_bus
45
+ service = bus.request_service('net.tmtms.Rkremap')
46
+ klass = Class.new(DBus::Object) do
47
+ dbus_interface 'net.tmtms.RkremapInterface' do
48
+ dbus_method :windowActivated, 'in id:s, in caption:s, in resourceName:s, in resourceClass:s' do |id, caption, resource_name, resource_class|
49
+ winattr.set(id, caption, resource_name, resource_class)
50
+ end
51
+ dbus_method :windowRemoved, 'in id:s' do |id|
52
+ winattr.remove(id)
53
+ end
54
+ end
55
+ end
56
+ obj = klass.new('/net/tmtms/Rkremap')
57
+ service.export(obj)
58
+
59
+ Thread.new do
60
+ loop = DBus::Main.new
61
+ loop << bus
62
+ loop.run
63
+ end
64
+ sleep 0.1
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,89 @@
1
+ require 'fiddle/import'
2
+
3
+ class Rkremap
4
+ # アプリの name, class, title を取得する
5
+ class WinAttrX11
6
+ def initialize
7
+ @app_win = {}
8
+ @display = X11.XOpenDisplay(nil) or raise "Cannot open display: #{ENV['DISPLAY']}"
9
+ @buf = ' '*8
10
+ end
11
+
12
+ # @return [Integer] Window
13
+ def focus_win
14
+ win = X11::Window.malloc(Fiddle::RUBY_FREE)
15
+ X11.XGetInputFocus(@display, win, @buf)
16
+ win.window
17
+ end
18
+
19
+ # @return [Array<window, name, class>]
20
+ def app_win(window)
21
+ return @app_win[window] if @app_win[window]
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
+ win = window
26
+ while win > 0
27
+ class_hint.name = nil
28
+ class_hint.class_name = nil
29
+ X11.XGetClassHint(@display, win, class_hint)
30
+ X11.XQueryTree(@display, win, @buf, parent, children, @buf)
31
+ X11.XFree(children.ptr)
32
+ break unless class_hint.name.null? && class_hint.class_name.null?
33
+ win = parent.window
34
+ end
35
+ unless class_hint.name.null?
36
+ win_name = class_hint.name.to_s
37
+ X11.XFree(class_hint.name)
38
+ end
39
+ unless class_hint.class_name.null?
40
+ win_class = class_hint.class_name.to_s
41
+ X11.XFree(class_hint.class_name)
42
+ end
43
+ @app_win[window] = [win, win_name, win_class]
44
+ end
45
+
46
+ # @return [String]
47
+ def class_name(window)
48
+ app_win(window)[2]
49
+ end
50
+
51
+ # @return [String]
52
+ def app_title(window)
53
+ win = app_win(window)[0]
54
+ return '' if win == 0
55
+ prop = X11::XTextProperty.malloc(Fiddle::RUBY_FREE)
56
+ text_list = X11::Pointer.malloc(Fiddle::RUBY_FREE)
57
+ X11.XGetWMName(@display, win, prop)
58
+ X11.Xutf8TextPropertyToTextList(@display, prop, text_list, @buf)
59
+ ptr = text_list.ptr
60
+ return '' if ptr.null?
61
+ title = ptr.ptr.to_s.force_encoding('utf-8')
62
+ X11.XFreeStringList(text_list.ptr)
63
+ title
64
+ end
65
+ end
66
+
67
+ module X11
68
+ extend Fiddle::Importer
69
+
70
+ dlload 'libX11.so.6'
71
+ typealias 'XID', 'unsigned long'
72
+ typealias 'Window', 'XID'
73
+ typealias 'Status', 'int'
74
+ typealias 'Atom', 'unsigned long'
75
+ Window = struct ['Window window']
76
+ Pointer = struct ['void *ptr']
77
+ XClassHint = struct ['char *name', 'char *class_name']
78
+ XTextProperty = struct ['unsigned char *value', 'Atom encoding', 'int format', 'unsigned long nitems']
79
+
80
+ extern 'Display* XOpenDisplay(char*)'
81
+ extern 'int XGetInputFocus(Display*, Window*, int*)'
82
+ extern 'int XGetClassHint(Display*, Window, XClassHint*)'
83
+ extern 'Status XQueryTree(Display*, Window, Window*, Window*, Window**, unsigned int*)'
84
+ extern 'Status XGetWMName(Display*, Window, XTextProperty*)'
85
+ extern 'int Xutf8TextPropertyToTextList(Display*, XTextProperty*, char***, int*)'
86
+ extern 'int XFree(void*)'
87
+ extern 'void XFreeStringList(char**)'
88
+ end
89
+ end
data/lib/rkremap.rb CHANGED
@@ -29,6 +29,7 @@ class Rkremap
29
29
  attr_accessor :grab
30
30
  attr_accessor :modifiers
31
31
  attr_accessor :x11
32
+ attr_accessor :window_system
32
33
  attr_accessor :auto_detect
33
34
  attr_accessor :exclude
34
35
  attr_accessor :mouse
@@ -48,6 +49,7 @@ class Rkremap
48
49
  @uinput = Uinput.new
49
50
  @grab = false
50
51
  @x11 = false
52
+ @window_system = @x11 ? 'x11' : nil # 'x11' or 'kde'
51
53
  @modifiers = [
52
54
  KEY_LEFTCTRL, KEY_RIGHTCTRL,
53
55
  KEY_LEFTSHIFT, KEY_RIGHTSHIFT,
@@ -82,10 +84,12 @@ class Rkremap
82
84
  @evdev_list.grab = @grab
83
85
  @evdev_list.detect_loop
84
86
  @mod_state = @modifiers.map.to_h{|m| [m, false]}
85
- winattr = WinAttr.new if @x11
87
+ @window_system = 'x11' if @x11
88
+ winattr = WinAttr.for(@window_system) if @window_system
89
+ @events = []
86
90
  while true
87
91
  @keys = []
88
- event = @evdev_list.read_event
92
+ event = @events.shift || @evdev_list.read_event
89
93
  if event.ev_type != EV_KEY
90
94
  if event.device.grab?
91
95
  @uinput.write_event(event.ev_type, event.code, event.value)
@@ -133,11 +137,17 @@ class Rkremap
133
137
  write_event(mcode, state ? 1 : 0)
134
138
  end
135
139
  block.call
136
- mod_diff(mod).each do |mcode, _|
140
+ mod_diff(mod).each_key do |mcode|
137
141
  write_event(mcode, @mod_state[mcode] ? 1 : 0)
138
142
  end
139
143
  end
140
144
 
145
+ # @param event [Rkremap::Event]
146
+ def append_event(event)
147
+ @events.push event
148
+ @events.push Event.new(event.device, event.time, EV_SYN, SYN_REPORT, 0)
149
+ end
150
+
141
151
  private
142
152
 
143
153
  def update_modifiers(code, value)
@@ -179,7 +189,7 @@ class Rkremap
179
189
 
180
190
  # @return [String, nil]
181
191
  def class_name
182
- @winattr.app_win(@win)[2] if @winattr && @win
192
+ @winattr.class_name(@win) if @winattr && @win
183
193
  end
184
194
 
185
195
  # @return [String, nil]
@@ -190,7 +200,7 @@ class Rkremap
190
200
  # @param app [Array, Hash, String, Regexp]
191
201
  # @return [Boolean]
192
202
  def match?(app)
193
- Array(app).each do |a|
203
+ [app].flatten.each do |a|
194
204
  a = {class_name: a, title: a} unless a.is_a? Hash
195
205
  return true if match_sub(a[:class_name], class_name) || match_sub(a[:title], title)
196
206
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rkremap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - TOMITA Masahiro
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2022-09-04 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: tmtms_timer
@@ -33,6 +32,7 @@ extra_rdoc_files: []
33
32
  files:
34
33
  - README.md
35
34
  - example/henkan-super.rb
35
+ - example/hoge.rb
36
36
  - example/keylogger.rb
37
37
  - example/mac-shortcut.rb
38
38
  - example/tmtms.rb
@@ -45,6 +45,8 @@ files:
45
45
  - lib/rkremap/uinput.rb
46
46
  - lib/rkremap/version.rb
47
47
  - lib/rkremap/winattr.rb
48
+ - lib/rkremap/winattr_kde.rb
49
+ - lib/rkremap/winattr_x11.rb
48
50
  homepage: https://gitlab.com/tmtms/rkremap
49
51
  licenses:
50
52
  - MIT
@@ -53,7 +55,6 @@ metadata:
53
55
  source_code_uri: https://gitlab.com/tmtms/rkremap
54
56
  documentation_uri: https://www.rubydoc.info/gems/rkremap
55
57
  rubygems_mfa_required: 'true'
56
- post_install_message:
57
58
  rdoc_options: []
58
59
  require_paths:
59
60
  - lib
@@ -68,8 +69,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
68
69
  - !ruby/object:Gem::Version
69
70
  version: '0'
70
71
  requirements: []
71
- rubygems_version: 3.3.7
72
- signing_key:
72
+ rubygems_version: 3.7.0.dev
73
73
  specification_version: 4
74
74
  summary: key remapper
75
75
  test_files: []