LoginSignup
4
5

More than 5 years have passed since last update.

Karabinerのランチャーアイテムを編集するシェルスクリプト

Last updated at Posted at 2015-02-26

動機

使用ツール

xmlstarlet

  • コマンドラインでXML解析・編集
$ brew install xmlstarlet

$ type xmlstarlet
xmlstarlet is /usr/local/bin/xmlstarlet
$ type xml
xml is /usr/local/bin/xml

GNU sed

  • xmlstarletだとネストした要素を追加するのが超かったるいので
  • メタキャラクタ\nを使いたいので
$ brew install gnu-sed

$ type gsed
gsed is /usr/local/bin/gsed

MacVim

$ brew cask install macvim

$ type mvim
mvim is /usr/local/bin/mvim

pygmentize

Karabiner launcherの構造

private.xml
<?xml version="1.0"?>
<root>
  <item><!-- 関係ないitem -->
    <name>Esc alternative</name>
    <identifier>esc_alternative</identifier>
    <appendix>All Applications</appendix>
    <autogen>
      __SimultaneousKeyPresses__
      KeyCode::J, KeyCode::K,
      KeyCode::ESCAPE,
      Option::SIMULTANEOUSKEYPRESSES_RAW
    </autogen>
  </item>
  <item><!-- このitemがランチャーを定義 -->
    <name>launcher</name>
    <identifier>karabiner_launcher</identifier>
    <vkopenurldef>
      <name>KeyCode::VK_OPEN_URL_SHELL.toggle.Finder</name>
      <url type="shell">
        <![CDATA[ osascript ~/bin/osascript/toggleapp.scpt Finder ]]>
      </url>
    </vkopenurldef>
    <vkopenurldef>
      <name>KeyCode::VK_OPEN_URL_SHELL.doingtxt</name>
      <url type="shell">
        <![CDATA[ open -a "TaskPaper" ~/Dropbox/todo/doing.txt ]]>
      </url>
    </vkopenurldef>
    <autogen>
      __SimultaneousKeyPresses__
      KeyCode::F, KeyCode::D,
      KeyCode::VK_OPEN_URL_SHELL.toggle.Finder
    </autogen>
    <autogen>
      __SimultaneousKeyPresses__
      KeyCode::D, KeyCode::G,
      KeyCode::VK_OPEN_URL_SHELL.doingtxt,
      Option::SIMULTANEOUSKEYPRESSES_STRICT_KEY_ORDER
    </autogen>
  </item>
  <item>
    <name>remap to Delete</name>
    <identifier>remap.to_delete</identifier>
    <autogen>__SimultaneousKeyPresses__ KeyCode::D, KeyCode::L, KeyCode::DELETE</autogen>
  </item>
  <item><!-- 関係ないitem -->
    <name>Simultaneous Key Presses to Geneal Hotkey</name>
    <identifier>remap.simultaneouskeypresses_to_general</identifier>
    <appendix>C-V: Cmd+C</appendix>
    <autogen>__SimultaneousKeyPresses__ KeyCode::M, KeyCode::N, KeyCode::F2, VK_CONTROL, Option::SIMULTANEOUSKEYPRESSES_STRICT_KEY_ORDER</autogen>
  </item>
</root>

<identifier>karabiner_launcher</identifier>を持つ<item>内に、<vkopenurldef><autogen>を追加する必要がある。

完成したコード

#!/bin/bash
# @(#) add launcher item to private.xml for Karabiner
# readonly FILE=~/Documents/karabiner.xml
readonly CMDNAME="$(basename "$0")"
readonly FILE=~/Library/Application\ Support/Karabiner/private.xml
url='<url type="shell">'
defid=''
nametype=''
def=''
autogen=''
dflag=0
usage () {
  echo "Usage: $(basename "$0") -t <type> -i <id> [-h] [contents]" 1>&2
  echo "-t: url/file/shell" 1>&2
}
while getopts t:i:d:h OPT
do
  case $OPT in
    t)#type
      case "$OPTARG" in
        u*)
          url='<url>'
          nametype="WEB"
          ;;
        f*)
          url='<url type="file">'
          nametype="FILE"
          ;;
        s*)
          url='<url type="shell">'
          nametype="SHELL"
          ;;
        ?) echo "$(basename "$0"): Undifined url type. select from 'url/file/shell'" 1>&2; exit 1
          ;;
      esac
      ;;
    i)#identifier
      defid="$OPTARG"
      ;;
    d)#delete
      dflag=1
      darg="$OPTARG"
      ;;
    h)
      usage
      exit 0
      ;;
    ?)
      echo "$(basename "$0"): Undifined option." 1>&2
      usage
      exit 1
      ;;
  esac
done
shift $((OPTIND - 1))

# process
# delete option
if [ "$dflag" = 1 ];then
  dname="$(xmlstarlet sel -I -t -v '//item[identifier="karabiner_launcher"]/vkopenurldef/name' "$FILE" 2>/dev/null | grepeco -p "Select item to delete:" "$darg")"
  if [ -n "$dname" ];then
    {
      xmlstarlet sel -t -c "//item[identifier='karabiner_launcher']/vkopenurldef[name='$dname']" "$FILE" | xmlstarlet fo | gsed -e 1d -e "\$a\ " | gsed -e "1i\------------------------------"
      xmlstarlet sel -t -c "//item[identifier='karabiner_launcher']/autogen[contains(./text(),'$dname')]" "$FILE" | xmlstarlet fo | gsed -e 1d -e "\$a\------------------------------"
    } | pygmentize
    echo "$CMDNAME: Delete this launcher item? ['y'/n]" 1>&2
    read ANSWER
  else
    echo "$CMDNAME: ERROR: No hit." 1>&2
    exit 1
  fi
  if ! echo "$ANSWER" | grep -q '^n'; then
    xmlstarlet ed -L -d "//item[identifier='karabiner_launcher']/vkopenurldef[name='$dname']" "$FILE"
    xmlstarlet ed -L -d "//item[identifier='karabiner_launcher']/autogen[contains(./text(),'$dname')]" "$FILE"
    echo "$CMDNAME: Deleted." 1>&2
    /Applications/Karabiner.app/Contents/Library/bin/karabiner reloadxml
    exit 0
  else
    echo "$CMDNAME: Canceled." 1>&2
    exit 0
  fi
fi

if [ -z "$defid" ];then
  echo "$CMDNAME: Enter 'vkopenurldef' identifier." 1>&2
  echo -n "id: " 1>&2
  read defid
fi

if [ -z "$1" ];then
  echo "$CMDNAME: Enter 'vkopenurldef' url content." 1>&2
  echo -n "CDATA: " 1>&2
  read CDATA
else
  CDATA="$*"
fi

# add <vkopenurldef>
def="    <vkopenurldef>\n      <name>KeyCode::VK_OPEN_URL_$nametype.$defid<\/name>\n      $url\n        <\![CDATA[ $CDATA ]]>\n      <\/url>\n    <\/vkopenurldef>"
echo "$def" | gsed -e 's/\\n/\n/g' -e 's@\\!@!@g' -e 's@\\/@/@g' | pygmentize
echo "$CMDNAME: Add this item? ['y'/n]" 1>&2
read ANSWER
if ! echo "$ANSWER" | grep -q '^n'; then
  gsed -i "/<identifier>karabiner_launcher<\/identifier>/a\\$def" "$FILE"
else
  echo "$CMDNAME: Canceled." 1>&2
  exit 0
fi

# add <autogen>
autogen="    <autogen>\n      __SimultaneousKeyPresses__\n      KeyCode::, KeyCode::,\n      KeyCode::VK_OPEN_URL_$nametype.$defid\n    <\/autogen>"
gsed -i "/<identifier>karabiner_launcher<\/identifier>/,/<\/item>/s/\( *<\/item>\)/$autogen\n\1/" "$FILE"
mvim +"/^ *KeyCode::VK_OPEN_URL_$nametype.$defid" +-1 +"normal f," "$FILE"

使い方

  • 追加
$ kled -t shell -i toggle.Notes osascript ~/bin/osascript/toggleapp.scpt Notes
    <vkopenurldef>
      <name>KeyCode::VK_OPEN_URL_SHELL.toggle.Notes</name>
      <url type="shell">
        <![CDATA[ osascript /Users/catfist/bin/osascript/toggleapp.scpt Notes ]]>
      </url>
    </vkopenurldef>
Add this item? ['y'/n]
# n以外を入力
# MacVimが起動して<autogen>部分の編集に入る
  • 削除
$ kled -d Notes
------------------------------
<vkopenurldef>
  <name>KeyCode::VK_OPEN_URL_SHELL.toggle.Notes</name>
  <url type="shell"> osascript /Users/catfist/bin/osascript/toggleapp.scpt Notes </url>
</vkopenurldef>

<autogen> __SimultaneousKeyPresses__ KeyCode::N, KeyCode::T,KeyCode::VK_OPEN_URL_SHELL.toggle.Notes</autogen>
------------------------------
kled: Delete this launcher item? ['y'/n]
# n以外を入力
kled: Deleted.

補遺

# !をエスケープする
def="    <vkopenurldef>\n      <name>KeyCode::VK_OPEN_URL_SHELL.toggle.$appname<\/name>\n      <url type="shell">\n      <\![CDATA[ osascript ~\/bin\/osascript\/toggleapp.scpt $appname ]]>\n<\/url>\n    <\/vkopenurldef>"
# $をエスケープする
$ var=replaced
$ cat txt | gsed "/aaa/a\\$var"
aaaa
replaced
bbbb
cccc
ddff
gghh

参考

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5