お絵描きアプリの入力色の類いを一発で切り替えるAutoHotkeyレシピ(Ankiも例に)

# 色切り替え問題

例えば、「お絵描き系アプリで色を頻繁に素早く切り替えたい」と言った類いの要求はパソコンを使っているとよく発生する。

5色程度の中で切り替えるならショートカットキーを割り当てることも可能だが、数十以上の選択肢からこまめに切り替えるのは大変だ。

ショートカットがアプリ側で設定できないこともある。例えば、「ペイント」アプリケーションでは「色の編集」をいちいちクリックしないといけない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34296/0b5aa7e1-31db-ffe6-89cd-575e23a0401b.png)

そんな時にもAutoHotkeyが役に立つ。


# 基本的な書き方

簡単のためr, g, bの色で切り替えることを考える。

```autohotkey:example1.ahk
#If WinActive("ahk_exe mspaint.exe")

; Alt+Cに続いてr,g,bを入力することで色を変更する
!c::
; L2にすれば2キーストロークにも対応できる
Input, cl, L1 T3, {Enter}, r,g,b
If(ErrorLevel = "Match"){
    ; 簡単のためボタンは固定位置と仮定したが、変動しても使えるにはImageSearchを用いる。
    SendInput, {Click 1020 90}
    WinWaitActive, 色の編集
    rval := cl == "r" ? 255 : 0
    ControlSetText, Edit4, %rval%
    gval := cl == "g" ? 255 : 0
    ControlSetText, Edit5, %gval%
    bval := cl == "b" ? 255 : 0
    ControlSetText, Edit6, %bval%
}
return

#If
```
結果　例えばAlt+Cに続いてbを入力するとこういう小窓が開く。必要であれば微調整してからEnterで色を確定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34296/6aff92f8-190b-2a75-170c-b77058b1b17f.png)



# 参考　PCCS色彩体系に基づく簡易入力

前項で2キーストロークにも対応できると述べたが、2キーストロークあれば数百もの色を入力できる。
と聞いて、どのキーの組み合わせでどんな色が出せるか数百通りも記憶するなど不可能だと思うかもしれない。
**PCCS色彩体系**を用いれば可能である。色相環とは人間の感覚に合った色見本である。色彩体系と言えば2000色あるマンセル色相環を用いる選択もあるが色数が多すぎるので、およそ200色というコンパクトな色見本が提供されているPCCS色彩体系を用いる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34296/59eeb2cc-caa1-e904-6157-bd2efd110bfb.png)
PCCSでは色は **色相(hue)** と **色調(tone)** で表される。画像の左側には色相が並んでおり [^1] それぞれに英字大文字が付与されている。右側には色調が並びそれぞれに英字小文字が添えられている。(上部の正方形の図は大して重要ではないが、こうしたアルファベットに紐付けられた情報は5x5(+1)の形で捉えると覚えやすいことが多いと個人的には思う。)

これを用いて、例えばvividな緑を選択するには、緑はLでありvividはaなので、Laと入力する。ちなみに、Inputコマンドでは既定では文字の大小は無視される。全く色みのないグレーを入力するにはZを前置する。(さらに私はお気に入り色を登録して入力する仕組みも付けている。)

具体的な実装としては、CSVに英字2文字とRGB値との対応を記述するなどし、それを先の例のrval, gval, bvalとする。

[^1]: 色調はPCCSを元に拡張されたもので、[トーン別の色相カラーチャート](https://iro-color.com/colorchart/tone/)からお借りした。色相&色調とRGB値の対応もこのサイトが参考になる。


# Ankiの場合

続いて、昨今流行っているカード型復習管理アプリ「**Anki**」を例にとろう。Ankiでノートを書いている時に、文字色を素早く変えたいという需要は大きいと思われる。特に手入力が多い人にとっては。

## こんな例を考える

ノート編集でこのように入力すると――
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34296/05d83a72-f073-e272-0daa-4fac27321354.png)

このような問題(カード)が作られるようにしている。具体的な仕様やJavaScriptの記述は割愛するが、例文の青色背景の語句が学習語句で、緑色背景の語句が共起表現である。
表面:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34296/8e9b73af-6644-0ee4-d5a9-8c167e424a29.png)
裏面:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34296/74aa8a57-7342-d6a5-0e03-a2c42fd2b96e.png)

## 新しい色を追加する

ここで、vermicompostも伏せて出題したい。

重要な共起表現ではないので、今度は青緑色で太字でない文字にする。青色や緑色はマークダウン記法(強調記法** **と独自記法 == ==)を解析した結果の表示となるが、青緑色はmarkタグを直書きするものとする。


```html
<mark style="background-color:#afd">vermicompost<mark>
```
ノートの例文フィールドはこうなる。黒背景になっているのはHTMLソースを表示するアドオンを用いている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34296/6299df7f-8b6d-41f6-6636-3d5486da3a9f.png)
するとこう出題されるようになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34296/209b244a-3c4f-d12e-92ae-3a1364ba0a58.png)

## 色の選択を増やし、指定を簡易にする

この青緑色の部分を色んな色で設定できるようにしたい。どうすればいいだろう？


## 基本的な書き方(Anki編)

この場合は「ペイント」と異なり、メインウィンドウで用いるのではなく小窓で用いるため、小窓でしかホットキーが発動しないように書く必要がある。具体的にはWinActive()の引数にウィンドウタイトルの条件を指定する。ここでは拡張性のため正規表現指定モードをテンプレとしている。

```autohotkey:example2.ahk
#If WinActive("ahk_exe Anki.exe")

!c::
SetTitleMatchMode, RegEx
If(WinActive("(?:^現在のノートを編集|^追加)$ ahk_exe anki.exe")){
    global anki_waiting_input := 1
    Input, cl, L1 T3, {Enter}, r,g,b,e,f,v,w
    global anki_waiting_input := 0
    If(ErrorLevel = "Match")
        SetAnkiBackgroundColor(cl) ; 具体的な処理は後述
}else{
    SendInput, !c
}
return

#If
```

ちなみに、r, g, bに加えてe, f, v, wが色に指定できるが、eはmagenta, fはyellow, vはcyan, wはwhiteを意味する。


## ホットキー衝突の回避

これまで触れないで来たがInputコマンドを使用する時には1つ留意点があって、Inputコマンドで待機するキーと他のホットキーの衝突を回避する必要がある。(ここでは小窓だけでなくAnki全体で#Ifディレクティブを用いているのでなおさら衝突しやすい。)

色んな対策があると思うが、ここでは、「global anki_waiting_input」を用いることで、他ホットキーからInput待機中か否かが分かるようにしてある。

例えば、Ankiではショートカットキー「e」で表示中のカードの編集ができるが、この時に開かれる小窓の位置を調整するためにeホットキーを次のように定義したとする。
```autohotkey:example3.ahk
~e::
SetTitleMatchMode, RegEx
cannotEdit := WinActive("^(検索|Statistics)")
editing := WinActive("^(追加|現在のノートを編集)$ ahk_exe anki.exe")
; 編集不可ウィンドウまたは元々編集ウィンドウでは何もしない
If(cannotEdit or editing)
    return

; 開いたウィンドウを定位置にやる
WinWaitActive, ^(追加|現在のノートを編集)$ ahk_exe anki.exe, , 2
If(ErrorLevel = 0)
    WinMove, 0, 300
return

```
「e::」ではなく「~e::」としたのは、生入力「e」をシステムに送ることで、Anki側のショートカットキーを発動させている。

しかしこれは前掲のAlt+cのホットキーと衝突する。Alt+Cホットキー内のInputで待機する文字に「e」が含まれるからだ。
そこで、Input待機中はeホットキーを中断させる。次のように書く。
```autohotkey:example4.ahk
~e::
global anki_waiting_input

; Input待機中は何もしない
If(anki_waiting_input == 1)
    return

SetTitleMatchMode, RegEx
cannotEdit := WinActive("^(検索|Statistics)")
editing := WinActive("^(追加|現在のノートを編集)$ ahk_exe anki.exe")
; 編集不可ウィンドウまたは元々編集ウィンドウでは何もしない
If(cannotEdit or editing)
    return

; 開いたウィンドウを定位置にやる
WinWaitActive, ^(追加|現在のノートを編集)$ ahk_exe anki.exe, , 2
If(ErrorLevel = 0)
    WinMove, 0, 300
return

```

## 色を設定する処理の記述

最後に色を設定する関数SetAnkiBackgroundColor()の中身について。コードは下記。


```autohotkey:example5.ahk

SetAnkiBackgroundColor(cl){
    ; ノート編集ウィンドウでハイライトの色を設定する
    ; 要IME.ahk

    rgb :=
    (Join C
    ({
        r: [255, 192, 192],
        g: [192, 255, 192],
        b: [192, 192, 255],
        e: [255, 192, 255], ; magenta
        f: [255, 255, 192], ; yellow
        v: [192, 255, 255], ; cyan
        w: [255, 255, 255]  ; white
    })[cl]
    )

    ; 色の選択を開く
    SendInput, ^+n
    WinWaitActive, 色を選択, , 1
    IME_SET(0)

    SendInput, !r
    SendInput, % rgb[1]
    IME_SET(0)
    SendInput, {Tab}
    Sleep, 50
    SendInput, % rgb[2]
    IME_SET(0)
    Sleep, 50
    SendInput, {Tab}
    Sleep, 50
    SendInput, % rgb[3]
    SendInput, {Enter}
}

```
「ペイント」とは異なり、RGB値を指定する入力ボックスにはClassNN(クラス名)が付与されていないので、ショートカットでボックスに移動してはキー入力を送るということをR, G, Bについて行う。

IMEの動作が安定せず他のボックスに移動した時にオフにした日本語入力がオンになるといったことが起きるようなので、泥臭く何度もIME_SET(0)を送信している。また、Tabで次のボックスに移動した直後の入力も安定しないので、スリープをいちいち挟んでいる。

あと、「(Join C」の部分はヒアドキュメントにおいて、コメントを無視して各行を連結することを指定している。ちなみに、このコードはAutoHotkey v1向けであるが、AutoHotkey v2からはヒアドキュメントを使わずに普通にJavaScriptのようなオブジェクトリテラルを書ける。


## 完成

これでAnkiで編集時の色設定をラクラクにするAutoHotkeyスクリプトは完成した。

例えば、こういう編集ウィンドウの時に――
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34296/97a6d74f-3195-0aee-5840-426911c53d7a.png)

例文フィールドの「in」を選択してAlt+C, eと入力することで瞬時にマゼンタに背景色を切り替えられる:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34296/b8cc4ec9-6fd4-e7d1-157c-7425f493ea8a.png)
ソース:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34296/9dc6e5d9-34d4-2f8c-74c2-f785ed35e09a.png)
マゼンタ色の場合は注目を促すだけで出題時に伏せないことにしている:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34296/13912b46-5c97-5776-9146-bbcccd069e28.png)