dotremap 0.0.3 → 0.0.4

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
  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