karabiner 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.rspec +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +122 -0
- data/Rakefile +7 -0
- data/bin/karabiner +8 -0
- data/bin/karabiner-dsl +11 -0
- data/dotremap.gemspec +26 -0
- data/img/disabled.png +0 -0
- data/img/enabled.png +0 -0
- data/lib/karabiner/appdef.rb +23 -0
- data/lib/karabiner/cli.rb +25 -0
- data/lib/karabiner/config.rb +15 -0
- data/lib/karabiner/dsl/group.rb +10 -0
- data/lib/karabiner/dsl/item.rb +38 -0
- data/lib/karabiner/dsl/root.rb +28 -0
- data/lib/karabiner/group.rb +16 -0
- data/lib/karabiner/invoke_history.rb +16 -0
- data/lib/karabiner/item.rb +54 -0
- data/lib/karabiner/key.rb +85 -0
- data/lib/karabiner/namespace.rb +5 -0
- data/lib/karabiner/property.rb +15 -0
- data/lib/karabiner/remap.rb +16 -0
- data/lib/karabiner/root.rb +30 -0
- data/lib/karabiner/version.rb +3 -0
- data/lib/karabiner/vkopenurldef.rb +11 -0
- data/lib/karabiner/xml_tree.rb +42 -0
- data/lib/karabiner.rb +56 -0
- data/spec/lib/dotremap/appdef_spec.rb +35 -0
- data/spec/lib/dotremap/karabiner_spec.rb +29 -0
- data/spec/lib/dotremap/key_spec.rb +113 -0
- data/spec/lib/dotremap/remap_spec.rb +10 -0
- data/spec/lib/dotremap_spec.rb +335 -0
- data/spec/spec_helper.rb +2 -0
- metadata +158 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 54eca927143367b5272357cf58664363593c5b9b
|
4
|
+
data.tar.gz: 0bdcaaaee69fa945cab5e71d29d1b53b890c783f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6d6370cb2fdead72745f722f9948bd5a9014e226cb12959d8aba50ba7f37f302008475f101dcfa1d6a76622d92a66daef78b364ec8a6f3849e772371d2edb59c
|
7
|
+
data.tar.gz: 0004cc00131dec168743bd19b4dd297960d9230fab516f9575e474692050c69af437c53520704fc2ad84f35ddf5bf1ac8523fed260f008ac9b1a6138efadd16c
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
-c
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Takashi Kokubun
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
# Karabiner DSL [![Build Status](https://travis-ci.org/k0kubun/karabiner-dsl.png?branch=master)](https://travis-ci.org/k0kubun/karabiner-dsl)
|
2
|
+
|
3
|
+
Lightweight keyremap configuration DSL for [Karabiner](https://pqrs.org/osx/karabiner/index.html.en)
|
4
|
+
|
5
|
+
## Why Karabiner DSL?
|
6
|
+
|
7
|
+
Original [Karabiner's configuration](https://pqrs.org/osx/karabiner/xml.html.ja) is very hard to write.
|
8
|
+
Karabiner DSL is its wrapper, which is easy-to-write and readable.
|
9
|
+
|
10
|
+
If you write Karabiner's config with Karabiner DSL, you can update your keyremap configuration quickly.
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
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
|
20
|
+
$ gem install karabiner
|
21
|
+
```
|
22
|
+
|
23
|
+
Then `karabiner` executable will be installed.
|
24
|
+
This gem provides only `karabiner dsl` subcommand and other subcommands are delegated to original CLI for Karabiner.app.
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
### 1. Create ~/.karabiner
|
28
|
+
|
29
|
+
```rb
|
30
|
+
item "Command+G to open Google Chrome" do
|
31
|
+
remap "Cmd-g", to: invoke("Google Chrome")
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
### 2. Execute karabiner dsl command
|
36
|
+
|
37
|
+
```bash
|
38
|
+
$ karabiner dsl
|
39
|
+
```
|
40
|
+
|
41
|
+
Then `karabiner dsl` will update Karabiner's config as you expected.
|
42
|
+
|
43
|
+
![](https://raw.githubusercontent.com/k0kubun/karabiner-dsl/master/img/disabled.png)
|
44
|
+
|
45
|
+
### 3. Enable your favorite configurations
|
46
|
+
|
47
|
+
![](https://raw.githubusercontent.com/k0kubun/karabiner-dsl/master/img/enabled.png)
|
48
|
+
|
49
|
+
Enjoy!
|
50
|
+
|
51
|
+
## How to write ~/.karabiner
|
52
|
+
### Basics
|
53
|
+
|
54
|
+
karabiner-dsl's DSL is a superset of Ruby.
|
55
|
+
So you can use any Ruby methods in ~/.karabiner.
|
56
|
+
|
57
|
+
#### item
|
58
|
+
|
59
|
+
```rb
|
60
|
+
item "configuration unit" do
|
61
|
+
...
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
In karabiner-dsl, any Karabiner's configuration unit is expressed in `item` and its `do ~ end` block.
|
66
|
+
You can group some remap configurations in one item and enable them in one click.
|
67
|
+
|
68
|
+
#### remap
|
69
|
+
|
70
|
+
```rb
|
71
|
+
item "remap example" do
|
72
|
+
remap "Cmd-a", to: "C-a"
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
If you want to add remap configuration, you have to call `remap` method.
|
77
|
+
In this example, Command+A will be remapped to Control+A.
|
78
|
+
|
79
|
+
You have to write "key expression" to specify keys to remap.
|
80
|
+
|
81
|
+
#### key expression
|
82
|
+
|
83
|
+
- `a`, `A`, `1`, `;`, `tab`, `Tab`, `space`, `up`, `down`
|
84
|
+
- any string without `-` will be regarded as single key
|
85
|
+
- ignore upcase or downcase
|
86
|
+
- `C-a`, `Ctrl-a`
|
87
|
+
- regarded as Control + A
|
88
|
+
- `C-` is a short expression of `Ctrl-`
|
89
|
+
- `M-a`, `Opt-a`
|
90
|
+
- regarded as Option + A
|
91
|
+
- `Shift-a`
|
92
|
+
- regarded as large A
|
93
|
+
- if you write just `A`, it will be regarded as small a
|
94
|
+
- `Cmd-a`
|
95
|
+
- regarded as Command + A
|
96
|
+
- `Cmd-Shift-a`
|
97
|
+
- regarded as Command + Shift + A
|
98
|
+
- you can use any combination of Ctrl, Opt, Shift, Cmd
|
99
|
+
|
100
|
+
#### available single keys
|
101
|
+
|
102
|
+
```
|
103
|
+
a b c ... x y z
|
104
|
+
0 1 2 ... 7 8 9
|
105
|
+
F1 F2 ... F11 F12
|
106
|
+
\ [ ] ; ' , . / - =
|
107
|
+
Up Down Right Left
|
108
|
+
space tab delete forward_delete capslock
|
109
|
+
|
110
|
+
Ctrl_R Ctrl_L
|
111
|
+
Opt_R Opt_L
|
112
|
+
Cmd_R Cmd_L
|
113
|
+
Shift_R Shift_L
|
114
|
+
```
|
115
|
+
|
116
|
+
## Contributing
|
117
|
+
|
118
|
+
1. Fork it ( https://github.com/k0kubun/karabiner-dsl/fork )
|
119
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
120
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
121
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
122
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/karabiner
ADDED
data/bin/karabiner-dsl
ADDED
data/dotremap.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'karabiner/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "karabiner"
|
8
|
+
spec.version = Karabiner::VERSION
|
9
|
+
spec.authors = ["Takashi Kokubun"]
|
10
|
+
spec.email = ["takashikkbn@gmail.com"]
|
11
|
+
spec.summary = %q{Lightweight keyremap configuration DSL}
|
12
|
+
spec.description = %q{Lightweight keyremap configuration DSL for Karabiner}
|
13
|
+
spec.homepage = "https://github.com/k0kubun/karabiner-dsl"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.3.2"
|
23
|
+
spec.add_development_dependency "rspec", "~> 3.0.0"
|
24
|
+
spec.add_development_dependency "pry"
|
25
|
+
spec.add_dependency 'unindent', '~> 1.0'
|
26
|
+
end
|
data/img/disabled.png
ADDED
Binary file
|
data/img/enabled.png
ADDED
Binary file
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "karabiner/xml_tree"
|
2
|
+
|
3
|
+
class Karabiner::Appdef
|
4
|
+
include Karabiner::XmlTree
|
5
|
+
|
6
|
+
AVAILABLE_OPTIONS = %i(
|
7
|
+
equal
|
8
|
+
prefix
|
9
|
+
suffix
|
10
|
+
).freeze
|
11
|
+
|
12
|
+
def initialize(appname, options)
|
13
|
+
property = Karabiner::Property.new("appname", appname)
|
14
|
+
add_child(property)
|
15
|
+
|
16
|
+
options.each do |option, value|
|
17
|
+
raise "Unavailable option: #{property}" unless AVAILABLE_OPTIONS.include?(option)
|
18
|
+
|
19
|
+
property = Karabiner::Property.new(option, value)
|
20
|
+
add_child(property)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "karabiner/namespace"
|
2
|
+
|
3
|
+
module Karabiner::CLI
|
4
|
+
CLI_PATH = "/Applications/Karabiner.app/Contents/Library/bin/karabiner"
|
5
|
+
|
6
|
+
def self.reload_xml
|
7
|
+
system("#{CLI_PATH} reloadxml")
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.current_config
|
11
|
+
changed = `#{CLI_PATH} changed`
|
12
|
+
config_by_changed(changed)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def self.config_by_changed(changed)
|
18
|
+
config = {}
|
19
|
+
changed.each_line do |line|
|
20
|
+
property, value = line.strip.split("=")
|
21
|
+
config[property] = value
|
22
|
+
end
|
23
|
+
config
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
require "karabiner/namespace"
|
3
|
+
|
4
|
+
class Karabiner::Config
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
def_delegator :@parent, :item
|
8
|
+
def_delegator :@parent, :group
|
9
|
+
|
10
|
+
def initialize(name)
|
11
|
+
@name = name
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_writer :parent
|
15
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "karabiner/namespace"
|
2
|
+
require "karabiner/property"
|
3
|
+
require "karabiner/remap"
|
4
|
+
require "karabiner/invoke_history"
|
5
|
+
|
6
|
+
module Karabiner::DSL::Item
|
7
|
+
AVAILABLE_PROPERTIES = %i(
|
8
|
+
name
|
9
|
+
identifier
|
10
|
+
autogen
|
11
|
+
).freeze
|
12
|
+
|
13
|
+
def remap(target, options = {})
|
14
|
+
remap = Karabiner::Remap.new(target, options[:to])
|
15
|
+
add_child(remap)
|
16
|
+
end
|
17
|
+
|
18
|
+
def show_message(message)
|
19
|
+
property = Karabiner::Property.new("autogen", "__ShowStatusMessage__ #{message}")
|
20
|
+
add_child(property)
|
21
|
+
end
|
22
|
+
|
23
|
+
def invoke(application)
|
24
|
+
Karabiner::InvokeHistory.register(application)
|
25
|
+
"VK_OPEN_URL_APP_#{application.gsub(/ /, '_')}"
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def method_missing(property, value = '', options = {})
|
31
|
+
if AVAILABLE_PROPERTIES.include?(property)
|
32
|
+
property = Karabiner::Property.new(property, value, options)
|
33
|
+
add_child(property)
|
34
|
+
else
|
35
|
+
super
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "karabiner/namespace"
|
2
|
+
require "karabiner/appdef"
|
3
|
+
require "karabiner/config"
|
4
|
+
require "karabiner/item"
|
5
|
+
require "karabiner/group"
|
6
|
+
require "karabiner/dsl/group"
|
7
|
+
|
8
|
+
module Karabiner::DSL::Root
|
9
|
+
include Karabiner::DSL::Group
|
10
|
+
|
11
|
+
def group(name, &block)
|
12
|
+
group = Karabiner::Group.new(name)
|
13
|
+
group.instance_exec(&block)
|
14
|
+
add_child(group)
|
15
|
+
end
|
16
|
+
|
17
|
+
def config(name, &block)
|
18
|
+
config = Karabiner::Config.new(name)
|
19
|
+
config.parent = self
|
20
|
+
config.instance_exec(&block)
|
21
|
+
add_config(config)
|
22
|
+
end
|
23
|
+
|
24
|
+
def appdef(appname = '', options = {})
|
25
|
+
appdef = Karabiner::Appdef.new(appname, options)
|
26
|
+
add_child(appdef)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
require "karabiner/namespace"
|
3
|
+
require "karabiner/dsl/group"
|
4
|
+
|
5
|
+
class Karabiner::Group
|
6
|
+
extend Forwardable
|
7
|
+
include Karabiner::XmlTree
|
8
|
+
include Karabiner::DSL::Group
|
9
|
+
|
10
|
+
def_delegator :@item, :to_xml
|
11
|
+
def_delegator :@item, :add_child
|
12
|
+
|
13
|
+
def initialize(name)
|
14
|
+
@item = Karabiner::Item.new(name, skip_identifier: true)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "set"
|
2
|
+
require "karabiner/vkopenurldef"
|
3
|
+
|
4
|
+
module Karabiner::InvokeHistory
|
5
|
+
def self.clear_histroy
|
6
|
+
@@registered_applications = Set.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.register(application)
|
10
|
+
registered_applications.add(application)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.registered_applications
|
14
|
+
@@registered_applications ||= Set.new
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require "karabiner/dsl/item"
|
2
|
+
require "karabiner/xml_tree"
|
3
|
+
|
4
|
+
class Karabiner::Item
|
5
|
+
include Karabiner::XmlTree
|
6
|
+
include Karabiner::DSL::Item
|
7
|
+
|
8
|
+
AVAILABLE_OPTIONS = %i(
|
9
|
+
not
|
10
|
+
only
|
11
|
+
config_not
|
12
|
+
config_only
|
13
|
+
).freeze
|
14
|
+
|
15
|
+
def initialize(name, options = {})
|
16
|
+
@skip_identifier = options.delete(:skip_identifier)
|
17
|
+
|
18
|
+
if name
|
19
|
+
property = Karabiner::Property.new("name", name)
|
20
|
+
add_child(property)
|
21
|
+
end
|
22
|
+
|
23
|
+
options.each do |option, value|
|
24
|
+
raise "Unavailable option: #{option}" unless AVAILABLE_OPTIONS.include?(option)
|
25
|
+
|
26
|
+
property = Karabiner::Property.new(option, value)
|
27
|
+
add_child(property)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_xml
|
32
|
+
validate_name_existence
|
33
|
+
generate_identifier unless @skip_identifier
|
34
|
+
|
35
|
+
super
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def validate_name_existence
|
41
|
+
properties = search_childs(Karabiner::Property)
|
42
|
+
raise "Name property does not exist" unless properties.map(&:attr).include?("name")
|
43
|
+
end
|
44
|
+
|
45
|
+
def generate_identifier
|
46
|
+
properties = search_childs(Karabiner::Property)
|
47
|
+
return if properties.map(&:attr).include?("identifier")
|
48
|
+
|
49
|
+
name = properties.find { |p| p.attr == "name" }
|
50
|
+
generated_identifier = name.value.gsub(/[^a-zA-Z]/, "_").downcase
|
51
|
+
identifier = Karabiner::Property.new("identifier", "remap.#{generated_identifier}")
|
52
|
+
childs[1, 0] = identifier
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
class Karabiner::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
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Karabiner::Property
|
2
|
+
include Karabiner::XmlTree
|
3
|
+
|
4
|
+
def initialize(attr, value, options = {})
|
5
|
+
@attr = attr.to_s
|
6
|
+
@value = value
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
attr_accessor :attr, :value
|
10
|
+
|
11
|
+
def to_xml
|
12
|
+
open_tag = @options.map { |a, v| "#{a}=\"#{v}\"" }.unshift(attr).join(" ")
|
13
|
+
"<#{open_tag}>#{value}</#{attr}>"
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "karabiner/key"
|
2
|
+
require "karabiner/property"
|
3
|
+
|
4
|
+
class Karabiner::Remap < Karabiner::Property
|
5
|
+
def initialize(from, to)
|
6
|
+
tos = [to].flatten
|
7
|
+
|
8
|
+
super(
|
9
|
+
"autogen",
|
10
|
+
[
|
11
|
+
"__KeyToKey__ #{Karabiner::Key.new(from)}",
|
12
|
+
*tos.map { |to| Karabiner::Key.new(to) },
|
13
|
+
].join(", "),
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "karabiner/invoke_history"
|
2
|
+
require "karabiner/vkopenurldef"
|
3
|
+
require "karabiner/dsl/root"
|
4
|
+
|
5
|
+
class Karabiner::Root
|
6
|
+
include Karabiner::XmlTree
|
7
|
+
include Karabiner::DSL::Root
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@configs = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_xml
|
14
|
+
Karabiner::InvokeHistory.registered_applications.each do |application|
|
15
|
+
vkopenurldef = Karabiner::Vkopenurldef.new(application)
|
16
|
+
add_child(vkopenurldef)
|
17
|
+
end
|
18
|
+
|
19
|
+
[
|
20
|
+
"<?xml version=\"1.0\"?>",
|
21
|
+
super(1),
|
22
|
+
].join("\n")
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def add_config(config)
|
28
|
+
@configs << config
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require "karabiner/xml_tree"
|
2
|
+
|
3
|
+
class Karabiner::Vkopenurldef
|
4
|
+
include Karabiner::XmlTree
|
5
|
+
|
6
|
+
def initialize(application)
|
7
|
+
name = Karabiner::Property.new("name", "KeyCode::VK_OPEN_URL_APP_#{application.gsub(/ /, "_")}")
|
8
|
+
url = Karabiner::Property.new("url", "/Applications/#{application}.app", type: "file")
|
9
|
+
add_child(name, url)
|
10
|
+
end
|
11
|
+
end
|