karabiner 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,7 @@
1
+ rvm:
2
+ - 2.1.2
3
+ branches:
4
+ only:
5
+ - master
6
+ script:
7
+ - 'bundle exec rspec .'
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in karabiner.gemspec
4
+ gemspec
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
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task :spec do
4
+ system("bundle exec rspec")
5
+ end
6
+
7
+ task default: :spec
data/bin/karabiner ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+
3
+ if [ $@ == "dsl" ]; then
4
+ bin_dir=$(cd $(dirname $0); pwd)
5
+ ${bin_dir}/karabiner-dsl
6
+ else
7
+ /Applications/Karabiner.app/Contents/Library/bin/karabiner $@
8
+ fi
data/bin/karabiner-dsl ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.dirname(__FILE__) + "/../lib"
4
+ $:.unshift lib unless $:.include? lib
5
+
6
+ require "karabiner"
7
+
8
+ DOTFILE_PATH = File.expand_path("~/.karabiner")
9
+
10
+ karabiner = Karabiner.new(DOTFILE_PATH)
11
+ karabiner.apply_configuration
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,10 @@
1
+ require "karabiner/namespace"
2
+ require "karabiner/item"
3
+
4
+ module Karabiner::DSL::Group
5
+ def item(name = nil, options = {}, &block)
6
+ item = Karabiner::Item.new(name, options)
7
+ item.instance_exec(&block)
8
+ add_child(item)
9
+ end
10
+ 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,5 @@
1
+ # Files which require this file can avoid deep nesting for class declaration
2
+ class Karabiner
3
+ module DSL
4
+ end
5
+ 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,3 @@
1
+ class Karabiner
2
+ VERSION = "0.1.0"
3
+ 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