AutoHotkeyに小説周りの雑用を外注してみた
但し書き
この記事に提示しているサンプルスクリプトは、すべて動作未確認となります。
あらかじめご了承ください。
要点
- AutoHotkey にやらせているアレコレ
- 定型文入力
- 括弧・ショートコード入力
- Google 検索・DeepL 翻訳・JapanKnowledge 検索
雑用外注先・AutoHotkey
なぜ外注するのか
小説を書くにあたって、やることはたくさんある。
資料を集め、人物や設定を育て、プロットを組む。
これらが継続的に襲いかかってきては、執筆者の時間を奪っていく。
もちろん原稿として形にすることも、大きなタスクだ。
それが終われば推敲校正。
分解するとキリがない。
仕事量に溺れないためには、細かい仕事を自分の手から放してしまうのが一番だ。
とはいえ他人に頼むには、小説というのは些か内面に踏み込みすぎている。
また小説にかかわらず、自分の求める作業品質を他人に正確に伝え、それを実現してもらうのは至難の業だ。人類共通の課題と言ってもいい。
自分で育てたスクリプトくんに雑用を外注するのが、一番角が立たないと判断した。
何しろすべて自分の責任として、まったく文句の余地なく受け入れるしかないからだ。
何を外注するのか
定型文をいちいち入力するのが嫌いだ。
とはいえ、「いつもお世話になっております」と相手に伝えるのが嫌なわけではない。
「いつもお世話になっております」といちいち入力するのが嫌なだけだ。
カギ括弧の入力が嫌いだ。
正確には、台詞を入力した後に、カギ括弧の閉じる方をいちいち入力するのが嫌いだ。
さりとて自動補完でエディタに閉じられるのも腹が立つ。
あの機能、こちらのキー入力の速度なんかお構いなしに閉じてくるもんだから、台詞の中途半端なところに閉じ括弧が入ったりするのだ。
いちいちブラウザのアドレスバーにカーソルをあわせるのが嫌いだ。
ただ検索するためだけにホームポジションから手を移動しなくてはならない。
不愉快極まりない。
よって、まずはこれらを外注することにした。
どこに外注するのか
AutoHotkey というスクリプト言語がある。
Windows であれば、DLL 等を介して基本なんでもできる。
現環境がすべて Windows なので、これで問題ないと判断した。
定型文入力
日本語IMEとの相性
AutoHotkey にはホットキーとホットストリングというふたつのトリガー方式がある。
ホットキーは複数キーの組み合わせを指定し、大抵はキーの同時押しでコマンドを実行する。
ショートカットキーを追加するようなものと思えばよい。
;Windowsキー + y キーを同時押ししてメモ帳を起動する
#y::
WinActivate, Untitled - Notepad
Return
ホットストリングは複数の文字列を連続的に入力することで、自動入力やスクリプトを実行する。
自動補完のようなものだ。
;自動入力
::btw::by the way
;スクリプト
::btw::
Clipboard = by the way
Send,^v
Return
深く考えなければ、定型文入力にはホットストリングの自動入力が適しているように見える。
しかし、こと日本語圏においては、同じホットストリングを使うとしてもスクリプトのほうに使い勝手の軍配が上がる。
理由として大きいのは、AutoHotkey は日本語 IME をうまく扱えないという点だ。
自動入力の場合、AutoHotkey は実際にキー入力を送り込む動作をしている。
文字どおりキーボードを入力しているわけだが、IME が ON の状態で自動入力を発動させた場合、文字列は 「日本語 IME を ON にした状態で入力した」 ものとなる。
つまり、上記の例を日本語 IME を ON にした状態で実行すると、こうなる。
::btw::by the way
;結果出力
byてぇわy
一方、同じ条件でスクリプトを実行すると、こうなる。
::btw::
Clipboard = by the way
Send,^v
Return
;結果出力
by the way
クリップボードに文字列として受け渡し、それを貼り付けるという方法だ。
これなら、IME と干渉することなく英数字を入力できる。
一応、入力した際に IME を OFF にするという発想もある。
実際、それを実現してくれる関数も公開されている。
関数の機能を適切に用いれば、ホットキー処理終了後に IME の状態を復元できる。
クリップボードひとつを介することで問題が解決するなら、それもいいじゃないかというだけの話だ。
気にせず好きに使ってくれ。
だが、クリップボードを介するスクリプト方式もベターとは言い難い。
クリップボードの履歴に文字列が残ってしまうので、いろいろと不便になるという問題がある。
特に Clibor などのクリップボード拡張ツールを使っている場合は、その影響が顕著に出る。
なので、それを解決するための方法を次に紹介する。
クリップボードを清潔に保つスクリプトの提案
要はクリップボードの履歴をバックアップ・復元すればいいのであって、それは AutoHotkey の中で解決できる。
PasteString(String){
Backup := ClipboardAll
Sleep, 50
Clipboard := String
Sleep, 50
Send, ^v
Sleep, 50
Clipboard := Backup
ClipWait, 3, 1
}
クリップボードの履歴をバックアップし、クリップボードへ入力したい文字列を投入。
貼り付け処理を行ってから、クリップボードにバックアップを戻すという処理だ。
他の部分はクリップボード処理待ちだったり変更検知だったりだ。
変更検知があまり信用ならないので、sleep で明示的に 50 ミリ秒処理を止めている。
これは関数として記述されたものなので、入力したい文字列は別途指定しなければならない。
下のように呼び出す。
::btw::
PasteString("by the way")
Return
Clibor を使っている人は、「短時間のクリップボード更新を無視する」という設定項目を 500 ミリ秒にでもすればよい。
Clibor のクリップボード履歴格納処理を 1000 ミリ秒遅延させれば完璧だ。

↑頼むから使ってくれ。
括弧・ショートコード入力
上記した PasteString 関数はいろいろと応用できる。
一例として、 「選択した文字列をクリップボードにコピーし、その前後を引数で指定した文字列に挟んで返す」 関数を用意した。
クリップボードへの登録は、シンプルに Ctrl+C を押下させている。
Ctrl+C 後にクリップボードが 0 文字だったら(=無選択だったら)単に引数を返して、カーソルをひとつ前に送る。
Ctrl+C 後、クリップボード内に改行が入っていたら、上記と同様の処理を行う。
最後にクリップボードを処理前の状態に戻して、終了だ。
WrapBracket(x,y){
Backup := ClipboardAll
Clipboard =
Send, ^c
Sleep,50
IfInString, Clipboard, `r`n
{
Clipboard =
ClipStatus := 0 ;中身が空文字列なので0
}Else if (Clipboard = ""){
ClipStatus := 0
}else{
ClipStatus := 1 ;中身があるので1
#if
}
Sleep,50
Clipboard = %x%%Clipboard%%y%
Sleep, 50
Send,^v
Sleep,50
if (ClipStatus = 0){
send,{Left}
}Else{
#If
}
Clipboard := Backup
ClipStatus =
}
関数の呼び出し方は以下のとおり。
ホットキー方式を用いているのは、文字列を選択した状態で入力すると上書きされてしまうため。
sc07B & k::
WrapBracket("「","」")
Return
ちなみに、sc07B とは無変換キーを示す文字列だ。
全角・半角キーなら sc029、変換キーなら sc079 といった具合に指定する。
キーリストはこちら。
「小説家になろう」や「ハーメルン」などでお馴染みのルビ付与ショートコードも、上記の関数で後追い付与できる。
sc07B & r::
WrapBracket("|","《》")
send {left}
Return
選択した文字列はルビを振られる文字列になる。
send,{Left} を追記しているのは、ルビを振られる文字列から書き始められるようにするため。
後追いでルビを振るときは大抵元の言葉も弄るから、これでいいのだ。
Google 検索
AutoHotkey は簡易的な GUI を作成できる。
上記した括弧・ショートコード入力同様、ホットキーを指定して呼び出すこともできる。
Google 検索機能と後に紹介する DeepL 翻訳機能、JapanKnowledge 検索機能は、いずれもこの GUI を作成して実現した。
sc07B & l::
stash := ClipboardAll
Clipboard :=
Send, ^c
ClipWait, 0.5
clip := Clipboard
Clipboard := stash
clip := rm_crlf(clip)
Gui, Add, Text, , 英語→日本語
Gui, Add, Text, , (Shift)日本語→英語
Gui, Add, Edit, v_str_deepl w380 -WantReturn
Gui, Add, Button, Default, Translate
Gui, Show, Center w400, DeepL
clip := ""
Return
ButtonTranslate:
Gui, Submit
; Shift押下時はja->en
If GetKeyState("Shift", "P") {
Run, https://www.deepl.com/translator#ja/en/%_str_deepl%
; 直打ちならばen->ja
} Else {
Run, https://www.deepl.com/translator#en/ja/%_str_deepl%
}
GuiEscape:
Gui, Destroy
GuiClose:
Gui, Destroy
Return
sc07B & g::
stash := ClipboardAll
Clipboard :=
Send, ^c
ClipWait, 0.5
clip := Clipboard
Clipboard := stash
If clip !=
IfNotInString, clip, `r`n
{
Run, https://www.google.co.jp/search?q=%clip%
clip := ""
IfWinActive, Chrome
{
return
}else{
WinActivate, Chrome
}
Return
}
Gui, Add, Edit, v_str_google w380 -WantReturn
Gui, Add, Button, Default, Search
Gui, Show, Center w400, Google
Send, {vkF2}
clip := ""
Return
ButtonSearch:
Gui, Submit
Run, https://www.google.co.jp/search?q=%_str_google%
2GuiEscape:
Gui, Destroy
2GuiClose:
Gui, Destroy
Return
; 2:JapanKnowledge検索
sc07B & j::
stash := ClipboardAll
Clipboard :=
Send, ^c
ClipWait, 0.05
clip := Clipboard
Clipboard := stash
If clip !=
IfNotInString, clip, `r`n
{
Run, https://japanknowledge.com/psnl/search/basic/?q1=%clip%
clip := ""
IfWinActive, Chrome
{
return
}else{
WinActivate, Chrome
}
Return
}
Gui, Add, Edit, v_str_japanknowledge w380 -WantReturn
Gui, Add, Button, Default, JKSearch
Gui, Show, Center w400, JapanKnowledge
Send, {vkF2}
clip := ""
Return
ButtonJKSearch:
Gui, Submit
Run, https://japanknowledge.com/psnl/search/basic/?q1=%_str_japanknowledge%
3GuiEscape:
Gui, Destroy
3GuiClose:
Gui, Destroy
Return
やっていることは、括弧・ショートコード入力と大差ない。
選択文字列があれば Ctrl+C を押下し、クリップボードから文字列を取得し、検索用 URL へ変数として埋め込む。
選択文字列がなければ GUI を起動し、入力し Submit された文字列を取得し、検索用 URL へ変数として埋め込む。
サニタイジングが面倒なので、改行コードや記号が選択文字列にあれば無視して、GUI を起動するようにしている。
今後の展望
この記事は「入門編」だ。
当然、後方にはいろいろな記事が控えている。
職場やネカフェで執筆するのに必須、Windows の機能と絡めた『ボスが来た』機能実装のアレコレだとか。
AutoHotkey はアイデア次第でいくらでも便利にできるので飽きない。
興味が湧いたという物好きな人はここから AutoHotkey を落としてインストールしよう。 共に世界の支配構造を打ち砕こうではないか。
最後に
この記事は、下の GitHub Actions を用いて予約投稿しています。
説明記事はこちらです。
あなたも使おう。
Discussion