karabiner 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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