dotremap 0.0.3 → 0.0.4

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
  SHA1:
3
- metadata.gz: b583b2e6288717148abe4fdaf0a0005ee4e44d7b
4
- data.tar.gz: 56162121e591fce2c2df10404fa8f058204f261e
3
+ metadata.gz: f7239e13995fda02fc4fa7d3aadb9b7a23ab7efa
4
+ data.tar.gz: beea8d31a99eddca3b13e18a28a68a3103493ea2
5
5
  SHA512:
6
- metadata.gz: 6152e932f2ce3581d3bec446abb8697f9607a381e03c3b321e7ed1ef10091ed191ae693e85411c40c927cad8e34be869dbad70dd28d2c0bacf8218b7fbd0b407
7
- data.tar.gz: de087ee48dac92eb7f479830e196e3b6fe63dc828d7784f1531fcd6489a086dd423b1907b23f6574b0cc1a77487fa2b38d075a64a96c970446fc17f80870289f
6
+ metadata.gz: 0611d804ba6284b53ae62a75db22159a054f964be1ba9be6d12af307b9605bedcd84bade9a75fdd7ceedef77339a5d167f21a0af270bf09938929285f6a6590e
7
+ data.tar.gz: e9a66f62416f43b44675ff615ae02d395bb8bd00abd43b41561330f46c1fb8a5e8822749659110299e8307188e2b3d801f77d49700ce3f951607277012ebf506
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ -c
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ rvm:
2
+ - 2.1.2
3
+ branches:
4
+ only:
5
+ - master
6
+ script:
7
+ - 'bundle exec rspec .'
data/README.md CHANGED
@@ -1,10 +1,22 @@
1
- # Dotremap
1
+ # Dotremap [![Build Status](https://travis-ci.org/k0kubun/dotremap.png?branch=master)](https://travis-ci.org/k0kubun/dotremap)
2
2
 
3
- Lightweight configuration DSL for [KeyRemap4MacBook](https://pqrs.org/osx/karabiner/index.html)
3
+ Lightweight keyremap configuration DSL for [Karabiner](https://pqrs.org/osx/karabiner/index.html.en)
4
+
5
+ ## Why dotremap?
6
+
7
+ Original [Karabiner's configuration](https://pqrs.org/osx/karabiner/xml.html.ja) is very hard to write.
8
+ Dotremap's DSL is its wrapper, which is easy-to-write and readable.
9
+
10
+ If you write Karabiner's config by dotremap, you can update your keyremap configuration quickly.
4
11
 
5
12
  ## Installation
6
13
 
7
- ````bash
14
+ First of all, you have to install [Karabiner](https://pqrs.org/osx/karabiner/index.html.en).
15
+ Karabiner is a keyboard remap utility for Mac OSX.
16
+
17
+ Then execute:
18
+
19
+ ```bash
8
20
  $ gem install dotremap
9
21
  ```
10
22
 
@@ -12,12 +24,8 @@ $ gem install dotremap
12
24
  ### 1. Create ~/.remap
13
25
 
14
26
  ```rb
15
- # ~/.remap
16
- item "Control+PNBF to Up/Down/Left/Right", not: "TERMINAL" do
17
- remap "C-p", to: "Up"
18
- remap "C-n", to: "Down"
19
- remap "C-b", to: "Left"
20
- remap "C-f", to: "Right"
27
+ item "Command+G to open Google Chrome" do
28
+ remap "Cmd-g", to: invoke("Google Chrome")
21
29
  end
22
30
  ```
23
31
 
@@ -27,30 +35,89 @@ end
27
35
  $ dotremap
28
36
  ```
29
37
 
30
- It will replace KeyRemap4MacBook's private.xml with compiled ~/.remap:
31
-
32
- ```xml
33
- <?xml version="1.0"?>
34
- <root>
35
- <item>
36
- <name>Control+PNBF to Up/Down/Left/Right</name>
37
- <identifier>remap.control_pnbf_to_up_down_left_right</identifier>
38
- <not>TERMINAL</not>
39
- <autogen>__KeyToKey__ KeyCode::P, VK_CONTROL, KeyCode::CURSOR_UP</autogen>
40
- <autogen>__KeyToKey__ KeyCode::N, VK_CONTROL, KeyCode::CURSOR_DOWN</autogen>
41
- <autogen>__KeyToKey__ KeyCode::B, VK_CONTROL, KeyCode::CURSOR_LEFT</autogen>
42
- <autogen>__KeyToKey__ KeyCode::F, VK_CONTROL, KeyCode::CURSOR_RIGHT</autogen>
43
- </item>
44
- </root>
38
+ Then dotremap will update Karabiner's config as you expected.
39
+
40
+ ![](https://raw.githubusercontent.com/k0kubun/dotremap/master/img/disabled.png)
41
+
42
+ ### 3. Enable your favorite configurations
43
+
44
+ ![](https://raw.githubusercontent.com/k0kubun/dotremap/master/img/enabled.png)
45
+
46
+ Enjoy!
47
+
48
+ ## How to write ~/.remap
49
+ ### Basics
50
+
51
+ Dotremap's DSL is a superset of Ruby.
52
+ So you can use any Ruby methods in ~/.remap.
53
+
54
+ #### item
55
+
56
+ ```rb
57
+ item "configuration unit" do
58
+ ...
59
+ end
45
60
  ```
46
61
 
47
- dotremap will automatically execute "ReloadXML".
48
- Then activate your favorite configurations.
62
+ In dotremap, any Karabiner's configuration unit is expressed in `item` and its `do ~ end` block.
63
+ You can group some remap configurations in one item and enable them in one click.
64
+
65
+ #### remap
66
+
67
+ ```rb
68
+ item "remap example" do
69
+ remap "Cmd-a", to: "C-a"
70
+ end
71
+ ```
72
+
73
+ If you want to add remap configuration, you have to call `remap` method.
74
+ In this example, Command+A will be remapped to Control+A.
75
+
76
+ You have to write "key expression" to specify keys to remap.
77
+
78
+ #### key expression
79
+
80
+ - `a`, `A`, `1`, `;`, `tab`, `Tab`, `space`, `up`, `down`
81
+ - any string without `-` will be regarded as single key
82
+ - ignore upcase or downcase
83
+ - `C-a`, `Ctrl-a`
84
+ - regarded as Control + A
85
+ - `C-` is a short expression of `Ctrl-`
86
+ - `M-a`, `Opt-a`
87
+ - regarded as Option + A
88
+ - `Shift-a`
89
+ - regarded as large A
90
+ - if you write just `A`, it will be regarded as small a
91
+ - `Cmd-a`
92
+ - regarded as Command + A
93
+ - `Cmd-Shift-a`
94
+ - regarded as Command + Shift + A
95
+ - you can use any combination of Ctrl, Opt, Shift, Cmd
96
+
97
+ #### available single keys
98
+
99
+ ```
100
+ a b c ... x y z
101
+ 0 1 2 ... 7 8 9
102
+ F1 F2 ... F11 F12
103
+ \ [ ] ; ' , . / - =
104
+ Up Down Right Left
105
+ space tab delete forward_delete capslock
106
+
107
+ Ctrl_R Ctrl_L
108
+ Opt_R Opt_L
109
+ Cmd_R Cmd_L
110
+ ```
111
+
112
+ ### Advanced usage
113
+
114
+ I'm sorry but currently some features are not documented here.
115
+ You can see [my ~/.remap](https://github.com/k0kubun/dotfiles/blob/master/.remap.rb) or
116
+ [dotremap's spec files](https://github.com/k0kubun/dotremap/tree/master/spec/lib).
49
117
 
50
- ## Example
118
+ ## TODO
51
119
 
52
- I'm sorry but currently this software is not well documented.
53
- Please see [example.rb](https://github.com/k0kubun/dotremap/blob/master/example.rb) to learn how to use.
120
+ - Document all features in this README
54
121
 
55
122
  ## Contributing
56
123
 
data/dotremap.gemspec CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Dotremap::VERSION
9
9
  spec.authors = ["Takashi Kokubun"]
10
10
  spec.email = ["takashikkbn@gmail.com"]
11
- spec.summary = %q{Configuration DSL for KeyRemap4MacBook}
12
- spec.description = %q{Configuration DSL for KeyRemap4MacBook}
11
+ spec.summary = %q{Lightweight keyremap configuration DSL}
12
+ spec.description = %q{Lightweight keyremap configuration DSL for Karabiner}
13
13
  spec.homepage = "https://github.com/k0kubun/dotremap"
14
14
  spec.license = "MIT"
15
15
 
@@ -19,6 +19,8 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_development_dependency "bundler"
22
- spec.add_development_dependency "rake"
22
+ spec.add_development_dependency "rake", "~> 10.3.2"
23
+ spec.add_development_dependency "rspec", "~> 3.0.0"
24
+ spec.add_development_dependency "pry"
23
25
  spec.add_dependency 'unindent', '~> 1.0'
24
26
  end
data/img/disabled.png ADDED
Binary file
data/img/enabled.png ADDED
Binary file
data/lib/dotremap.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require "dotremap/karabiner"
1
2
  require "dotremap/version"
2
3
  require "dotremap/root"
3
4
  require "unindent"
@@ -5,11 +6,7 @@ require "fileutils"
5
6
 
6
7
  class Dotremap
7
8
  XML_FILE_NAME = "private.xml"
8
- OLD_XML_DIR = File.expand_path("~/Library/Application Support/KeyRemap4MacBook")
9
- NEW_XML_DIR = File.expand_path("~/Library/Application Support/Karabiner")
10
- OLD_APP_PATH = "/Applications/KeyRemap4MacBook.app"
11
- NEW_APP_PATH = "/Applications/Karabiner.app"
12
- RELOAD_XML_PATH = "Contents/Applications/Utilities/ReloadXML.app"
9
+ XML_DIR = File.expand_path("~/Library/Application Support/Karabiner")
13
10
 
14
11
  def initialize(config_path)
15
12
  @config_path = config_path
@@ -18,38 +15,18 @@ class Dotremap
18
15
 
19
16
  def apply_configuration
20
17
  replace_private_xml
21
- reload_xml
18
+ Karabiner.reload_xml
19
+
22
20
  puts "Successfully updated Karabiner configuration"
23
21
  end
24
22
 
25
23
  private
26
24
 
27
25
  def replace_private_xml
28
- ensure_xml_dir_existence
29
- remove_current_xml
30
- write_new_xml
31
- end
32
-
33
- def reload_xml
34
- app_path = File.exists?(OLD_APP_PATH) ? OLD_APP_PATH : NEW_APP_PATH
35
- reload_xml_path = File.join(app_path, RELOAD_XML_PATH)
36
-
37
- system("open #{reload_xml_path}")
38
- end
39
-
40
- def ensure_xml_dir_existence
41
- FileUtils.mkdir_p(OLD_XML_DIR)
42
- FileUtils.mkdir_p(NEW_XML_DIR)
43
- end
44
-
45
- def remove_current_xml
46
- FileUtils.rm_f(File.join(OLD_XML_DIR, XML_FILE_NAME))
47
- FileUtils.rm_f(File.join(NEW_XML_DIR, XML_FILE_NAME))
48
- end
26
+ FileUtils.mkdir_p(XML_DIR)
49
27
 
50
- def write_new_xml
51
- File.write(File.join(OLD_XML_DIR, XML_FILE_NAME), new_xml)
52
- File.write(File.join(NEW_XML_DIR, XML_FILE_NAME), new_xml)
28
+ xml_path = File.join(XML_DIR, XML_FILE_NAME)
29
+ File.write(xml_path, new_xml)
53
30
  end
54
31
 
55
32
  def new_xml
@@ -59,7 +36,7 @@ class Dotremap
59
36
  root = Root.new
60
37
  config = File.read(config_path)
61
38
  root.instance_eval(config)
62
- @new_xml = root.to_xml.gsub(/ *$/, "")
39
+ @new_xml = root.to_xml.gsub(/ *$/, "").concat("\n")
63
40
  end
64
41
 
65
42
  def validate_config_existence
@@ -18,8 +18,10 @@ class Dotremap::Appdef
18
18
  def to_xml
19
19
  [
20
20
  "<appdef>",
21
- " <appname>#{@appname}</appname>",
22
- @childs.map(&:to_xml).join("\n").gsub(/^/, " "),
21
+ [
22
+ "<appname>#{@appname}</appname>",
23
+ *@childs.map(&:to_xml),
24
+ ].join("\n").gsub(/^/, " "),
23
25
  "</appdef>",
24
26
  ].join("\n")
25
27
  end
@@ -0,0 +1,7 @@
1
+ module Dotremap::Karabiner
2
+ CLI_PATH = "/Applications/Karabiner.app/Contents/Library/bin/karabiner"
3
+
4
+ def self.reload_xml
5
+ system("#{CLI_PATH} reloadxml")
6
+ end
7
+ end
@@ -0,0 +1,85 @@
1
+ class Dotremap::Key
2
+ KEYCODE_MAP = {
3
+ "0" => "KEY_0",
4
+ "1" => "KEY_1",
5
+ "2" => "KEY_2",
6
+ "3" => "KEY_3",
7
+ "4" => "KEY_4",
8
+ "5" => "KEY_5",
9
+ "6" => "KEY_6",
10
+ "7" => "KEY_7",
11
+ "8" => "KEY_8",
12
+ "9" => "KEY_9",
13
+ "Up" => "CURSOR_UP",
14
+ "Down" => "CURSOR_DOWN",
15
+ "Right" => "CURSOR_RIGHT",
16
+ "Left" => "CURSOR_LEFT",
17
+ "]" => "BRACKET_RIGHT",
18
+ "[" => "BRACKET_LEFT",
19
+ ";" => "SEMICOLON",
20
+ "-" => "MINUS",
21
+ "," => "COMMA",
22
+ "." => "DOT",
23
+ "\\" => "BACKSLASH",
24
+ "/" => "SLASH",
25
+ "=" => "EQUAL",
26
+ "'" => "QUOTE",
27
+ "Ctrl_R" => "CONTROL_R",
28
+ "Ctrl_L" => "CONTROL_L",
29
+ "Opt_R" => "OPTION_R",
30
+ "Opt_L" => "OPTION_L",
31
+ "Cmd_R" => "COMMAND_R",
32
+ "Cmd_L" => "COMMAND_L",
33
+ }.freeze
34
+ PREFIX_MAP = {
35
+ "C" => "VK_CONTROL",
36
+ "Ctrl" => "VK_CONTROL",
37
+ "Cmd" => "VK_COMMAND",
38
+ "Shift" => "VK_SHIFT",
39
+ "M" => "VK_OPTION",
40
+ "Opt" => "VK_OPTION",
41
+ }.freeze
42
+ PREFIX_EXPRESSION = "(#{PREFIX_MAP.keys.map { |k| k + '-' }.join('|')})"
43
+
44
+ def initialize(expression)
45
+ @expression = expression
46
+ end
47
+
48
+ def to_s
49
+ key_combination(@expression)
50
+ end
51
+
52
+ private
53
+
54
+ def key_combination(raw_combination)
55
+ raw_prefixes, raw_key = split_key_combination(raw_combination)
56
+ return key_expression(raw_key) if raw_prefixes.empty?
57
+
58
+ prefixes = raw_prefixes.map { |raw_prefix| PREFIX_MAP[raw_prefix] }
59
+ "#{key_expression(raw_key)}, #{prefixes.join(' | ')}"
60
+ end
61
+
62
+ def key_expression(raw_key)
63
+ case raw_key
64
+ when /^(#{KEYCODE_MAP.keys.map { |k| Regexp.escape(k) }.join('|')})$/
65
+ "KeyCode::#{KEYCODE_MAP[raw_key]}"
66
+ else
67
+ raw_key = raw_key.upcase unless raw_key.match(/^VK_/)
68
+ "KeyCode::#{raw_key}"
69
+ end
70
+ end
71
+
72
+ def split_key_combination(raw_combination)
73
+ prefixes = []
74
+ key = raw_combination.dup
75
+
76
+ while key.match(/^#{PREFIX_EXPRESSION}/)
77
+ key.gsub!(/^#{PREFIX_EXPRESSION}/) do
78
+ prefixes << $1.gsub(/-$/, "")
79
+ ""
80
+ end
81
+ end
82
+
83
+ [prefixes, key]
84
+ end
85
+ end
@@ -1,46 +1,6 @@
1
- class Dotremap::Remap
2
- KEYCODE_MAP = {
3
- "0" => "KEY_0",
4
- "1" => "KEY_1",
5
- "2" => "KEY_2",
6
- "3" => "KEY_3",
7
- "4" => "KEY_4",
8
- "5" => "KEY_5",
9
- "6" => "KEY_6",
10
- "7" => "KEY_7",
11
- "8" => "KEY_8",
12
- "9" => "KEY_9",
13
- "Up" => "CURSOR_UP",
14
- "Down" => "CURSOR_DOWN",
15
- "Right" => "CURSOR_RIGHT",
16
- "Left" => "CURSOR_LEFT",
17
- "]" => "BRACKET_RIGHT",
18
- "[" => "BRACKET_LEFT",
19
- ";" => "SEMICOLON",
20
- "-" => "MINUS",
21
- "," => "COMMA",
22
- "." => "DOT",
23
- "\\" => "BACKSLASH",
24
- "/" => "SLASH",
25
- "=" => "EQUAL",
26
- "'" => "QUOTE",
27
- "Ctrl_R" => "CONTROL_R",
28
- "Ctrl_L" => "CONTROL_L",
29
- "Opt_R" => "OPTION_R",
30
- "Opt_L" => "OPTION_L",
31
- "Cmd_R" => "COMMAND_R",
32
- "Cmd_L" => "COMMAND_L",
33
- }.freeze
34
- PREFIX_MAP = {
35
- "C" => "VK_CONTROL",
36
- "Ctrl" => "VK_CONTROL",
37
- "Cmd" => "VK_COMMAND",
38
- "Shift" => "VK_SHIFT",
39
- "M" => "VK_OPTION",
40
- "Opt" => "VK_OPTION",
41
- }.freeze
42
- PREFIX_EXPRESSION = "(#{PREFIX_MAP.keys.map { |k| k + '-' }.join('|')})"
1
+ require "dotremap/key"
43
2
 
3
+ class Dotremap::Remap
44
4
  def initialize(from, to)
45
5
  @from = from
46
6
  @to = to
@@ -53,42 +13,10 @@ class Dotremap::Remap
53
13
  private
54
14
 
55
15
  def from
56
- key_combination(@from)
16
+ Dotremap::Key.new(@from)
57
17
  end
58
18
 
59
19
  def to
60
- [@to].flatten.map { |to| key_combination(to) }.join(", ")
61
- end
62
-
63
- def key_combination(raw_combination)
64
- raw_prefixes, raw_key = split_key_combination(raw_combination)
65
- return key_expression(raw_key) if raw_prefixes.empty?
66
-
67
- prefixes = raw_prefixes.map { |raw_prefix| PREFIX_MAP[raw_prefix] }
68
- "#{key_expression(raw_key)}, #{prefixes.join(' | ')}"
69
- end
70
-
71
- def key_expression(raw_key)
72
- case raw_key
73
- when /^(#{KEYCODE_MAP.keys.map { |k| Regexp.escape(k) }.join('|')})$/
74
- "KeyCode::#{KEYCODE_MAP[raw_key]}"
75
- else
76
- raw_key = raw_key.upcase unless raw_key.match(/^VK_/)
77
- "KeyCode::#{raw_key}"
78
- end
79
- end
80
-
81
- def split_key_combination(raw_combination)
82
- prefixes = []
83
- key = raw_combination.dup
84
-
85
- while key.match(/^#{PREFIX_EXPRESSION}/)
86
- key.gsub!(/^#{PREFIX_EXPRESSION}/) do
87
- prefixes << $1.gsub(/-$/, "")
88
- ""
89
- end
90
- end
91
-
92
- [prefixes, key]
20
+ [@to].flatten.map { |to| Dotremap::Key.new(to) }.join(", ")
93
21
  end
94
22
  end
data/lib/dotremap/root.rb CHANGED
@@ -13,9 +13,11 @@ class Dotremap::Root
13
13
  [
14
14
  "<?xml version=\"1.0\"?>",
15
15
  "<root>",
16
- childs.map(&:to_xml).join("\n\n").gsub(/^/, " "),
17
- Dotremap::Openurl.registered_xml.gsub(/^/, " "),
16
+ [
17
+ childs.map(&:to_xml).join("\n\n"),
18
+ Dotremap::Openurl.registered_xml,
19
+ ].compact.join("\n").gsub(/^/, " "),
18
20
  "</root>",
19
- ].compact.join("\n")
21
+ ].join("\n")
20
22
  end
21
23
  end
@@ -1,3 +1,3 @@
1
1
  class Dotremap
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -0,0 +1,35 @@
1
+ require "spec_helper"
2
+
3
+ describe Dotremap::Appdef do
4
+ describe "#to_xml" do
5
+ it "returns valid xml from appdef with equal" do
6
+ appdef = Dotremap::Appdef.new("CHROME", equal: "com.google.Chrome")
7
+ expect(appdef.to_xml).to eq(<<-EOS.unindent.strip)
8
+ <appdef>
9
+ <appname>CHROME</appname>
10
+ <equal>com.google.Chrome</equal>
11
+ </appdef>
12
+ EOS
13
+ end
14
+
15
+ it "returns valid xml from appdef with prefix" do
16
+ appdef = Dotremap::Appdef.new("CHROME", prefix: "com")
17
+ expect(appdef.to_xml).to eq(<<-EOS.unindent.strip)
18
+ <appdef>
19
+ <appname>CHROME</appname>
20
+ <prefix>com</prefix>
21
+ </appdef>
22
+ EOS
23
+ end
24
+
25
+ it "returns valid xml from appdef with suffix" do
26
+ appdef = Dotremap::Appdef.new("CHROME", suffix: "Chrome")
27
+ expect(appdef.to_xml).to eq(<<-EOS.unindent.strip)
28
+ <appdef>
29
+ <appname>CHROME</appname>
30
+ <suffix>Chrome</suffix>
31
+ </appdef>
32
+ EOS
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,111 @@
1
+ require "spec_helper"
2
+
3
+ describe Dotremap::Key do
4
+ describe "#to_s" do
5
+ EXPECTED_RESULTS = {
6
+ "a" => "KeyCode::A",
7
+ "b" => "KeyCode::B",
8
+ "c" => "KeyCode::C",
9
+ "d" => "KeyCode::D",
10
+ "e" => "KeyCode::E",
11
+ "f" => "KeyCode::F",
12
+ "g" => "KeyCode::G",
13
+ "h" => "KeyCode::H",
14
+ "i" => "KeyCode::I",
15
+ "j" => "KeyCode::J",
16
+ "k" => "KeyCode::K",
17
+ "l" => "KeyCode::L",
18
+ "m" => "KeyCode::M",
19
+ "n" => "KeyCode::N",
20
+ "o" => "KeyCode::O",
21
+ "p" => "KeyCode::P",
22
+ "q" => "KeyCode::Q",
23
+ "r" => "KeyCode::R",
24
+ "s" => "KeyCode::S",
25
+ "t" => "KeyCode::T",
26
+ "u" => "KeyCode::U",
27
+ "v" => "KeyCode::V",
28
+ "w" => "KeyCode::W",
29
+ "x" => "KeyCode::X",
30
+ "y" => "KeyCode::Y",
31
+ "z" => "KeyCode::Z",
32
+ "A" => "KeyCode::A",
33
+ "B" => "KeyCode::B",
34
+ "C" => "KeyCode::C",
35
+ "D" => "KeyCode::D",
36
+ "E" => "KeyCode::E",
37
+ "F" => "KeyCode::F",
38
+ "G" => "KeyCode::G",
39
+ "H" => "KeyCode::H",
40
+ "I" => "KeyCode::I",
41
+ "J" => "KeyCode::J",
42
+ "K" => "KeyCode::K",
43
+ "L" => "KeyCode::L",
44
+ "M" => "KeyCode::M",
45
+ "N" => "KeyCode::N",
46
+ "O" => "KeyCode::O",
47
+ "P" => "KeyCode::P",
48
+ "Q" => "KeyCode::Q",
49
+ "R" => "KeyCode::R",
50
+ "S" => "KeyCode::S",
51
+ "T" => "KeyCode::T",
52
+ "U" => "KeyCode::U",
53
+ "V" => "KeyCode::V",
54
+ "W" => "KeyCode::W",
55
+ "X" => "KeyCode::X",
56
+ "Y" => "KeyCode::Y",
57
+ "Z" => "KeyCode::Z",
58
+ "0" => "KeyCode::KEY_0",
59
+ "1" => "KeyCode::KEY_1",
60
+ "2" => "KeyCode::KEY_2",
61
+ "3" => "KeyCode::KEY_3",
62
+ "4" => "KeyCode::KEY_4",
63
+ "5" => "KeyCode::KEY_5",
64
+ "6" => "KeyCode::KEY_6",
65
+ "7" => "KeyCode::KEY_7",
66
+ "8" => "KeyCode::KEY_8",
67
+ "9" => "KeyCode::KEY_9",
68
+ "Up" => "KeyCode::CURSOR_UP",
69
+ "Down" => "KeyCode::CURSOR_DOWN",
70
+ "Right" => "KeyCode::CURSOR_RIGHT",
71
+ "Left" => "KeyCode::CURSOR_LEFT",
72
+ "]" => "KeyCode::BRACKET_RIGHT",
73
+ "[" => "KeyCode::BRACKET_LEFT",
74
+ ";" => "KeyCode::SEMICOLON",
75
+ "-" => "KeyCode::MINUS",
76
+ "," => "KeyCode::COMMA",
77
+ "." => "KeyCode::DOT",
78
+ "\\" => "KeyCode::BACKSLASH",
79
+ "/" => "KeyCode::SLASH",
80
+ "=" => "KeyCode::EQUAL",
81
+ "'" => "KeyCode::QUOTE",
82
+ "Ctrl_R" => "KeyCode::CONTROL_R",
83
+ "Ctrl_L" => "KeyCode::CONTROL_L",
84
+ "Opt_R" => "KeyCode::OPTION_R",
85
+ "Opt_L" => "KeyCode::OPTION_L",
86
+ "Cmd_R" => "KeyCode::COMMAND_R",
87
+ "Cmd_L" => "KeyCode::COMMAND_L",
88
+ }.freeze
89
+
90
+ it "converts single key expression as expected" do
91
+ EXPECTED_RESULTS.each do |expression, result|
92
+ expect(described_class.new(expression).to_s).to eq(result)
93
+ end
94
+ end
95
+
96
+ it "converts double key combination as expected" do
97
+ Dotremap::Key::PREFIX_MAP.each do |prefix, vk|
98
+ key, keycode = EXPECTED_RESULTS.to_a.sample
99
+ expect(described_class.new("#{prefix}-#{key}").to_s).to eq("#{keycode}, #{vk}")
100
+ end
101
+ end
102
+
103
+ it "converts triple key combination as expected" do
104
+ key, keycode = EXPECTED_RESULTS.to_a.sample
105
+ unique_maps = Dotremap::Key::PREFIX_MAP.to_a.sort_by { rand }.uniq { |a| a[1] }
106
+ unique_maps.combination(2) do |(prefix1, vk1), (prefix2, vk2)|
107
+ expect(described_class.new("#{prefix1}-#{prefix2}-#{key}").to_s).to eq("#{keycode}, #{vk1} | #{vk2}")
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,10 @@
1
+ require "spec_helper"
2
+
3
+ describe Dotremap::Remap do
4
+ describe "#to_xml" do
5
+ it "converts key remap to autogen tag" do
6
+ expect(Dotremap::Remap.new("Cmd-Shift-]", "Opt-Ctrl-Up").to_xml).
7
+ to eq("<autogen>__KeyToKey__ KeyCode::BRACKET_RIGHT, VK_COMMAND | VK_SHIFT, KeyCode::CURSOR_UP, VK_OPTION | VK_CONTROL</autogen>")
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,248 @@
1
+ require "spec_helper"
2
+ require "tempfile"
3
+
4
+ describe Dotremap do
5
+ let!(:config) { Tempfile.new(".remap") }
6
+ let(:xml_dir) { "/tmp" }
7
+ let(:xml_path) { File.join(xml_dir, Dotremap::XML_FILE_NAME) }
8
+ let(:result) { File.read(xml_path) }
9
+
10
+ before do
11
+ stub_const("Dotremap::XML_DIR", xml_dir)
12
+ allow(Dotremap::Karabiner).to receive(:reload_xml)
13
+
14
+ # Silence stdout
15
+ allow_any_instance_of(Kernel).to receive(:puts)
16
+ end
17
+
18
+ after do
19
+ config.close!
20
+ end
21
+
22
+ def prepare_dotremap(dotremap)
23
+ config.write(dotremap)
24
+ config.rewind
25
+ end
26
+
27
+ def expect_result(expected_result)
28
+ dotremap = Dotremap.new(config.path)
29
+ dotremap.apply_configuration
30
+ expect(result).to eq(expected_result)
31
+ end
32
+
33
+ it "accepts blank config" do
34
+ prepare_dotremap("")
35
+
36
+ expect_result(<<-EOS.unindent)
37
+ <?xml version="1.0"?>
38
+ <root>
39
+
40
+ </root>
41
+ EOS
42
+ end
43
+
44
+ it "accepts cmd combination" do
45
+ prepare_dotremap(<<-EOS)
46
+ item "Command+A to Command+B" do
47
+ remap "Cmd-A", to: "Cmd-B"
48
+ end
49
+ EOS
50
+
51
+ expect_result(<<-EOS.unindent)
52
+ <?xml version="1.0"?>
53
+ <root>
54
+ <item>
55
+ <name>Command+A to Command+B</name>
56
+ <identifier>remap.command_a_to_command_b</identifier>
57
+ <autogen>__KeyToKey__ KeyCode::A, VK_COMMAND, KeyCode::B, VK_COMMAND</autogen>
58
+ </item>
59
+ </root>
60
+ EOS
61
+ end
62
+
63
+ it "accepts multiple remaps" do
64
+ prepare_dotremap(<<-EOS)
65
+ item "multiple remaps" do
66
+ remap "Cmd-A", to: "Cmd-B"
67
+ remap "Shift-A", to: "Shift-B"
68
+ end
69
+ EOS
70
+
71
+ expect_result(<<-EOS.unindent)
72
+ <?xml version="1.0"?>
73
+ <root>
74
+ <item>
75
+ <name>multiple remaps</name>
76
+ <identifier>remap.multiple_remaps</identifier>
77
+ <autogen>__KeyToKey__ KeyCode::A, VK_COMMAND, KeyCode::B, VK_COMMAND</autogen>
78
+ <autogen>__KeyToKey__ KeyCode::A, VK_SHIFT, KeyCode::B, VK_SHIFT</autogen>
79
+ </item>
80
+ </root>
81
+ EOS
82
+ end
83
+
84
+ it "accepts multiple items" do
85
+ prepare_dotremap(<<-EOS)
86
+ item "first item" do
87
+ remap "Cmd-C-A", to: "Cmd-M-B"
88
+ end
89
+
90
+ item "second item" do
91
+ remap "Shift-Opt-A", to: "Shift-Cmd-B"
92
+ end
93
+ EOS
94
+
95
+ expect_result(<<-EOS.unindent)
96
+ <?xml version="1.0"?>
97
+ <root>
98
+ <item>
99
+ <name>first item</name>
100
+ <identifier>remap.first_item</identifier>
101
+ <autogen>__KeyToKey__ KeyCode::A, VK_COMMAND | VK_CONTROL, KeyCode::B, VK_COMMAND | VK_OPTION</autogen>
102
+ </item>
103
+
104
+ <item>
105
+ <name>second item</name>
106
+ <identifier>remap.second_item</identifier>
107
+ <autogen>__KeyToKey__ KeyCode::A, VK_SHIFT | VK_OPTION, KeyCode::B, VK_SHIFT | VK_COMMAND</autogen>
108
+ </item>
109
+ </root>
110
+ EOS
111
+ end
112
+
113
+ it "accepts appdef and app option" do
114
+ prepare_dotremap(<<-EOS)
115
+ appdef "CHROME", equal: "com.google.Chrome"
116
+
117
+ item "Command+K to Command+L", only: "CHROME" do
118
+ remap "Cmd-K", to: "Cmd-L"
119
+ end
120
+ EOS
121
+
122
+ expect_result(<<-EOS.unindent)
123
+ <?xml version="1.0"?>
124
+ <root>
125
+ <appdef>
126
+ <appname>CHROME</appname>
127
+ <equal>com.google.Chrome</equal>
128
+ </appdef>
129
+
130
+ <item>
131
+ <name>Command+K to Command+L</name>
132
+ <identifier>remap.command_k_to_command_l</identifier>
133
+ <only>CHROME</only>
134
+ <autogen>__KeyToKey__ KeyCode::K, VK_COMMAND, KeyCode::L, VK_COMMAND</autogen>
135
+ </item>
136
+ </root>
137
+ EOS
138
+ end
139
+
140
+ it "accepts config and show_message" do
141
+ prepare_dotremap(<<-EOS)
142
+ item "CapsLock ON", config_not: "notsave.private_capslock_on" do
143
+ remap "Cmd-L", to: ["capslock", "VK_CONFIG_FORCE_ON_notsave_private_capslock_on"]
144
+ end
145
+
146
+ item "CapsLock OFF", config_only: "notsave.private_capslock_on" do
147
+ remap "Cmd-L", to: ["capslock", "VK_CONFIG_FORCE_OFF_notsave_private_capslock_on"]
148
+ end
149
+
150
+ item "CapsLock Mode" do
151
+ identifier "notsave.private_capslock_on", vk_config: "true"
152
+ show_message "CapsLock"
153
+ end
154
+ EOS
155
+
156
+ expect_result(<<-EOS.unindent)
157
+ <?xml version="1.0"?>
158
+ <root>
159
+ <item>
160
+ <name>CapsLock ON</name>
161
+ <identifier>remap.capslock_on</identifier>
162
+ <config_not>notsave.private_capslock_on</config_not>
163
+ <autogen>__KeyToKey__ KeyCode::L, VK_COMMAND, KeyCode::CAPSLOCK, KeyCode::VK_CONFIG_FORCE_ON_notsave_private_capslock_on</autogen>
164
+ </item>
165
+
166
+ <item>
167
+ <name>CapsLock OFF</name>
168
+ <identifier>remap.capslock_off</identifier>
169
+ <config_only>notsave.private_capslock_on</config_only>
170
+ <autogen>__KeyToKey__ KeyCode::L, VK_COMMAND, KeyCode::CAPSLOCK, KeyCode::VK_CONFIG_FORCE_OFF_notsave_private_capslock_on</autogen>
171
+ </item>
172
+
173
+ <item>
174
+ <name>CapsLock Mode</name>
175
+ <identifier vk_config="true">notsave.private_capslock_on</identifier>
176
+ <autogen>__ShowStatusMessage__ CapsLock</autogen>
177
+ </item>
178
+ </root>
179
+ EOS
180
+ end
181
+
182
+ it "accepts implicit autogen selection" do
183
+ prepare_dotremap(<<-EOS)
184
+ item "Control+LeftClick to Command+LeftClick" do
185
+ autogen "__PointingButtonToPointingButton__ PointingButton::LEFT, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_CONTROL, PointingButton::LEFT, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_COMMAND"
186
+ end
187
+ EOS
188
+
189
+ expect_result(<<-EOS.unindent)
190
+ <?xml version="1.0"?>
191
+ <root>
192
+ <item>
193
+ <name>Control+LeftClick to Command+LeftClick</name>
194
+ <identifier>remap.control_leftclick_to_command_leftclick</identifier>
195
+ <autogen>__PointingButtonToPointingButton__ PointingButton::LEFT, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_CONTROL, PointingButton::LEFT, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_COMMAND</autogen>
196
+ </item>
197
+ </root>
198
+ EOS
199
+ end
200
+
201
+ it "application invoking" do
202
+ prepare_dotremap(<<-EOS)
203
+ item "Application shortcuts" do
204
+ remap "C-o", to: invoke("YoruFukurou")
205
+ remap "C-u", to: invoke("Google Chrome")
206
+ remap "C-h", to: invoke("iTerm")
207
+ end
208
+
209
+ item "duplicate app" do
210
+ remap "C-a", to: invoke("YoruFukurou")
211
+ end
212
+ EOS
213
+
214
+ expect_result(<<-EOS.unindent)
215
+ <?xml version="1.0"?>
216
+ <root>
217
+ <item>
218
+ <name>Application shortcuts</name>
219
+ <identifier>remap.application_shortcuts</identifier>
220
+ <autogen>__KeyToKey__ KeyCode::O, VK_CONTROL, KeyCode::VK_OPEN_URL_APP_YoruFukurou</autogen>
221
+ <autogen>__KeyToKey__ KeyCode::U, VK_CONTROL, KeyCode::VK_OPEN_URL_APP_Google_Chrome</autogen>
222
+ <autogen>__KeyToKey__ KeyCode::H, VK_CONTROL, KeyCode::VK_OPEN_URL_APP_iTerm</autogen>
223
+ </item>
224
+
225
+ <item>
226
+ <name>duplicate app</name>
227
+ <identifier>remap.duplicate_app</identifier>
228
+ <autogen>__KeyToKey__ KeyCode::A, VK_CONTROL, KeyCode::VK_OPEN_URL_APP_YoruFukurou</autogen>
229
+ </item>
230
+
231
+ <vkopenurldef>
232
+ <name>KeyCode::VK_OPEN_URL_APP_YoruFukurou</name>
233
+ <url type="file">/Applications/YoruFukurou.app</url>
234
+ </vkopenurldef>
235
+
236
+ <vkopenurldef>
237
+ <name>KeyCode::VK_OPEN_URL_APP_Google_Chrome</name>
238
+ <url type="file">/Applications/Google Chrome.app</url>
239
+ </vkopenurldef>
240
+
241
+ <vkopenurldef>
242
+ <name>KeyCode::VK_OPEN_URL_APP_iTerm</name>
243
+ <url type="file">/Applications/iTerm.app</url>
244
+ </vkopenurldef>
245
+ </root>
246
+ EOS
247
+ end
248
+ end
@@ -0,0 +1,2 @@
1
+ require "dotremap"
2
+ require "pry"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dotremap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Takashi Kokubun
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-25 00:00:00.000000000 Z
11
+ date: 2014-07-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -26,6 +26,34 @@ dependencies:
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 10.3.2
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 10.3.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.0.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.0.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
29
57
  requirement: !ruby/object:Gem::Requirement
30
58
  requirements:
31
59
  - - ">="
@@ -52,7 +80,7 @@ dependencies:
52
80
  - - "~>"
53
81
  - !ruby/object:Gem::Version
54
82
  version: '1.0'
55
- description: Configuration DSL for KeyRemap4MacBook
83
+ description: Lightweight keyremap configuration DSL for Karabiner
56
84
  email:
57
85
  - takashikkbn@gmail.com
58
86
  executables:
@@ -61,24 +89,34 @@ extensions: []
61
89
  extra_rdoc_files: []
62
90
  files:
63
91
  - ".gitignore"
92
+ - ".rspec"
93
+ - ".travis.yml"
64
94
  - Gemfile
65
95
  - LICENSE.txt
66
96
  - README.md
67
97
  - Rakefile
68
98
  - bin/dotremap
69
99
  - dotremap.gemspec
70
- - example.rb
100
+ - img/disabled.png
101
+ - img/enabled.png
71
102
  - lib/dotremap.rb
72
103
  - lib/dotremap/appdef.rb
73
104
  - lib/dotremap/dsl.rb
74
105
  - lib/dotremap/dsl/item.rb
75
106
  - lib/dotremap/dsl/root.rb
76
107
  - lib/dotremap/item.rb
108
+ - lib/dotremap/karabiner.rb
109
+ - lib/dotremap/key.rb
77
110
  - lib/dotremap/openurl.rb
78
111
  - lib/dotremap/property.rb
79
112
  - lib/dotremap/remap.rb
80
113
  - lib/dotremap/root.rb
81
114
  - lib/dotremap/version.rb
115
+ - spec/lib/dotremap/appdef_spec.rb
116
+ - spec/lib/dotremap/key_spec.rb
117
+ - spec/lib/dotremap/remap_spec.rb
118
+ - spec/lib/dotremap_spec.rb
119
+ - spec/spec_helper.rb
82
120
  homepage: https://github.com/k0kubun/dotremap
83
121
  licenses:
84
122
  - MIT
@@ -102,5 +140,10 @@ rubyforge_project:
102
140
  rubygems_version: 2.2.2
103
141
  signing_key:
104
142
  specification_version: 4
105
- summary: Configuration DSL for KeyRemap4MacBook
106
- test_files: []
143
+ summary: Lightweight keyremap configuration DSL
144
+ test_files:
145
+ - spec/lib/dotremap/appdef_spec.rb
146
+ - spec/lib/dotremap/key_spec.rb
147
+ - spec/lib/dotremap/remap_spec.rb
148
+ - spec/lib/dotremap_spec.rb
149
+ - spec/spec_helper.rb
data/example.rb DELETED
@@ -1,135 +0,0 @@
1
- item "[Not Terminal] Command+O|P to Command+{|} (US)", not: "TERMINAL" do
2
- remap "Cmd-P", to: "Cmd-Shift-]"
3
- remap "Cmd-O", to: "Cmd-Shift-["
4
- end
5
-
6
- item "[Only Terminal] Command+O|P to Option+{|} (US)", only: "TERMINAL" do
7
- remap "Cmd-P", to: "Opt-Shift-]"
8
- remap "Cmd-O", to: "Opt-Shift-["
9
- end
10
-
11
- item "[Not Terminal] Command+E to Command+W", not: "TERMINAL" do
12
- remap "Cmd-E", to: "Cmd-W"
13
- end
14
-
15
- item "[Only Terminal] Command+T to Option+T, Command+E to Option+E", only: "TERMINAL" do
16
- remap "Cmd-T", to: "Opt-T"
17
- remap "Cmd-E", to: "Opt-E"
18
- end
19
-
20
- # For tmux copy mode
21
- item "[Only Terminal] Command+I to Option+I", only: "TERMINAL" do
22
- remap "Cmd-I", to: "Opt-I"
23
- end
24
-
25
- item "Command_L to Control_R" do
26
- remap "Cmd_L", to: "Ctrl_R"
27
- end
28
-
29
- # Change japanese input mode by Cmd_L + Space
30
- item "Exchange Control + Space and Command + Space" do
31
- remap "C-Space", to: "Cmd-Space"
32
- remap "Cmd-Space", to: "C-Space"
33
- end
34
-
35
- item "CapsLock ON", config_not: "notsave.private_capslock_on" do
36
- remap "Cmd-L", to: ["capslock", "VK_CONFIG_FORCE_ON_notsave_private_capslock_on"]
37
- end
38
-
39
- item "CapsLock OFF", config_only: "notsave.private_capslock_on" do
40
- remap "Cmd-L", to: ["capslock", "VK_CONFIG_FORCE_OFF_notsave_private_capslock_on"]
41
- end
42
-
43
- item "CapsLock Mode" do
44
- identifier "notsave.private_capslock_on", vk_config: "true"
45
- show_message "CapsLock"
46
- end
47
-
48
- item "[Not Terminal] Control+PNBF to Up/Down/Left/Right", not: "TERMINAL" do
49
- remap "C-p", to: "Up"
50
- remap "C-n", to: "Down"
51
- remap "C-b", to: "Left"
52
- remap "C-f", to: "Right"
53
- end
54
-
55
- # Use Cmd_R+D as M-d
56
- item "[Not Terminal] Command+D to Option+Forward Delete", not: "TERMINAL" do
57
- remap "Cmd-D", to: "Opt-forward_delete"
58
- end
59
-
60
- item "[Only Terminal] Command+D to Option+D, Command+BF to Option+BF", only: "TERMINAL" do
61
- remap "Cmd-D", to: "M-d"
62
- remap "Cmd-B", to: "M-b"
63
- remap "Cmd-F", to: "M-f"
64
- end
65
-
66
- # Use Cmd_R+B/F as M-b/f, and Cmd_R+S as Cmd+F to avoid conflict with M-f
67
- item "[Not Terminal] Command+B/F to Option+Left/Right, Command+S to Command+F", not: "TERMINAL" do
68
- remap "Cmd-B", to: "Opt-Left"
69
- remap "Cmd-F", to: "Opt-Right"
70
- remap "Cmd-S", to: "Cmd-F"
71
- end
72
-
73
- item "[Not Terminal] Control+W to Option+Delete", not: "TERMINAL" do
74
- remap "C-w", to: "Opt-delete"
75
- end
76
-
77
- item "Control+LeftClick to Command+LeftClick" do
78
- autogen "__PointingButtonToPointingButton__ PointingButton::LEFT, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_CONTROL, PointingButton::LEFT, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_COMMAND"
79
- end
80
-
81
- item "[Not Terminal] Chrome inspector Command+Control+I", not: "TERMINAL" do
82
- remap "Cmd-Ctrl-I", to: "Cmd-Opt-i"
83
- end
84
-
85
- # browser reload
86
- item "[Not Terminal] Control-R -> Command-R", not: "TERMINAL" do
87
- remap "C-r", to: "Cmd-R"
88
- end
89
-
90
- # tmux prefix
91
- item "[Only Terminal] Command-R -> Option-R", only: "TERMINAL" do
92
- remap "Cmd-R", to: "M-r"
93
- end
94
-
95
- # I don't want to press shift key
96
- item "Command semicolon to colon" do
97
- remap "Cmd-;", to: "Shift-;"
98
- end
99
-
100
- item "Shift by control" do
101
- remap "C--", to: "Shift--"
102
- remap "C-0", to: "Shift-0"
103
- remap "C-9", to: "Shift-9"
104
- remap "C-8", to: "Shift-8"
105
- remap "C-7", to: "Shift-7"
106
- remap "C-6", to: "Shift-6"
107
- remap "C-[", to: "Shift-["
108
- remap "C-]", to: "Shift-]"
109
- remap "C-;", to: "Shift-;"
110
- remap "C-,", to: "Shift-,"
111
- remap "C-.", to: "Shift-."
112
- remap "C-/", to: "Shift-/"
113
- remap "C-=", to: "Shift-="
114
- remap "C-\\", to: "Shift-\\"
115
- end
116
-
117
- item "Exchange single quote and double quote" do
118
- remap "Shift-'", to: "'"
119
- remap "'", to: "Shift-'"
120
- end
121
-
122
- item "[Only Terminal] Command+A to Option+A", only: "TERMINAL" do
123
- remap "Cmd-A", to: "M-a"
124
- end
125
-
126
- item "Disable Command-W" do
127
- remap "Cmd-W", to: "w"
128
- end
129
-
130
- appdef "YORUFUKUROU", equal: "com.YoruFukurouProject.YoruFukurou"
131
-
132
- item "YoruFukurou Account Change", only: "YORUFUKUROU" do
133
- remap "Cmd-K", to: "Cmd-Opt-Up"
134
- remap "Cmd-J", to: "Cmd-Opt-Down"
135
- end