Skip to content

Repository files navigation

Build Status License

KE-complex_modifications

complex_modifications for Karabiner-Elements.

https://ke-complex-modifications.pqrs.org/

complex_modifications documents

Rule file formats in this repository

Rule files can use any of the following formats:

  • A JSON ruleset containing title and rules under public/json.
  • A JSON file containing one rule (description and manipulators) under public/json.
  • A JavaScript file under public/js whose final expression returns one rule (description and manipulators).

Karabiner-Elements 16.2.0 and later can import single-rule JSON and JavaScript directly. To support Karabiner-Elements 16.1.0 and earlier, the build also converts these sources to the title and rules ruleset format. The rule's description is used as the ruleset title.

A single JSON rule is replaced by its ruleset form at the same distribution path, so there is only one distributed JSON file. JavaScript source remains available unchanged, and its generated ruleset JSON is written beside it with the .ruleset.json suffix.

  • public/json/example.jsondist/json/example.json
  • public/js/example.jsdist/js/example.js
  • generated JavaScript ruleset JSON → dist/js/example.ruleset.json

The generated dist.json index contains lightweight metadata for display and search. Full manipulators remain in the distributed JSON files and are not duplicated in this index.

JSON ruleset

JSON rulesets bundle multiple rules into a single file so users can pick and enable what they need. For example, the "Emacs key bindings" ruleset includes several rules for different use cases.

The distributed JSON file Complex Modifications
distributed-json-file complex-modifications

To bundle them this way, the JSON has the following structure. Each element under rules is a single rule as defined in Complex Modifications.

If you list GitHub usernames in the "maintainers" field, the distribution site will automatically link to those accounts: https://ke-complex-modifications.pqrs.org/

{
    "title": "Emacs key bindings (rev XXX)",
    "maintainers": ["tekezo"],
    "rules": [
        {
            "description": "Emacs key bindings [control+keys] (rev XXX)",
            "manipulators": [
                {
                    "type": "basic",
                    "from": {},
                    "to": []
                }
            ]
        },
        {
            "description": "Emacs key bindings [option+keys] (rev XXX)",
            "manipulators": [
                {
                    "type": "basic",
                    "from": {},
                    "to": []
                }
            ]
        }
    ]
}

Single JSON rule

The object normally placed inside rules can also be saved directly:

{
    "description": "Change caps_lock to escape",
    "manipulators": [
        {
            "type": "basic",
            "from": { "key_code": "caps_lock" },
            "to": [{ "key_code": "escape" }]
        }
    ]
}

Optional ruleset attribution fields such as maintainers and author can be included in the same object. They are moved to the ruleset level during the build.

The distributed json/example.json contains the converted ruleset form. The distribution site imports this file directly and does not provide a separate compatible JSON action for single JSON rules.

JavaScript rule

JavaScript is useful when a rule contains repeated definitions. Helper functions can be defined in the same file. The last expression must return a single rule (description and manipulators). JSON ruleset objects containing title and rules are not supported under public/js. For example:

// JavaScript must be written in ECMAScript 5.1.

function main() {
  return {
    description: 'Change h/j/k/l to arrow keys',
    manipulators: [
      makeManipulator('h', 'left_arrow'),
      makeManipulator('j', 'down_arrow'),
      makeManipulator('k', 'up_arrow'),
      makeManipulator('l', 'right_arrow'),
    ],
  }
}

function makeManipulator(from, to) {
  return {
    type: 'basic',
    from: { key_code: from },
    to: [{ key_code: to }],
  }
}

main()

A source named public/js/example.js is distributed as dist/js/example.js. Its evaluated and normalized JSON ruleset is distributed as dist/js/example.ruleset.json. Use js/example.js as its path in public/groups.json. The build uses the value of the last JavaScript expression; standard output from the script is ignored.

For JavaScript rules, the distribution site's import menu provides both of the following actions:

  • Import JavaScript code
  • Import JSON compatible with Karabiner-Elements 16.1.0 or earlier

The menu can also display the generated JSON with Show compatible JSON and copy its URL with Copy compatible JSON URL.

How to add your rules

Follow the steps below to create a PR and add your settings!

  1. Fork this repository on GitHub.

  2. Clone the repository in Terminal.

    git clone --depth 1 https://github.com/{your_account}/KE-complex_modifications.git
    cd KE-complex_modifications
    git submodule update --init --recursive --depth 1
  3. Create a git branch in Terminal.

    git switch -c my-settings
  4. Put a JSON file into public/json or a JavaScript file into public/js. A JSON file can contain either a full ruleset or a single rule. A JavaScript file must return a single rule.

    Existing generator files in src/json are also supported. Their names must end in .json.js; generated JSON is written to public/json as before.

  5. (Optional) Update public/groups.json if you want to add your rules to a particular category.

    Add the following entry into public/groups.json.

    {
        "path": "json/your_awesome_configuration.json", // required
        "extra_description_path": "extra_descriptions/your_awesome_configuration.html" // optional
    },

    You can use the tag <kbd>⇧Shift</kbd> to make a nice ⇧Shift in your html.

  6. Run make command in Terminal to validate your files.
    JavaScript files are evaluated for validation. JSON is written under dist/json, and JavaScript is copied to dist/js. Each JavaScript rule also produces a sibling *.ruleset.json file. Single JSON rules are converted to ruleset form at their original path under dist/json. Files in src/json also update their corresponding generated files under public/json.

    make all

    If there is a problem, an error message is displayed. Fix your files until no errors are shown.

    "../public/json/personal_tekezo.json": `Personal rules (@tekezo) (rev 47)` error: `to` entry error: `key_code` error: unknown key_code: `"space"`
    make[1]: *** [all] Error 1
    make: *** [all] Error 2
    
  7. Test your files

    Copy the file to test to ~/.config/karabiner/assets/complex_modifications. For a JSON source, copy the built JSON ruleset. For a JavaScript source, copy the JavaScript file itself without converting it to JSON.

    cp dist/json/your_awesome_configuration.json ~/.config/karabiner/assets/complex_modifications
    # For a JavaScript source:
    cp dist/js/your_awesome_configuration.js ~/.config/karabiner/assets/complex_modifications

    Import rules from Karabiner-Elements Settings > Complex Modifications > Rules > Add rule.

  8. (Optional) Test your files on local web server.

    Run local web server by the following command in Terminal.

    make preview-server

    Then open http://localhost:8000.

  9. Run git commit and git push in Terminal.

    git add -A
    git commit -m 'your commit message'
    git push --set-upstream origin my-settings
  10. Create a PR on GitHub.

How to add additional description for your rules

Use the description field to explain how each distributed JSON rule works. If a one-line description is not enough (e.g., for complex rules), you can add supplementary text on the site:

  1. Place an HTML file under public/extra_descriptions/.
  2. Reference that HTML file from public/groups.json.

The additional description will then appear on the site as shown in the screenshot.

JSON only With extra description
json-only extra description
{
    "path": "json/emacs_key_bindings.json",
    "extra_description_path": "extra_descriptions/emacs_key_bindings.json.html"
}

Tips for writing extra description HTML file

  • Bootstrap's CSS are applied automatically, so you can adjust spacing with utility classes like mt-4, etc.
  • Do not include <html> and <body> tags. Write only the HTML for the description section.
  • You can include images with tags like <img src="multitouch-extension/enable-multitouch-extension.png" class="img-fluid border" />. Be sure to add the images to the repository.
  • As described above, you can preview your HTML by make preview-server command and open http://localhost:8000/ in your browser. The HTML file will not be loaded unless you specify extra_description_path in public/groups.json, so be sure to update groups.json.
  • After modifying an HTML file, reload the page in your browser to reflect the changes on the preview server. Automatic hot reload is not supported.

Sync your fork

To update your previously forked repositories, run the following command in Terminal.

Run only once

git remote add upstream https://github.com/pqrs-org/KE-complex_modifications.git

Run every time

# switch to main branch
git switch main

# fetch upstream
git fetch --all --prune --prune-tags

# update local repository
git reset --hard upstream/main

# update submodules
git submodule update --init --recursive

# clean files
git clean -x -d -f .

# update GitHub repository
git push

Notes on JavaScript rule files and generators

On macOS, the code in public/js/*.js and src/json/*.js is executed by Duktape, which is built into the Karabiner-Elements command line interface (karabiner_cli). The Linux deployment build evaluates public/js/*.js with Node.js because karabiner_cli is not available there. JavaScript must remain compatible with the Duktape environment so both builds produce the same result.

Unlike the latest Node.js, the basic language specification is ES5.1, so the following features cannot be used.

  • let (const is specially supported)
  • Arrow functions
  • Default parameters
  • Spread (...) syntax
  • Template literals

Examples

There are many existing codes. Here are some of the more distinctive ones among them.

About

Karabiner-Elements complex_modifications rules

Resources

Security policy

Stars

1.5k stars

Watchers

59 watching

Forks

Releases

Packages

Used by

Contributors

Languages