DiscordでEnter送信されないようにするコードを書いた (by AutoHotkey)

2024/11/17に公開

WindowsのDiscordデスクトップアプリのキーバインドを改造した話です。
Enterで補完確定・改行、Ctrl + Enterで送信 にしています。

ファイルとして公開しているので、Windowsユーザでお困りの方はぜひお使いください。

完成コード

https://github.com/clumsy-ug/discord_ahk_keybind

環境

  • Windows 11 Home
  • 標準搭載のMicrosoft IME
  • Discordアプリ
  • AutoHotkey バージョン2
  • JIS配列キーボード

使い方

すぐに使えます。とても簡単です。

まずAutoHotkeyのv2.0をインストールしてください。
https://www.autohotkey.com/

そして前述の完成コードを載せてあるGitHubの.ahkファイルを自分のPCにも配置してください。

そしてそれをダブルクリックなどによりAutoHotkeyとして実行すればOKです。

実行されているかどうかをタスクトレイから確認してみましょう。緑でHと書かれているマークがAutoHotkeyです。これが見えたら無事プログラムが起動しています。
タスクトレイ上のahkのマーク

...しかし、PCの電源を入れるたびに毎回.ahkファイルをダブルクリックして実行するのは面倒ですよね。

そこで、この.ahkファイルをスタートアップとして登録することで、PC起動時に自動的に起動するようにしましょう。

方法は以下です。

  1. Windows + R
  2. shell:common startupと入力してEnter
  3. 開いたフォルダ内に.ahkファイルを配置

これで完了です。何もしなくても常時使えるようになります。
(PCを起動してから30秒後くらいに自動起動するかと思います)

開発の背景(前提)

(ここからは興味のある方のみぜひご覧ください。)


Discordは以下のようなキーバインドがされています。

  • Enterで送信またはIMEの補完の確定
  • Shift + Enterで改行

これで個人的に困ることは以下です。

  • 半角英数字モードで入力しているとき、Enterを押したら送信されてしまう
  • ひらがなモードで入力しているとき、IMEの補完の確定でEnterを押そうとして誤って2連続でEnterを押してしまった場合、送信されてしまう
  • 改行するたびにわざわざキーを2つ(Shift + Enter)押す必要がある

「誤って送信してしまったので編集するはめになり、編集したことで文の最後に (edited) という邪魔なものがついてしまう」という事象はDiscord界で頻発しているのでは?と思っています。これがストレスでした。

「補完確定」と「送信」のどちらもEnterであるという特性上、ミス送信が頻発することは容易に想像できます。

そもそも、1つの文章につき「送信」は必ず1回しか行いません。
しかし「改行」と「補完確定」が複数回行われるということはよくあります。

なので、面倒なキー押下(2つのキーを押さなければならない)は「送信」に、楽なキー押下(1つのキーだけで済む)は「改行」「補完確定」に割り当てたい訳です。

つまり「送信」はCtrl + Enterに、「改行」「補完確定」はEnterに割り当てれば良いですね。
(あと一応Ctrl + Enterは補完確定もできるようにしておきたい)

実はDiscordアプリ側でキーバインドの設定をすることはできますが、なぜか改行・送信に関するものは用意されていないので、やはりアプリ側でカスタマイズすることは不可能です。
(なぜ用意しないのか、Discord側の思想(理由)が純粋に気になる)

この議題に関する記事はいくつかありますが、どれも前述の理想をかなえてくれるものではありませんでした。そもそもMacでしか動かなかったり、機能が物足りなかったりするものしかありませんでした。

なので自分で頑張って作ってみました。完璧に理想をかなえることができたので詳細を書いていきます。

どんな感じで進めていったか

どんな思考プロセスで進めて、どんなことに苦戦したのかをつらつら書いていきます。


まず、Karabiner-Elementsというソフトウェアで同じことをしている方がいることを知りました。
https://zenn.dev/mh/articles/ccd9fd185a66d4
https://zenn.dev/shuto2828/articles/63edac4f20f057

しかしこれはmacOS専用なのでWindowsでは使えませんでした😢

A powerful and stable keyboard customizer for macOS.

https://karabiner-elements.pqrs.org/


そこで次に、私と同じWindows 11 Homeの環境を使用しているこちらの記事を見ました。
https://note.com/teruyoshikun/n/n0b7e1b45529d

これでAutoHotkeyというソフトウェア(スクリプト言語)の存在を知りました。
これはWindows専用!期待できます。

The ultimate automation scripting language for Windows.

https://www.autohotkey.com/

しかし記事を読んだあと疑問・課題が4つ残りました。

  1. なぜあえて古い方のv1.1を使うのかわからない
    • できれば新しいバージョン2を使いたい
      ahkバージョン画像
  2. なぜ.ahkではなく.ashという拡張子を使うのかわからない
    • 公式では.ahkを使えと書かれている(v1とv2のドキュメント両方で)

    A script is simply a plain text file with the .ahk filename extension containing instructions for the program, like a configuration file, but much more powerful.
    https://www.autohotkey.com/docs/v1/Program.htm

  3. 記事のコードだけだと、補完の確定をしようとEnterを押しても何も起こらない
    • わざわざCtrl + Enterを押さなければ補完確定できない
  4. shell::startupを打ってもエラーになる(調べたらすぐ解決できたけど)
    shellエラー画像

正直動けば良いので1, 2, 4は重要ではないのですが、3が私にとってはクリティカルでした。

ただキーバインドを設定するだけなら簡単にできそうなんですが、今回の様にIMEが関わると複雑になります。

そこで調べるうちに凄く良さげなものを見つけました。
https://w.atwiki.jp/eamat/pages/17.html

AutoHotkey上で日本語入力の制御を可能にするための関数群

ドンピシャだ!と思いました。事実助かりました。
しかし1つだけ問題がありました。

IME_GetConverting関数が機能しないという問題です。最終更新が2012年なので、新しいIMEに対応できていないからだと思われます。
(IME_GET関数は機能する)

名前からわかるように「現在変換中かどうか(入力中かどうか)」を調べることのできる関数です。

変換中は1か2が返ってくるはずなのですが、どんな時でもなぜか0しか返ってこないのです。

これが使えれば、コードは以下のように書くだけで完成していたはずです。

DiscordKeybind.ahk
; Enterが押された時
Enter::
{
    converting := IME_GetConverting()
    if (converting > 0) {  ; もし入力中(補完候補がでている状態)だったら
        SendInput "{Enter}"  ; Enterで補完確定
    } else {  ; もし入力中ではない状態だったら
        SendInput "+{Enter}"  ; Shift + Enter で改行
    }
    return
}

; Ctrl + Enter が押された場合
^Enter::
{
    SendInput "{Enter}"  ; Enterで送信または補完確定
    return
}

自分の環境で試してみた結果、主要な関数の結果はこうなりました。

  • IME_GET
    ひらがなモードなら1、半角英数字モードなら0がちゃんと返ってくる

  • IME_GetConvMode
    9しか返ってこない

  • IME_GetSentenceMode
    8しか返ってこない

  • IME_GetConverting
    0しか返ってこない

ひらがなモードで入力中かどうか(補完が出ているかどうか)の状態が欲しかったので、何としてもIME_GetConverting関数は使いたかったのですが、結局使えませんでした。

また、自分のMicrosoft IMEは新しいバージョンになっていたので、以前のバージョンにあえて戻してみたのですが、それでもIME_GetConvertingは0しか返してくれませんでした。(↓をオンにしてもダメだった)
imeバージョン画像

つまり問題の核は、「関数が新しいMS IMEには対応していない」ということなのですが、結局対応させる方法がわかりませんでした。

なのでIME_GetConverting関数を使用せずに理想を実現するしかありません。


次に考えたのは、Escapeキーを使用する方法です。

ひらがなモードで入力中にEscapeキーを押すと入力中の文字は消えますよね。

ということで、ユーザーがEnterを押した際は裏で以下の処理を行えば良いのではないかと考えました。

ですが、結果全然ダメでした。

なぜなら、そもそも補完を確定してからでないとShift + ←で入力中の文字をコピーできないが、その補完を確定するためにEnterを実行しても良いかどうかはわからない、という問題があるからです。

補完は出ておらず(=補完確定済み)、Shift + Enterで改行したいだけなのかもしれません。

なのでやはり、入力中かどうか(補完が出ているかどうか)という状態を取得しなければならないという根本課題は残り続けたままです。

(11/19追記:Enterではなくクリックで補完確定しておけば可能だったかも。ただクリックは現在のカーソルの位置で実行されてしまうのでできれば使いたくない)


次に、「そういえばマウスクリックでも補完確定できるぞ!」ということに気付いたのでクリック実行関係を試しましたが、これも結局同じ結末でした。

なぜなら、クリックして確実に補完確定後の状態にしたとしても、その後Enterを実行すべきかShift + Enterを実行すべきかわからないからです。

以下のような感じです。

Enterが押される

クリックを実行する(これにより入力中という状態ではなくなることが保証される)

Shift + Enterを実行すべきかEnterを実行すべきかわからない

...やはり入力中かどうかをなんとかして判定しないとならない、という結果でした。


そしていろいろ考えていたら、入力中の文字数を数えるcount変数をうまく使えば理想を実現できることに気付きました。

countとは、先程のフローチャート図でも出てきたやつです。

この変数は、Enterが押される度に0に初期化します。そしてキーが押されるたびに+1します。

それを踏まえると、以下の処理を書けば理想を実現できるはずです。

実際のコード

DiscordKeybind.ahk
; Enter が押された場合
Enter::
{
    ; 確認用
    ; ToolTip("countは: " . count)
    ; SetTimer () => ToolTip(), -2000

    global count
    imeMode := IME_GET()

    if (imeMode) {
        if (count == 0) {
            SendInput "+{Enter}"
        } else {
            SendInput "{Enter}"
            count := 0
        }
    } else {
        SendInput "+{Enter}"
        count := 0
    }

    return
}


; Ctrl + Enter が押された場合
^Enter::
{
    SendInput "{Enter}"
    return
}

これで試してみたらちゃんと動きました。やっとです。

ちなみに、AutoHotkeyのバージョン2に合わせて先程の関数群を更新してくれている方がおり、IME_GET関数はそこから使わせていただきました。私もバージョン2で書いているので、助かりました。
https://qiita.com/kenichiro_ayaki/items/d55005df2787da725c6f
https://github.com/k-ayaki/IMEv2.ahk/blob/master/IMEv2.ahk

...ただ!実はまだ英語を打って最後にひらがなモードに変えてからEnterを押すと送信されてしまうという問題が残っています。

なぜなら、

英語を打って最後にひらがなモードに変えてからEnterを押す

count > 0 かつ ひらがなモード

「補完が出ているはず!Enterで補完確定すべきだ!」と誤った判断がされる

Enterで送信されてしまう

という流れになるからです。

これに対しては、英語モードとひらがなモードを切り替える半角/全角キーを~sc029::で取得できることがわかったので、そのスコープ内にcountを0に初期化する処理を書いて解決しました。

https://so-zou.jp/software/tool/system/auto-hot-key/hotkeys/#:~:text=sc029

DiscordKeybind.ahk
; 半角/全角 が押された場合(「英語->ひらがな」ならcountを0にする)
~sc029::
{
    global count
    ; 押された瞬間のモードが取得できるので、「英語->ひらがな」の変更では「英語」が取得される
    imeMode := IME_GET()

    if (!imeMode) {
        count := 0
    }

    ; 確認用
    ; ToolTip("countは" . count . " / " . "imeModeは" . imeMode)
    ; SetTimer () => ToolTip(), -2000

    return
}

ちなみに、countの処理はこのように書いています。

DiscordKeybind.ahk
; キーが押された回数
global count := 0

; ほぼ全てのキーが押された際の処理(半角/全角キー などは不要なので除く)
~*a::
~*b::
~*c::
~*d::
~*e::
~*f::
~*g::
~*h::
~*i::
~*j::
~*k::
~*l::
~*m::
~*n::
~*o::
~*p::
~*q::
~*r::
~*s::
~*t::
~*u::
~*v::
~*w::
~*x::
~*y::
~*z::
~*1::
~*2::
~*3::
~*4::
~*5::
~*6::
~*7::
~*8::
~*9::
~*0::
~*Space::
~*,::
~*.::
~*/::
~*;::
~*[::
~*]::
~*-::
~*=::
{
    global count
    count++
    
    ; 確認用
    ; ToolTip("countは: " . count)  ; カウントをツールチップで表示
    ; SetTimer () => ToolTip(), -2000  ; 2秒後にツールチップを消す

    return
}

これで完成です🥳

実際に、理想通りの挙動が確認できました。

最後に

この記事と同じような内容の記事は見当たらなかったので、同じように困っている方にとって有益になれば幸いです。

今回のプログラムをWindowsアプリ(ソフトウェア)として配布できたらもっと良いかな?とか思っていますが、それは気が向いたら...。

また、

DiscordKeybind.ahk
#HotIf WinActive("ahk_exe Discord.exe")

という部分にLineなど他のexeも追加すれば、同じキーバインドを適用することができるはずです。(まだ試してない)

今回の機能は私自身普段使いしているので、使っていく中で対応できていないケースを発見したらその都度修正して以下に追記していこうと思います。

追記(Fix)

【2024/11/17】

  • Ctrl + V(コピペ)->Enter で送信されてしまう挙動を修正
  • クリック(補完確定)->Enter で送信されてしまう挙動を修正
  • コピペ->全角スペース->Enter で送信されてしまう挙動を修正

【11/18】

  • Ctrl + Enter(補完確定)->Enter で送信されてしまう挙動を修正
  • 全角の, , , , , , , _がEnterで補完確定できない挙動を修正
  • 英語で入力->CapsLockでひらがなモードに変更->Enter で送信されてしまう挙動を修正

【11/19】

  • ひらがなモードで入力中にCtrl + v->Enter で補完確定できない挙動を修正

【11/20】

  • ひらがなモードかつ入力中でない時にCtrl + c->Enter で送信されてしまう挙動を修正
  • 入力中の文字をBackspaceですべて消す->Enter で送信されてしまう挙動を修正
  • テンキーパッドの/, *, + -> Enterで補完確定できない挙動を修正
  • テンキーパッドのEnterで送信されてしまう挙動を修正
GitHubで編集を提案

Discussion