動機
- Karabinerのvkopenurldef素晴らしすぎて泣ける
- 簡単に追加できるようにしたい
使用ツール
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