英日キーボードが混在する環境で生きる
新しいノートPCを買ったらキーボードが英字キーボードでした。
手持ちの外付けキーボードは日本語キーボードばっかり。
英字キーボードは以前使っていたから、日本語キーボードも印字の違いは気にせずに使う。
問題は、IMEの切り替えだ。
文章を入力しているときに、「今IMEがオンかオフか」はあまり気にしたくない。あるキーを押せばオン、別のキーを押せばオフにしてほしい。
英字キーボードの場合は左右のAltだし、日本語キーボードの場合は、無変換と変換を使いたい。
いくつかの選択肢
こちらに、英日混在環境の作り方がきちんと書いてある。
まあ、この通りにすればいいんだけど、Alt+Tabがどうも使えなくなるみたい。僕はかなりAlt+Tabを使うので、ストレスが大きくなってしまった。
というわけで、自分でやることにした。
候補はKeyhacとAutoHotKey。
ChatGPTに聞きながら、両者を並行してスクリプトを作成してみた。最終的になんとなくうまく行ったのが、Keyhacの方だ。AutoHotKeyの方が、OSのより深いレベルで制御しているそうなので、Keyhacでどうしようもなくなれば、AutoHotKeyに頼るべきなのかも知れない。ただ、KeyhacはスクリプトをPythonで書けるということもあり、先にKeyhac版が完成した。
開発の悩みは、Altを押すとMenuにフォーカスが移ってしまうという挙動の制御。Altをもう一度押すと良いアプリとか、Escを押すべきなアプリ、はたまたフォーカスが移らないアプリなど、いろいろだ。
上記サイトで紹介されていたTAALTというツールを使えば、この問題は一発で解決する。が、別のツールを入れずにKeyhacかAutoHotKey単独で実現するならそれがベストだ。
そのへんの制御を入れつつ、作っていったが、MicrosoftOfficeの挙動がまた特殊で、事前にESCを送信する処理をいれるとうまく行った。が、Officeのばあい、ESCを送出するとダイアログが閉じてしまうので、ファイル名等の入力には使えない。この問題は未だに解決できていない。
解答例
この記事はエッセイではないので、僕の現時点での解答を以下に示す。
import sys
import os
import datetime
import time
import pyauto
from keyhac import *
def configure(keymap):
# グローバルキー設定
keymap_global = keymap.defineWindowKeymap()
# 特定アプリケーションでESCなどを送信する処理
office_apps = ["winword.exe", "excel.exe", "powerpnt.exe"]
esc_apps = office_apps + ["chrome.exe", "notepad.exe"]
# C-h l でキーログを見る
def set_ime(status):
if status in [0, 1]: # 有効な値か確認
keymap.getWindow().setImeStatus(status)
#print(f"IME is {'ON' if status == 1 else 'OFF'}")
else:
print("Invalid status: Use 0 (OFF) or 1 (ON)")
def set_ime_on_simple():
set_ime(1)
def set_ime_off_simple():
set_ime(0)
# IMEをオンにする関数
def set_ime_on():
active_window = keymap.getWindow().getProcessName()
if any(app in active_window.lower() for app in office_apps):
keymap.InputKeyCommand("Esc")() # ESCキーを送信
set_ime(1)
if any(app in active_window.lower() for app in esc_apps):
time.sleep(0.5)
keymap.InputKeyCommand("Esc")() # ESCキーを送信
elif "emacs.exe" in active_window.lower():
return
else:
keymap.InputKeyCommand("Alt")() # Altキーを再送信してフォーカスをリセット
# IMEをオフにする関数
def set_ime_off():
active_window = keymap.getWindow().getProcessName()
if any(app in active_window.lower() for app in office_apps):
time.sleep(0.2)
keymap.InputKeyCommand("Esc")() # ESCキーを送信
set_ime(0)
if any(app in active_window.lower() for app in esc_apps):
keymap.InputKeyCommand("Esc")() # ESCキーを送信
elif "emacs.exe" in active_window.lower():
return
else:
keymap.InputKeyCommand("Alt")() # Altキーを再送信してフォーカスをリセット
# 右Altキー単押しでIMEをオンに設定
keymap_global["O-RAlt"] = set_ime_on # IMEオンの処理を呼び出す
# 「変換」キーでIMEをオンに設定
keymap_global["O-(255)"] = set_ime_on_simple
# 左Altキー単押しでIMEをオフに設定
keymap_global["O-LAlt"] = set_ime_off
# 「無変換」キーでIMEをオフに設定
keymap_global["O-(235)"] = set_ime_off_simple