はじめに
Windowsを再インストールしました。wordなどもemacs likeなキーバインドで動かしたいので、設定を持ってきました。
前提(背景)
macOS + Parallels + Win 10をつかっています。MBPがM1になったので、Parallesの仮想マシンを新規につくり、新規にWin 11を入れました。
以前にもkeyhacでemacs likeのキーバインドを実現していました。定着しすぎていて、設定の記録が残っていませんでした。下記には「keyhacをつかおうかな」とは書いてあって、その後微調整しているはずですが、あまりにもいい感じすぎてメモが残っていませんでした
やったこと
keyhacのダウンロード craftware - Keyhac (日本語)
解凍したものをDocument下に配置
前から使っていたconfig.pyをコピー
スタートアップフォルダにショートカットを登録
config.pyをコピー
今となってはどうやってつくったか思い出せない。が、じゅうぶんいい感じなのでこのまま使うことにします。
たぶん、ここから引っ張ってきた→ Windows の操作を Emacs のキーバインドで行うための設定 (Keyhac版) - NTEmacs @ ウィキ【3/15更新】 - atwiki(アットウィキ)
さらに原点はここである様子 → GitHub - smzht/fakeymacs: Emacs-like key bindings for Keyhac
スタートアップフォルダの開き方
エクスプローラにshell:startup
と入力
環境
ここで書いていることは、下記のバージョンで実施しました。
- keyhac 1.82
- Windows 11 Home 21H2
- Parallels 17.1.1 (51537)
- macOS Monterey 12.2.1
- MacBook Pro (14-inch, 2021)
ご参考:config.py
# -*- mode: python; coding: utf-8-with-signature-dos -*- ## nickname: Fakeymacs Light ## ## Windows の操作を Emacs のキーバインドで行うための設定 Light(Keyhac版)ver.20200820_01 ## # このスクリプトは、Keyhac for Windows ver 1.82 以降で動作します。 # https://sites.google.com/site/craftware/keyhac-ja # スクリプトですので、使いやすいようにカスタマイズしてご利用ください。 # # この内容は、utf-8-with-signature-dos の coding-system で config.py の名前でセーブして # 利用してください。 # # 本設定を利用するための仕様は、以下を参照してください。 # # <共通の仕様> # ・emacs_target_class 変数、not_emacs_target 変数、ime_target 変数で、Emacsキーバインドや # IME の切り替えキーバインドの対象とするアプリケーションソフトを指定できる。 # ・skip_settings_key 変数で、キーマップ毎にキー設定をスキップするキーを指定できる。 # ・emacs_exclusion_key 変数で、Emacs キーバインドから除外するキーを指定できる。 # ・not_clipboard_target 変数で、clipboard 監視の対象外とするアプリケーションソフトを指定 # できる。 # ・左右どちらの Ctrlキーを使うかを side_of_ctrl_key 変数で指定できる。 # ・左右どちらの Altキーを使うかを side_of_alt_key 変数で指定できる。 # ・キーバインドの定義では次の表記が利用できる。 # ・S- : Shiftキー # ・C- : Ctrlキー # ・A- : Altキー # ・M- : Altキー と Esc、C-[ のプレフィックスキーを利用する3パターンを定義 # (Emacsキーバインド設定で利用可。emacs の Meta と同様の意味。) # ・Ctl-x : ctl_x_prefix_key 変数で定義されているプレフィックスキーに置換え # (Emacsキーバインド設定で利用可。変数の意味は以下を参照のこと。) # ・(999) : 仮想キーコード指定 # # <Emacsキーバインド設定と IME の切り替え設定を有効にしたアプリケーションソフトでの動き> # ・toggle_input_method_key 変数と set_input_method_key 変数の設定により、IME を切り替える # キーを指定できる。 # ・use_emacs_ime_mode 変数の設定により、Emacs日本語入力モードを使うかどうかを指定 # できる。Emacs日本語入力モードは、IME が ON の時に文字(英数字か、スペースを除く # 特殊文字)を入力すると起動する。 # Emacs日本語入力モードでは、次のキーのみが Emacsキーバインドとして利用でき、 # その他のキーは emacs_ime_mode_key 変数に設定したキーにより置き換えがされた後、 # Windows にそのまま渡されるようになる。 # ・Emacs日本語入力モードで使える Emacsキーバインドキー # ・C-[ # ・C-b、C-f # ・C-p、C-n # ・C-a、C-e # ・C-h # ・C-d # ・C-m # ・C-g # ・scroll_key 変数で指定したスクロールキー # Emacs日本語入力モードは、次の操作で終了する。 # ・Enter、C-m または C-g が押された場合 # ・[半角/全角] キー、A-` キーが押された場合 # ・BS、C-h 押下直後に toggle_input_method_key 変数や set_input_method_key 変数の # disable で指定したキーが押された場合 # (間違って日本語入力をしてしまった時のキー操作を想定しての対策) # ・Emacs日本語入力モードの使用を有効にした際、emacs_ime_mode_balloon_message 変数の # 設定でバルーンメッセージとして表示する文字列を指定できる。 # # <Emacsキーバインド設定を有効にしたアプリケーションソフトでの動き> # ・use_ctrl_i_as_tab 変数の設定により、C-iキーを Tabキーとして使うかどうかを指定できる。 # ・use_esc_as_meta 変数の設定より、Escキーを Metaキーとして使うかどうかを指定できる。 # use_esc_as_meta 変数が True(Metaキーとして使う)に設定されている場合、ESC の # 二回押下で ESC が入力される。 # ・ctl_x_prefix_key 変数の設定により、Ctl-xプレフィックスキーに使うキーを指定できる。 # ・scroll_key 変数の設定により、スクロールに使うキーを指定できる。scroll_key 変数を # None に設定するなどして C-v の指定を外すと、C-v が Windows の 「ペースト」として # 機能するようになる。 # ・C-c、C-z は、Windows の「コピー」、「取り消し」が機能するようにしている。 # ctl_x_prefix_key 変数が C-x 以外に設定されている場合には、C-x が Windows の # 「カット」として機能するようにしている。 # ・C-k を連続して実行しても、クリップボードへの削除文字列の蓄積は行われない。 # 複数行を一括してクリップボードに入れたい場合は、削除の範囲をマークして削除するか # 前置引数を指定して削除する。 # ・C-y を前置引数を指定して実行すると、ヤンク(ペースト)の繰り返しが行われる。 # ・C-l は、アプリケーションソフト個別対応とする。recenter 関数で個別に指定すること。 # この設定では、Sakura Editor のみ対応している。 # ・キーボードマクロの再生時に IME の状態に依存した動作とならないようにするため、 # キーボードマクロの記録と再生の開始時に IME を強制的に OFF にするようにしている。 # ・kill-buffer に Ctl-x k とは別に M-k も割り当てている。プラウザのタブを削除する際 # などに利用可。 # ・use_ctrl_digit_key_for_digit_argument 変数の設定により、数引数の指定に Ctrl+数字 # キーを使うかを指定できる。 # ・reconversion_key 変数の設定により、IME の「再変換」を行うキーを指定できる。 # # <全てのアプリケーションソフトで共通の動き> # ・use_alt_digit_key_for_f1_to_f12 の設定により、F1 から F12 を Alt+数字キー列として # 使うかを指定できる。 # ・use_alt_shift_digit_key_for_f13_to_f24 の設定により、F13 から F24 を Alt+Shift+数字 # キー列として使うかを指定できる。 # ・window_switching_key 変数に設定したキーにより、アクティブウィンドウの切り替えが行われる。 # ・word_register_key 変数に設定したキーにより、IME の「単語登録」プログラムの起動が # 行われる。 import time import sys import os.path import re import fnmatch import copy import types import ctypes import keyhac_keymap from keyhac import * def configure(keymap): #################################################################################################### ## 初期設定 #################################################################################################### keymap.editor = r"notepad.exe" keymap.setFont("MS ゴシック", 12) # カスタマイズパラメータを格納するクラスを定義する class FakeymacsConfig: pass fc = fakeymacs_config = FakeymacsConfig() P = fc # 移行をスムースに行うため、当面残す # Fakeymacs を制御する変数を格納するクラスを定義する class Fakeymacs: pass fakeymacs = Fakeymacs() # OS に設定しているキーボードタイプが日本語キーボードかどうかを設定する(自動設定) # (True: 日本語キーボード、False: 英語キーボード) # ( http://tokovalue.jp/function/GetKeyboardType.htm ) if ctypes.windll.user32.GetKeyboardType(0) == 7: is_japanese_keyboard = True else: is_japanese_keyboard = False try: with open(dataPath() + "\config_personal.py", "r", encoding="utf-8") as f: config_personal = f.read() except: print("個人設定ファイル config_personal.py は存在しないため、読み込みしていません") config_personal = "" def read_config_personal(section): if config_personal: m = re.match(r".*(#\s{}.*?((?=#\s\[section-)|$)).*".format(re.escape(section)), config_personal, flags=re.DOTALL) try: config_section = m.group(1) config_section = re.sub(r"^##.*", r"", config_section, flags=re.MULTILINE) except: config_section = "" print("個人設定ファイルのセクション {} の読み込みに失敗しました".format(section)) else: config_section = "" return config_section # 個人設定ファイルのセクション [section-init] を読み込んで実行する exec(read_config_personal("[section-init]"), dict(globals(), **locals())) #################################################################################################### ## 機能オプションの選択 #################################################################################################### # IMEの設定(3つの設定のいずれか一つを True にする) fc.use_old_Microsoft_IME = True fc.use_new_Microsoft_IME = False fc.use_Google_IME = False # 個人設定ファイルのセクション [section-options] を読み込んで実行する exec(read_config_personal("[section-options]"), dict(globals(), **locals())) #################################################################################################### ## 基本設定 #################################################################################################### ########################################################################### ## カスタマイズパラメータの設定 ########################################################################### # Emacs のキーバインドにするウィンドウのクラスネームを指定する(全ての設定に優先する) fc.emacs_target_class = ["Edit"] # テキスト入力フィールドなどが該当 # Emacs のキーバインドに“したくない”アプリケーションソフトを指定する # (Keyhac のメニューから「内部ログ」を ON にすると processname や classname を確認することができます) fc.not_emacs_target = ["bash.exe", # WSL "ubuntu.exe", # WSL "ubuntu1604.exe", # WSL "ubuntu1804.exe", # WSL "ubuntu2004.exe", # WSL "debian.exe", # WSL "kali.exe", # WSL "SLES-12.exe", # WSL "openSUSE-42.exe", # WSL "openSUSE-Leap-15-1.exe", # WSL "mstsc.exe", # Remote Desktop "WindowsTerminal.exe", # Windows Terminal "mintty.exe", # mintty "Cmder.exe", # Cmder "ConEmu.exe", # ConEmu "ConEmu64.exe", # ConEmu "emacs.exe", # Emacs "emacs-X11.exe", # Emacs "emacs-w32.exe", # Emacs "gvim.exe", # GVim "Code.exe", # VSCode "xyzzy.exe", # xyzzy "VirtualBox.exe", # VirtualBox "XWin.exe", # Cygwin/X "XWin_MobaX.exe", # MobaXterm/X "Xming.exe", # Xming "vcxsrv.exe", # VcXsrv "X410.exe", # X410 "putty.exe", # PuTTY "ttermpro.exe", # TeraTerm "MobaXterm.exe", # MobaXterm "TurboVNC.exe", # TurboVNC "vncviewer.exe", # UltraVNC "vncviewer64.exe", # UltraVNC "Xpra-Launcher.exe", # Xpra ] # IME の切り替え“のみをしたい”アプリケーションソフトを指定する # (指定できるアプリケーションソフトは、not_emacs_target で(除外)指定したものからのみとなります) fc.ime_target = ["bash.exe", # WSL "ubuntu.exe", # WSL "ubuntu1604.exe", # WSL "ubuntu1804.exe", # WSL "ubuntu2004.exe", # WSL "debian.exe", # WSL "kali.exe", # WSL "SLES-12.exe", # WSL "openSUSE-42.exe", # WSL "openSUSE-Leap-15-1.exe", # WSL "WindowsTerminal.exe", # Windows Terminal "mintty.exe", # mintty "Cmder.exe", # Cmder "ConEmu.exe", # ConEmu "ConEmu64.exe", # ConEmu "gvim.exe", # GVim "Code.exe", # VSCode "xyzzy.exe", # xyzzy "putty.exe", # PuTTY "ttermpro.exe", # TeraTerm "MobaXterm.exe", # MobaXterm ] # キーマップ毎にキー設定をスキップするキーを指定する # (リストに指定するキーは、define_key の第二引数に指定する記法のキーとしてください。"A-v" や "C-v" # のような指定の他に、"M-f" や "Ctl-x d" などの指定も可能です。) # (ここで指定したキーに新たに別のキー設定をしたいときには、define_key2 関数を利用してください) fc.skip_settings_key = {"keymap_global" : [], "keymap_emacs" : [], "keymap_ime" : [], "keymap_ei" : [], "keymap_tsw" : [], "keymap_lw" : [], "keymap_edit_mode" : [], } # Emacs のキーバインドにするアプリケーションソフトで、Emacs キーバインドから除外するキーを指定する # (リストに指定するキーは、Keyhac で指定可能なマルチストロークではないキーとしてください。 # Fakeymacs の記法の "M-f" や "Ctl-x d" などの指定はできません。"A-v"、"C-v" などが指定可能です。) # (ここで指定しなくとも、左右のモディファイアキーを使い分けることで入力することは可能です) fc.emacs_exclusion_key = {"chrome.exe" : ["C-l", "C-t"], "msedge.exe" : ["C-l", "C-t"], "firefox.exe" : ["C-l", "C-t"], } # clipboard 監視の対象外とするアプリケーションソフトを指定する fc.not_clipboard_target = [] ## Microsoft Excel 2019 以降の Excel では、次の設定は不要のようです fc.not_clipboard_target += ["EXCEL.EXE"] # Excel # 左右どちらの Ctrlキーを使うかを指定する("L": 左、"R": 右) fc.side_of_ctrl_key = "L" # 左右どちらの Altキーを使うかを指定する("L": 左、"R": 右) fc.side_of_alt_key = "L" # 左右どちらの Winキーを使うかを指定する("L": 左、"R": 右) fc.side_of_win_key = "L" # C-iキーを Tabキーとして使うかどうかを指定する(True: 使う、False: 使わない) fc.use_ctrl_i_as_tab = False ## change default at 2020/09/04 due to Excel 経費精算の補完キー # Escキーを Metaキーとして使うかどうかを指定する(True: 使う、False: 使わない) fc.use_esc_as_meta = False # Ctl-xプレフィックスキーに使うキーを指定する # (Ctl-xプレフィックスキーのモディファイアキーは、Ctrl または Alt のいずれかから指定してください) fc.ctl_x_prefix_key = "C-x" # スクロールに使うキーの組み合わせ(Up、Down の順)を指定する fc.scroll_key = None # PageUp、PageDownキーのみを利用する # fc.scroll_key = ["M-v", "C-v"] # comment outed @ 200824 # Emacs日本語入力モードを使うかどうかを指定する(True: 使う、False: 使わない) fc.use_emacs_ime_mode = True # Emacs日本語入力モードが有効なときに表示するバルーンメッセージを指定する # fc.emacs_ime_mode_balloon_message = None fc.emacs_ime_mode_balloon_message = "▲" # IME をトグルで切り替えるキーを指定する(複数指定可) fc.toggle_input_method_key = [] fc.toggle_input_method_key += ["C-Yen"] fc.toggle_input_method_key += ["C-o"] # fc.toggle_input_method_key += ["O-LAlt"] #--------------------------------------------------------------------------------------------------- # IME を切り替えるキーの組み合わせ(disable、enable の順)を指定する(複数指定可) # (toggle_input_method_key のキー設定より優先します) fc.set_input_method_key = [] ## 日本語キーボードを利用している場合、[無変換] キーで英数入力、[変換] キーで日本語入力となる fc.set_input_method_key += [["(29)", "(28)"]] ## LAlt の単押しで英数入力、RAlt の単押しで日本語入力となる # fc.set_input_method_key += [["O-LAlt", "O-RAlt"]] ## C-j や C-j C-j で 英数入力となる(toggle_input_method_key の設定と併せ、C-j C-o で日本語入力となる) # fc.set_input_method_key += [["C-j", None]] ## C-j で英数入力、C-o で日本語入力となる(toggle_input_method_key の設定より優先) # fc.set_input_method_key += [["C-j", "C-o"]] #--------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------- # IME の「再変換」を行うキーを指定する ## IME の「再変換」のために利用するキーを設定する(複数指定可) ## (Google日本語入力を利用する場合、Ctrl キーと組み合わせたキーを設定してください。「確定取り消し」 ## が正常に動作しないアプリケーションソフト(Microsoft Excel、Sakura Editor など)があります。 ## ただし、C-Back キーは設定しないでください。) fc.reconversion_key = [] fc.reconversion_key += ["C-t"] # fc.reconversion_key += ["(28)"] # [変換] キーを利用する場合でも、本機能を全て使うためには設定が必要 # fc.reconversion_key += ["O-RAlt"] # ワンショットモディファイアの指定も可能 ## IME に設定してある「再変換」、「確定取り消し」を行うキーを指定する ## Windows 10 1909 以前の Microsoft IME の場合 ## (Windows 10 1909 以前の Microsoft IME の場合、C-t を押下して確定の取り消しの状態に入った後、 ## Ctrl キーを押したままで C-n による選択メニューの移動を行おうとすると正常に動作しません。 ## 一度 Ctrl キーを離す、メニューの移動に Space キーを利用する、ime_cancel_key に "W-Slash" を ## 設定して「再変換」の機能として利用するなど、いくつかの回避方法があります。お試しください。) if fc.use_old_Microsoft_IME: fc.ime_reconv_key = "W-Slash" # 「再変換」キー fc.ime_cancel_key = "C-Back" # 「確定の取り消し」キー fc.ime_reconv_region = False # 「再変換」の時にリージョンの選択が必要かどうかを指定する fc.ime_reconv_space = False # リージョンを選択した状態で Space キーを押下した際、「再変換」が働くか # どうかを指定する ## Windows 10 2004 以降の 新しい Microsoft IME の場合 ## (新しい Microsoft IME には確定取り消し(C-Backspace)の設定が無いようなので、「再変換」のキー ## を設定しています) if fc.use_new_Microsoft_IME: fc.ime_reconv_key = "W-Slash" # 「再変換」キー fc.ime_cancel_key = "W-Slash" # 「確定の取り消し」キー fc.ime_reconv_region = False # 「再変換」の時にリージョンの選択が必要かどうかを指定する fc.ime_reconv_space = True # リージョンを選択した状態で Space キーを押下した際、「再変換」が働くか # どうかを指定する ## Google日本語入力の場合 if fc.use_Google_IME: fc.ime_reconv_key = "W-Slash" # 「再変換」キー fc.ime_cancel_key = "C-Back" # 「確定の取り消し」キー fc.ime_reconv_region = True # 「再変換」の時にリージョンの選択が必要かどうかを指定する fc.ime_reconv_space = False # リージョンを選択した状態で Space キーを押下した際、「再変換」が働くか # どうかを指定する #--------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------- # Emacs日本語入力モードを利用する際に、IME のショートカットを置き換えるキーの組み合わせ # (置き換え先、置き換え元)を指定する # (if 文箇所は、Microsoft IME で「ことえり」のキーバインドを利用するための設定例です。 # この設定は、Google日本語入力で「ことえり」のキー設定になっている場合には不要ですが、 # 設定を行っても問題はありません。) fc.emacs_ime_mode_key = [] fc.emacs_ime_mode_key += [["C-i", "S-Left"], # 文節を縮める ["C-o", "S-Right"], # 文節を伸ばす ["C-j", "F6"], # ひらがなに変換 ["C-k", "F7"], # 全角カタカナに変換 ["C-l", "F9"], # 全角英数に表示切替 ["C-Semicolon", "F8"]] # 半角に変換 if is_japanese_keyboard: fc.emacs_ime_mode_key += [["C-Colon", "F10"]] # 半角英数に表示切替 else: fc.emacs_ime_mode_key += [["C-Quote", "F10"]] # 半角英数に表示切替 #--------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------- # IME の「単語登録」プログラムを利用するための設定を行う ## IME の「単語登録」プログラムを起動するキーを指定する # fc.word_register_key = None fc.word_register_key = "C-CloseBracket" ## IME の「単語登録」プログラムとそのパラメータを指定する ## Microsoft IME の場合 if fc.use_old_Microsoft_IME or fc.use_new_Microsoft_IME: fc.word_register_name = r"C:\Windows\System32\IME\IMEJP\IMJPDCT.EXE" fc.word_register_param = "" ## Google日本語入力の場合 if fc.use_Google_IME: fc.word_register_name = r"C:\Program Files (x86)\Google\Google Japanese Input\GoogleIMEJaTool.exe" fc.word_register_param = "--mode=word_register_dialog" #--------------------------------------------------------------------------------------------------- # 数引数の指定に Ctrl+数字キーを使うかを指定する(True: 使う、False: 使わない) # (False に指定しても、C-u 数字キーで数引数を指定することができます) fc.use_ctrl_digit_key_for_digit_argument = False # F1 から F12 を Alt+数字キー列として使うかを指定する(True: 使う、False: 使わない) fc.use_alt_digit_key_for_f1_to_f12 = False # F13 から F24 を Alt-Shift+数字キー列として使うかを指定する(True: 使う、False: 使わない) fc.use_alt_shift_digit_key_for_f13_to_f24 = False # アクティブウィンドウを切り替えるキーの組み合わせ(前、後 の順)を指定する(複数指定可) # (内部で A-Tab による切り替えを行っているため、設定するキーは Altキーとの組み合わせとしてください) # (切り替え画面が起動した後は、A-b、A-f、A-p、A-n でウィンドウを切り替えられるように設定している他、 # Alt + 矢印キーでもウィンドウを切り替えることができます。また、A-g もしくは A-Esc で切り替え画面の # 終了(キャンセル)となり、Altキーを離すか A-Enter で切り替えるウィンドウの確定となります。) # (デフォルトキーは、["A-S-Tab", "A-Tab"]) fc.window_switching_key = [] # fc.window_switching_key += [["A-p", "A-n"]] # コマンドのリピート回数の最大値を指定する fc.repeat_max = 1024 # Microsoft Excel のセル内で改行を選択可能かを指定する(True: 選択可、False: 選択不可) # (kill_line 関数の挙動を変えるための変数です。Microsoft Excel 2019 以降では True にして # ください。) fc.is_newline_selectable_in_Excel = False # 個人設定ファイルのセクション [section-base-1] を読み込んで実行する exec(read_config_personal("[section-base-1]"), dict(globals(), **locals())) ########################################################################### ## 基本機能の設定 ########################################################################### fakeymacs.last_window = None fakeymacs.ime_cancel = False def is_emacs_target(window): if window != fakeymacs.last_window: if window.getProcessName() in fc.not_clipboard_target: # クリップボードの監視用のフックを無効にする keymap.clipboard_history.enableHook(False) else: # クリップボードの監視用のフックを有効にする keymap.clipboard_history.enableHook(True) if window.getProcessName() in fc.emacs_exclusion_key.keys(): fakeymacs.exclution_key = list(map(addSideOfModifierKey, fc.emacs_exclusion_key[window.getProcessName()])) else: fakeymacs.exclution_key = [] fakeymacs.last_window = window fakeymacs.ime_cancel = False if is_task_switching_window(window): return False if window.getClassName() in fc.emacs_target_class: fakeymacs.keybind = "emacs" return True if window.getProcessName() in fc.not_emacs_target: fakeymacs.keybind = "not_emacs" return False fakeymacs.keybind = "emacs" return True def is_ime_target(window): if window.getClassName() in fc.emacs_target_class: return False if window.getProcessName() in fc.ime_target: return True return False if fc.use_emacs_ime_mode: keymap_emacs = keymap.defineWindowKeymap(check_func=lambda wnd: is_emacs_target(wnd) and not is_emacs_ime_mode(wnd)) keymap_ime = keymap.defineWindowKeymap(check_func=lambda wnd: is_ime_target(wnd) and not is_emacs_ime_mode(wnd)) else: keymap_emacs = keymap.defineWindowKeymap(check_func=is_emacs_target) keymap_ime = keymap.defineWindowKeymap(check_func=is_ime_target) # mark がセットされると True になる fakeymacs.is_marked = False # リージョンを拡張する際に、順方向に拡張すると True、逆方向に拡張すると False になる fakeymacs.forward_direction = None # 検索が開始されると True になる fakeymacs.is_searching = False # キーボードマクロの play 中 は True になる fakeymacs.is_playing_kmacro = False # universal-argument コマンドが実行されると True になる fakeymacs.is_universal_argument = False # digit-argument コマンドが実行されると True になる fakeymacs.is_digit_argument = False # コマンドのリピート回数を設定する fakeymacs.repeat_counter = 1 # undo のモードの時 True になる(redo のモードの時 False になる) fakeymacs.is_undo_mode = True # Ctl-xプレフィックスキーを構成するキーの仮想キーコードを設定する if fc.ctl_x_prefix_key: keyCondition = keyhac_keymap.KeyCondition.fromString(fc.ctl_x_prefix_key) if keyCondition.mod == MODKEY_CTRL: if fc.side_of_ctrl_key == "L": ctl_x_prefix_vkey = [VK_LCONTROL, keyCondition.vk] else: ctl_x_prefix_vkey = [VK_RCONTROL, keyCondition.vk] elif keyCondition.mod == MODKEY_ALT: if fc.side_of_alt_key == "L": ctl_x_prefix_vkey = [VK_LMENU, keyCondition.vk] else: ctl_x_prefix_vkey = [VK_RMENU, keyCondition.vk] else: print("Ctl-xプレフィックスキーのモディファイアキーは、Ctrl または Alt のいずれかから指定してください") ################################################## ## IME の操作 ################################################## def enable_input_method(): setImeStatus(1) def disable_input_method(): setImeStatus(0) def toggle_input_method(): setImeStatus(keymap.getWindow().getImeStatus() ^ 1) def setImeStatus(ime_status): if keymap.getWindow().getImeStatus() != ime_status: # IME を 切り替える # ( keymap.getWindow().setImeStatus(ime_status) を使わないのは、キーボードマクロの再生時に影響がでるため) self_insert_command("A-(25)")() if fakeymacs.is_playing_kmacro: delay(0.2) if not fakeymacs.is_playing_kmacro: if ime_status: message = "[あ]" else: message = "[A]" # IME の状態をバルーンヘルプで表示する keymap.popBalloon("ime_status", message, 500) def reconversion(reconv_key, cancel_key): def _func(): if fakeymacs.ime_cancel: self_insert_command(cancel_key)() if fc.use_emacs_ime_mode: enable_emacs_ime_mode() else: if fc.ime_reconv_region: if fakeymacs.forward_direction is not None: self_insert_command(reconv_key)() if fc.use_emacs_ime_mode: enable_emacs_ime_mode() else: self_insert_command(reconv_key)() if fc.use_emacs_ime_mode: enable_emacs_ime_mode() return _func ################################################## ## ファイル操作 ################################################## def find_file(): self_insert_command("C-o")() def save_buffer(): self_insert_command("C-s")() def write_file(): self_insert_command("A-f", "A-a")() def dired(): keymap.ShellExecuteCommand(None, r"explorer.exe", "", "")() ################################################## ## カーソル移動 ################################################## def backward_char(): self_insert_command("Left")() def forward_char(): self_insert_command("Right")() def backward_word(): self_insert_command("C-Left")() def forward_word(): self_insert_command("C-Right")() def previous_line(): self_insert_command("Up")() def next_line(): self_insert_command("Down")() def move_beginning_of_line(): self_insert_command("Home")() def move_end_of_line(): self_insert_command("End")() if (checkWindow("WINWORD.EXE", "_WwG") or # Microsoft Word checkWindow("POWERPNT.EXE", "mdiClass") or # Microsoft PowerPoint (checkWindow("EXCEL.EXE", "EXCEL*") and # Microsoft Excel fc.is_newline_selectable_in_Excel)): if fakeymacs.is_marked: self_insert_command("Left")() def beginning_of_buffer(): self_insert_command("C-Home")() def end_of_buffer(): self_insert_command("C-End")() def scroll_up(): self_insert_command("PageUp")() def scroll_down(): self_insert_command("PageDown")() def recenter(): if (checkWindow("sakura.exe", "EditorClient") or # Sakura Editor checkWindow("sakura.exe", "SakuraView*")): # Sakura Editor self_insert_command("C-h")() ################################################## ## カット / コピー / 削除 / アンドゥ ################################################## def delete_backward_char(): self_insert_command("Back")() def delete_char(): self_insert_command("Delete")() def backward_kill_word(repeat=1): resetRegion() fakeymacs.is_marked = True def move_beginning_of_region(): for i in range(repeat): backward_word() mark(move_beginning_of_region, False)() delay() kill_region() def kill_word(repeat=1): resetRegion() fakeymacs.is_marked = True def move_end_of_region(): for i in range(repeat): forward_word() mark(move_end_of_region, True)() delay() kill_region() def kill_line(repeat=1): resetRegion() fakeymacs.is_marked = True if repeat == 1: mark(move_end_of_line, True)() delay() if (checkWindow("cmd.exe", "ConsoleWindowClass") or # Cmd checkWindow("powershell.exe", "ConsoleWindowClass")): # PowerShell kill_region() elif checkWindow(None, "HM32CLIENT"): # Hidemaru Software kill_region() delay() if getClipboardText() == "": self_insert_command("Delete")() else: # 改行を消せるようにするため Cut にはしていない copyRegion() self_insert_command("Delete")() else: def move_end_of_region(): if checkWindow("WINWORD.EXE", "_WwG"): # Microsoft Word for i in range(repeat): next_line() move_beginning_of_line() else: for i in range(repeat - 1): next_line() move_end_of_line() forward_char() mark(move_end_of_region, True)() delay() kill_region() def kill_region(): # コマンドプロンプトには Cut に対応するショートカットがない。その対策。 if checkWindow("cmd.exe", "ConsoleWindowClass"): # Cmd copyRegion() if fakeymacs.forward_direction is not None: if fakeymacs.forward_direction: key = "Delete" else: key = "Back" delay() for i in range(len(getClipboardText())): self_insert_command(key)() else: cutRegion() def kill_ring_save(): copyRegion() resetRegion() def yank(): self_insert_command("C-v")() def undo(): # redo(C-y)の機能を持っていないアプリケーションソフトは常に undo とする if checkWindow("notepad.exe", "Edit"): # NotePad self_insert_command("C-z")() else: if fakeymacs.is_undo_mode: self_insert_command("C-z")() else: self_insert_command("C-y")() def set_mark_command(): if fakeymacs.is_marked or fakeymacs.forward_direction is not None: resetRegion() fakeymacs.is_marked = False fakeymacs.forward_direction = None else: fakeymacs.is_marked = True def mark_whole_buffer(): if checkWindow("cmd.exe", "ConsoleWindowClass"): # Cmd # "Home", "C-a" では上手く動かない場合がある self_insert_command("Home", "S-End")() fakeymacs.forward_direction = True # 逆の設定にする elif checkWindow("powershell.exe", "ConsoleWindowClass"): # PowerShell self_insert_command("End", "S-Home")() fakeymacs.forward_direction = False elif (checkWindow("EXCEL.EXE", "EXCEL*") or # Microsoft Excel checkWindow(None, "Edit")): # Edit クラス self_insert_command("C-End", "C-S-Home")() fakeymacs.forward_direction = False else: self_insert_command("C-Home", "C-a")() fakeymacs.forward_direction = False fakeymacs.is_marked = True def mark_page(): mark_whole_buffer() ################################################## ## バッファ / ウィンドウ操作 ################################################## def kill_buffer(): self_insert_command("C-F4")() def switch_to_buffer(): self_insert_command("C-Tab")() ################################################## ## 文字列検索 / 置換 ################################################## def isearch(direction): if checkWindow("powershell.exe", "ConsoleWindowClass"): # PowerShell self_insert_command({"backward":"C-r", "forward":"C-s"}[direction])() else: if fakeymacs.is_searching: if checkWindow("EXCEL.EXE", None): # Microsoft Excel if checkWindow(None, "EDTBX"): # 検索ウィンドウ self_insert_command({"backward":"A-S-f", "forward":"A-f"}[direction])() else: self_insert_command("C-f")() else: self_insert_command({"backward":"S-F3", "forward":"F3"}[direction])() else: self_insert_command("C-f")() fakeymacs.is_searching = True def isearch_backward(): isearch("backward") def isearch_forward(): isearch("forward") def query_replace(): if (checkWindow("sakura.exe", "EditorClient") or # Sakura Editor checkWindow("sakura.exe", "SakuraView*") or # Sakura Editor checkWindow(None, "HM32CLIENT")): # Hidemaru Software self_insert_command("C-r")() else: self_insert_command("C-h")() ################################################## ## キーボードマクロ ################################################## def kmacro_start_macro(): disable_input_method() keymap.command_RecordStart() def kmacro_end_macro(): keymap.command_RecordStop() # キーボードマクロの終了キー「Ctl-xプレフィックスキー + ")"」の Ctl-xプレフィックスキーがマクロに # 記録されてしまうのを対策する(キーボードマクロの終了キーの前提を「Ctl-xプレフィックスキー + ")"」 # としていることについては、とりあえず了承ください。) if fc.ctl_x_prefix_key and len(keymap.record_seq) >= 4: if (((keymap.record_seq[len(keymap.record_seq) - 1] == (ctl_x_prefix_vkey[0], True) and keymap.record_seq[len(keymap.record_seq) - 2] == (ctl_x_prefix_vkey[1], True)) or (keymap.record_seq[len(keymap.record_seq) - 1] == (ctl_x_prefix_vkey[1], True) and keymap.record_seq[len(keymap.record_seq) - 2] == (ctl_x_prefix_vkey[0], True))) and keymap.record_seq[len(keymap.record_seq) - 3] == (ctl_x_prefix_vkey[1], False)): keymap.record_seq.pop() keymap.record_seq.pop() keymap.record_seq.pop() if keymap.record_seq[len(keymap.record_seq) - 1] == (ctl_x_prefix_vkey[0], False): for i in range(len(keymap.record_seq) - 1, -1, -1): if keymap.record_seq[i] == (ctl_x_prefix_vkey[0], False): keymap.record_seq.pop() else: break else: # コントロール系の入力が連続して行われる場合があるための対処 keymap.record_seq.append((ctl_x_prefix_vkey[0], True)) def kmacro_end_and_call_macro(): def callKmacro(): # キーボードマクロの最初が IME ON の場合、この delay が必要 delay(0.2) fakeymacs.is_playing_kmacro = True disable_input_method() keymap.command_RecordPlay() fakeymacs.is_playing_kmacro = False keymap.delayedCall(callKmacro, 0) ################################################## ## その他 ################################################## def space(): self_insert_command("Space")() if fc.use_emacs_ime_mode: if fc.ime_reconv_space: if keymap.getWindow().getImeStatus(): if fakeymacs.forward_direction is not None: enable_emacs_ime_mode() def newline(): self_insert_command("Enter")() if not fc.use_emacs_ime_mode: if keymap.getWindow().getImeStatus(): fakeymacs.ime_cancel = True def newline_and_indent(): self_insert_command("Enter", "Tab")() def open_line(): self_insert_command("Enter", "Up", "End")() def indent_for_tab_command(): self_insert_command("Tab")() def keyboard_quit(): resetRegion() # Esc を発行して問題ないアプリケーションソフトには Esc を発行する if not (checkWindow("cmd.exe", "ConsoleWindowClass") or # Cmd checkWindow("powershell.exe", "ConsoleWindowClass") or # PowerShell checkWindow("EXCEL.EXE", "EXCEL*") or # Microsoft Excel checkWindow("Evernote.exe", "WebViewHost")): # Evernote self_insert_command("Esc")() keymap.command_RecordStop() if fakeymacs.is_undo_mode: fakeymacs.is_undo_mode = False else: fakeymacs.is_undo_mode = True def kill_emacs(): # Excel のファイルを開いた直後一回目、kill_emacs が正常に動作しない。その対策。 self_insert_command("D-Alt", "F4")() delay(0.1) self_insert_command("U-Alt")() def universal_argument(): if fakeymacs.is_universal_argument: if fakeymacs.is_digit_argument: fakeymacs.is_universal_argument = False else: fakeymacs.repeat_counter *= 4 else: fakeymacs.is_universal_argument = True fakeymacs.repeat_counter *= 4 def digit_argument(number): if fakeymacs.is_digit_argument: fakeymacs.repeat_counter = fakeymacs.repeat_counter * 10 + number else: fakeymacs.repeat_counter = number fakeymacs.is_digit_argument = True ################################################## ## 共通関数 ################################################## def delay(sec=0.02): time.sleep(sec) def copyRegion(): self_insert_command("C-c")() pushToClipboardList() def cutRegion(): self_insert_command("C-x")() pushToClipboardList() def pushToClipboardList(): # clipboard 監視の対象外とするアプリケーションソフトで copy / cut した場合でも # クリップボードの内容をクリップボードリストに登録する if keymap.getWindow().getProcessName() in fc.not_clipboard_target: delay(0.1) clipboard_text = getClipboardText() if clipboard_text: keymap.clipboard_history._push(clipboard_text) def checkWindow(processName, className, window=None): if window is None: window = keymap.getWindow() return ((processName is None or fnmatch.fnmatch(window.getProcessName(), processName)) and (className is None or fnmatch.fnmatch(window.getClassName(), className))) def vkeys(): vkeys = list(keyCondition.vk_str_table.keys()) for vkey in [VK_MENU, VK_LMENU, VK_RMENU, VK_CONTROL, VK_LCONTROL, VK_RCONTROL, VK_SHIFT, VK_LSHIFT, VK_RSHIFT, VK_LWIN, VK_RWIN]: vkeys.remove(vkey) return vkeys def addSideOfModifierKey(key): key = re.sub(r'(^|-)(C-)', r'\1' + fc.side_of_ctrl_key + r'\2', key) key = re.sub(r'(^|-)(A-)', r'\1' + fc.side_of_alt_key + r'\2', key) key = re.sub(r'(^|-)(W-)', r'\1' + fc.side_of_win_key + r'\2', key) return key def kbd(keys): if keys: keys_lists = [keys.split()] if keys_lists[0][0] == "Ctl-x": if fc.ctl_x_prefix_key: keys_lists[0][0] = fc.ctl_x_prefix_key else: keys_lists = [] elif keys_lists[0][0].startswith("M-"): key = re.sub("^M-", "", keys_lists[0][0]) keys_lists[0][0] = "A-" + key keys_lists.append(["C-OpenBracket", key]) if fc.use_esc_as_meta: keys_lists.append(["Esc", key]) for keys_list in keys_lists: keys_list[0] = addSideOfModifierKey(keys_list[0]) else: keys_lists = [] return keys_lists def define_key(window_keymap, keys, command, skip_check=True, _locals=locals()): if skip_check: # 設定をスキップするキーの処理を行う for keymap_name in fc.skip_settings_key.keys(): if (keymap_name in _locals.keys() and window_keymap == _locals[keymap_name]): if keys in fc.skip_settings_key[keymap_name]: print("skip settings key : [" + keymap_name + "] " + keys) return def keyCommand(key): if ("keymap_emacs" in _locals.keys() and window_keymap == _locals["keymap_emacs"] and type(command) is types.FunctionType): def _command(): if key in fakeymacs.exclution_key: keymap.InputKeyCommand(key)() else: command() return _command else: return command for keys_list in kbd(keys): if len(keys_list) == 1: window_keymap[keys_list[0]] = keyCommand(keys_list[0]) # Alt キーを単押しした際に、カーソルがメニューへ移動しないようにする # https://www.haijin-boys.com/discussions/4583 if re.match(keys_list[0], r"O-LAlt$", re.IGNORECASE): window_keymap["D-LAlt"] = "D-LAlt", "(7)" if re.match(keys_list[0], r"O-RAlt$", re.IGNORECASE): window_keymap["D-RAlt"] = "D-RAlt", "(7)" else: window_keymap[keys_list[0]][keys_list[1]] = keyCommand(None) def define_key2(window_keymap, keys, command, skip_check=False, _locals=locals()): define_key(window_keymap, keys, command, skip_check, _locals) def self_insert_command(*keys): func = keymap.InputKeyCommand(*list(map(addSideOfModifierKey, keys))) def _func(): func() fakeymacs.ime_cancel = False return _func def self_insert_command2(*keys): func = self_insert_command(*keys) def _func(): func() if fc.use_emacs_ime_mode: if keymap.getWindow().getImeStatus(): enable_emacs_ime_mode() return _func def digit(number): def _func(): if fakeymacs.is_universal_argument: digit_argument(number) else: reset_undo(reset_counter(reset_mark(repeat(self_insert_command2(str(number))))))() return _func def digit2(number): def _func(): fakeymacs.is_universal_argument = True digit_argument(number) return _func def resetRegion(): if fakeymacs.forward_direction is not None: if checkWindow(None, "Edit"): # Edit クラス # 選択されているリージョンのハイライトを解除するためにカーソルキーを発行する if fakeymacs.forward_direction: self_insert_command("Right")() else: self_insert_command("Left")() elif checkWindow("cmd.exe", "ConsoleWindowClass"): # Cmd # 選択されているリージョンのハイライトを解除するためにカーソルを移動する if fakeymacs.forward_direction: self_insert_command("Right", "Left")() else: self_insert_command("Left", "Right")() elif (checkWindow("powershell.exe", "ConsoleWindowClass") or # PowerShell checkWindow("EXCEL.EXE", None)): # Microsoft Excel # 選択されているリージョンのハイライトを解除するためにカーソルを移動する if fakeymacs.forward_direction: self_insert_command("Left", "Right")() else: self_insert_command("Right", "Left")() else: # 選択されているリージョンのハイライトを解除するためにカーソルキーを発行する if fakeymacs.forward_direction: self_insert_command("Right")() else: self_insert_command("Left")() def mark(func, forward_direction): def _func(): if fakeymacs.is_marked: # D-Shift だと、M-< や M-> 押下時に、D-Shift が解除されてしまう。その対策。 self_insert_command("D-LShift", "D-RShift")() delay() func() self_insert_command("U-LShift", "U-RShift")() # fakeymacs.forward_direction が未設定の場合、設定する if fakeymacs.forward_direction is None: fakeymacs.forward_direction = forward_direction else: fakeymacs.forward_direction = None func() return _func def mark2(func, forward_direction): def _func(): if fakeymacs.is_marked: resetRegion() fakeymacs.forward_direction = None fakeymacs.is_marked = True mark(func, forward_direction)() fakeymacs.is_marked = False return _func def reset_mark(func): def _func(): func() fakeymacs.is_marked = False fakeymacs.forward_direction = None return _func def reset_counter(func): def _func(): func() fakeymacs.is_universal_argument = False fakeymacs.is_digit_argument = False fakeymacs.repeat_counter = 1 return _func def reset_undo(func): def _func(): func() fakeymacs.is_undo_mode = True return _func def reset_search(func): def _func(): func() fakeymacs.is_searching = False return _func def repeat(func): def _func(): if fakeymacs.repeat_counter > fc.repeat_max: print("コマンドのリピート回数の最大値を超えています") repeat_counter = fc.repeat_max else: repeat_counter = fakeymacs.repeat_counter # キーボードマクロの繰り返し実行を可能とするために初期化する fakeymacs.repeat_counter = 1 for i in range(repeat_counter): func() return _func def repeat2(func): def _func(): if fakeymacs.is_marked: fakeymacs.repeat_counter = 1 repeat(func)() return _func def repeat3(func): def _func(): if fakeymacs.repeat_counter > fc.repeat_max: print("コマンドのリピート回数の最大値を超えています") repeat_counter = fc.repeat_max else: repeat_counter = fakeymacs.repeat_counter func(repeat_counter) return _func ################################################## ## キーバインド ################################################## # キーバインドの定義に利用している表記の意味は次のとおりです。 # ・S- : Shiftキー # ・C- : Ctrlキー # ・A- : Altキー # ・M- : Altキー と Esc、C-[ のプレフィックスキーを利用する3パターンを定義(emacs の Meta と同様) # ・W- : Winキー # ・Ctl-x : ctl_x_prefix_key 変数で定義されているプレフィックスキーに置換え # ・(999) : 仮想キーコード指定 # https://github.com/crftwr/keyhac/blob/master/keyhac_keymap.py # https://github.com/crftwr/pyauto/blob/master/pyauto_const.py # http://www.yoshidastyle.net/2007/10/windowswin32api.html # http://www.azaelia.net/factory/vk.html # http://www3.airnet.ne.jp/saka/hardware/keyboard/109scode.html ## マルチストロークキーの設定 define_key(keymap_emacs, "Ctl-x", keymap.defineMultiStrokeKeymap(fc.ctl_x_prefix_key)) define_key(keymap_emacs, "C-q", keymap.defineMultiStrokeKeymap("C-q")) define_key(keymap_emacs, "C-OpenBracket", keymap.defineMultiStrokeKeymap("C-OpenBracket")) if fc.use_esc_as_meta: define_key(keymap_emacs, "Esc", keymap.defineMultiStrokeKeymap("Esc")) ## 数字キーの設定 for key in range(10): s_key = str(key) define_key(keymap_emacs, s_key, digit(key)) if fc.use_ctrl_digit_key_for_digit_argument: define_key(keymap_emacs, "C-" + s_key, digit2(key)) define_key(keymap_emacs, "M-" + s_key, digit2(key)) define_key(keymap_emacs, "S-" + s_key, reset_undo(reset_counter(reset_mark(repeat(self_insert_command2("S-" + s_key)))))) define_key(keymap_ime, s_key, self_insert_command2( s_key)) define_key(keymap_ime, "S-" + s_key, self_insert_command2("S-" + s_key)) ## アルファベットキーの設定 for vkey in range(VK_A, VK_Z + 1): s_vkey = "({})".format(vkey) define_key(keymap_emacs, s_vkey, reset_undo(reset_counter(reset_mark(repeat(self_insert_command2( s_vkey)))))) define_key(keymap_emacs, "S-" + s_vkey, reset_undo(reset_counter(reset_mark(repeat(self_insert_command2("S-" + s_vkey)))))) define_key(keymap_ime, s_vkey, self_insert_command2( s_vkey)) define_key(keymap_ime, "S-" + s_vkey, self_insert_command2("S-" + s_vkey)) ## 特殊文字キーの設定 define_key(keymap_emacs, "Space" , reset_undo(reset_counter(reset_mark(repeat(space))))) define_key(keymap_emacs, "S-Space", reset_undo(reset_counter(reset_mark(repeat(self_insert_command("S-Space")))))) for vkey in [VK_OEM_MINUS, VK_OEM_PLUS, VK_OEM_COMMA, VK_OEM_PERIOD, VK_OEM_1, VK_OEM_2, VK_OEM_3, VK_OEM_4, VK_OEM_5, VK_OEM_6, VK_OEM_7, VK_OEM_102]: s_vkey = "({})".format(vkey) define_key(keymap_emacs, s_vkey, reset_undo(reset_counter(reset_mark(repeat(self_insert_command2( s_vkey)))))) define_key(keymap_emacs, "S-" + s_vkey, reset_undo(reset_counter(reset_mark(repeat(self_insert_command2("S-" + s_vkey)))))) define_key(keymap_ime, s_vkey, self_insert_command2( s_vkey)) define_key(keymap_ime, "S-" + s_vkey, self_insert_command2("S-" + s_vkey)) ## 10key の特殊文字キーの設定 for vkey in [VK_MULTIPLY, VK_ADD, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE]: s_vkey = "({})".format(vkey) define_key(keymap_emacs, s_vkey, reset_undo(reset_counter(reset_mark(repeat(self_insert_command2(s_vkey)))))) define_key(keymap_ime, s_vkey, self_insert_command2(s_vkey)) ## quoted-insertキーの設定 for vkey in vkeys(): s_vkey = "({})".format(vkey) define_key(keymap_emacs, "C-q " + s_vkey, reset_search(reset_undo(reset_counter(reset_mark(self_insert_command( s_vkey)))))) define_key(keymap_emacs, "C-q S-" + s_vkey, reset_search(reset_undo(reset_counter(reset_mark(self_insert_command("S-" + s_vkey)))))) define_key(keymap_emacs, "C-q C-" + s_vkey, reset_search(reset_undo(reset_counter(reset_mark(self_insert_command("C-" + s_vkey)))))) define_key(keymap_emacs, "C-q C-S-" + s_vkey, reset_search(reset_undo(reset_counter(reset_mark(self_insert_command("C-S-" + s_vkey)))))) define_key(keymap_emacs, "C-q A-" + s_vkey, reset_search(reset_undo(reset_counter(reset_mark(self_insert_command("A-" + s_vkey)))))) define_key(keymap_emacs, "C-q A-S-" + s_vkey, reset_search(reset_undo(reset_counter(reset_mark(self_insert_command("A-S-" + s_vkey)))))) define_key(keymap_emacs, "C-q W-" + s_vkey, reset_search(reset_undo(reset_counter(reset_mark(self_insert_command("W-" + s_vkey)))))) define_key(keymap_emacs, "C-q W-S-" + s_vkey, reset_search(reset_undo(reset_counter(reset_mark(self_insert_command("W-S-" + s_vkey)))))) ## Escキーの設定 define_key(keymap_emacs, "C-OpenBracket C-OpenBracket", reset_undo(reset_counter(self_insert_command("Esc")))) if fc.use_esc_as_meta: define_key(keymap_emacs, "Esc Esc", reset_undo(reset_counter(self_insert_command("Esc")))) else: define_key(keymap_emacs, "Esc", reset_undo(reset_counter(self_insert_command("Esc")))) ## universal-argumentキーの設定 define_key(keymap_emacs, "C-u", universal_argument) ## 「IME の切り替え」のキー設定 define_key(keymap_emacs, "(243)", toggle_input_method) define_key(keymap_emacs, "(244)", toggle_input_method) define_key(keymap_emacs, "A-(25)", toggle_input_method) define_key(keymap_ime, "(243)", toggle_input_method) define_key(keymap_ime, "(244)", toggle_input_method) define_key(keymap_ime, "A-(25)", toggle_input_method) ## 「ファイル操作」のキー設定 define_key(keymap_emacs, "Ctl-x C-f", reset_search(reset_undo(reset_counter(reset_mark(find_file))))) define_key(keymap_emacs, "Ctl-x C-s", reset_search(reset_undo(reset_counter(reset_mark(save_buffer))))) define_key(keymap_emacs, "Ctl-x C-w", reset_search(reset_undo(reset_counter(reset_mark(write_file))))) define_key(keymap_emacs, "Ctl-x d", reset_search(reset_undo(reset_counter(reset_mark(dired))))) ## 「カーソル移動」のキー設定 define_key(keymap_emacs, "C-b", reset_search(reset_undo(reset_counter(mark(repeat(backward_char), False))))) define_key(keymap_emacs, "C-f", reset_search(reset_undo(reset_counter(mark(repeat(forward_char), True))))) define_key(keymap_emacs, "M-b", reset_search(reset_undo(reset_counter(mark(repeat(backward_word), False))))) define_key(keymap_emacs, "M-f", reset_search(reset_undo(reset_counter(mark(repeat(forward_word), True))))) define_key(keymap_emacs, "C-p", reset_search(reset_undo(reset_counter(mark(repeat(previous_line), False))))) define_key(keymap_emacs, "C-n", reset_search(reset_undo(reset_counter(mark(repeat(next_line), True))))) define_key(keymap_emacs, "C-a", reset_search(reset_undo(reset_counter(mark(move_beginning_of_line, False))))) define_key(keymap_emacs, "C-e", reset_search(reset_undo(reset_counter(mark(move_end_of_line, True))))) define_key(keymap_emacs, "M-S-Comma", reset_search(reset_undo(reset_counter(mark(beginning_of_buffer, False))))) define_key(keymap_emacs, "M-S-Period", reset_search(reset_undo(reset_counter(mark(end_of_buffer, True))))) define_key(keymap_emacs, "C-l", reset_search(reset_undo(reset_counter(recenter)))) define_key(keymap_emacs, "C-S-b", reset_search(reset_undo(reset_counter(mark2(repeat(backward_char), False))))) define_key(keymap_emacs, "C-S-f", reset_search(reset_undo(reset_counter(mark2(repeat(forward_char), True))))) define_key(keymap_emacs, "M-S-b", reset_search(reset_undo(reset_counter(mark2(repeat(backward_word), False))))) define_key(keymap_emacs, "M-S-f", reset_search(reset_undo(reset_counter(mark2(repeat(forward_word), True))))) define_key(keymap_emacs, "C-S-p", reset_search(reset_undo(reset_counter(mark2(repeat(previous_line), False))))) define_key(keymap_emacs, "C-S-n", reset_search(reset_undo(reset_counter(mark2(repeat(next_line), True))))) define_key(keymap_emacs, "C-S-a", reset_search(reset_undo(reset_counter(mark2(move_beginning_of_line, False))))) define_key(keymap_emacs, "C-S-e", reset_search(reset_undo(reset_counter(mark2(move_end_of_line, True))))) define_key(keymap_emacs, "Left", reset_search(reset_undo(reset_counter(mark(repeat(backward_char), False))))) define_key(keymap_emacs, "Right", reset_search(reset_undo(reset_counter(mark(repeat(forward_char), True))))) define_key(keymap_emacs, "C-Left", reset_search(reset_undo(reset_counter(mark(repeat(backward_word), False))))) define_key(keymap_emacs, "C-Right", reset_search(reset_undo(reset_counter(mark(repeat(forward_word), True))))) define_key(keymap_emacs, "Up", reset_search(reset_undo(reset_counter(mark(repeat(previous_line), False))))) define_key(keymap_emacs, "Down", reset_search(reset_undo(reset_counter(mark(repeat(next_line), True))))) define_key(keymap_emacs, "Home", reset_search(reset_undo(reset_counter(mark(move_beginning_of_line, False))))) define_key(keymap_emacs, "End", reset_search(reset_undo(reset_counter(mark(move_end_of_line, True))))) define_key(keymap_emacs, "C-Home", reset_search(reset_undo(reset_counter(mark(beginning_of_buffer, False))))) define_key(keymap_emacs, "C-End", reset_search(reset_undo(reset_counter(mark(end_of_buffer, True))))) define_key(keymap_emacs, "PageUP", reset_search(reset_undo(reset_counter(mark(scroll_up, False))))) define_key(keymap_emacs, "PageDown", reset_search(reset_undo(reset_counter(mark(scroll_down, True))))) define_key(keymap_emacs, "S-Left", reset_search(reset_undo(reset_counter(mark2(repeat(backward_char), False))))) define_key(keymap_emacs, "S-Right", reset_search(reset_undo(reset_counter(mark2(repeat(forward_char), True))))) define_key(keymap_emacs, "C-S-Left", reset_search(reset_undo(reset_counter(mark2(repeat(backward_word), False))))) define_key(keymap_emacs, "C-S-Right", reset_search(reset_undo(reset_counter(mark2(repeat(forward_word), True))))) define_key(keymap_emacs, "S-Up", reset_search(reset_undo(reset_counter(mark2(repeat(previous_line), False))))) define_key(keymap_emacs, "S-Down", reset_search(reset_undo(reset_counter(mark2(repeat(next_line), True))))) define_key(keymap_emacs, "S-Home", reset_search(reset_undo(reset_counter(mark2(move_beginning_of_line, False))))) define_key(keymap_emacs, "S-End", reset_search(reset_undo(reset_counter(mark2(move_end_of_line, True))))) define_key(keymap_emacs, "C-S-Home", reset_search(reset_undo(reset_counter(mark2(beginning_of_buffer, False))))) define_key(keymap_emacs, "C-S-End", reset_search(reset_undo(reset_counter(mark2(end_of_buffer, True))))) define_key(keymap_emacs, "S-PageUP", reset_search(reset_undo(reset_counter(mark2(scroll_up, False))))) define_key(keymap_emacs, "S-PageDown", reset_search(reset_undo(reset_counter(mark2(scroll_down, True))))) ## 「カット / コピー / 削除 / アンドゥ」のキー設定 define_key(keymap_emacs, "C-h", reset_search(reset_undo(reset_counter(reset_mark(repeat2(delete_backward_char)))))) define_key(keymap_emacs, "C-d", reset_search(reset_undo(reset_counter(reset_mark(repeat2(delete_char)))))) define_key(keymap_emacs, "M-Delete", reset_search(reset_undo(reset_counter(reset_mark(repeat3(backward_kill_word)))))) define_key(keymap_emacs, "M-d", reset_search(reset_undo(reset_counter(reset_mark(repeat3(kill_word)))))) define_key(keymap_emacs, "C-k", reset_search(reset_undo(reset_counter(reset_mark(repeat3(kill_line)))))) define_key(keymap_emacs, "C-w", reset_search(reset_undo(reset_counter(reset_mark(kill_region))))) define_key(keymap_emacs, "M-w", reset_search(reset_undo(reset_counter(reset_mark(kill_ring_save))))) define_key(keymap_emacs, "C-y", reset_search(reset_undo(reset_counter(reset_mark(repeat(yank)))))) define_key(keymap_emacs, "C-Slash", reset_search(reset_counter(reset_mark(undo)))) define_key(keymap_emacs, "Ctl-x u", reset_search(reset_counter(reset_mark(undo)))) define_key(keymap_emacs, "Back", reset_search(reset_undo(reset_counter(reset_mark(repeat2(delete_backward_char)))))) define_key(keymap_emacs, "Delete", reset_search(reset_undo(reset_counter(reset_mark(repeat2(delete_char)))))) define_key(keymap_emacs, "C-Back", reset_search(reset_undo(reset_counter(reset_mark(repeat3(backward_kill_word)))))) define_key(keymap_emacs, "C-Delete", reset_search(reset_undo(reset_counter(reset_mark(repeat3(kill_word)))))) define_key(keymap_emacs, "C-c", reset_search(reset_undo(reset_counter(reset_mark(kill_ring_save))))) define_key(keymap_emacs, "C-v", reset_search(reset_undo(reset_counter(reset_mark(repeat(yank)))))) # scroll_key の設定で上書きされない場合 define_key(keymap_emacs, "C-z", reset_search(reset_counter(reset_mark(undo)))) # C-Underscore を機能させるための設定 if is_japanese_keyboard: define_key(keymap_emacs, "C-S-BackSlash", reset_search(reset_undo(reset_counter(reset_mark(undo))))) else: define_key(keymap_emacs, "C-S-Minus", reset_search(reset_undo(reset_counter(reset_mark(undo))))) if is_japanese_keyboard: # C-Atmark だとうまく動かない方が居るようなので C-(192) としている # (http://bhby39.blogspot.jp/2015/02/windows-emacs.html) define_key(keymap_emacs, "C-(192)", reset_search(reset_undo(reset_counter(set_mark_command)))) else: # C-S-2 は有効とならないが、一応設定は行っておく(C-S-3 などは有効となる。なぜだろう?) define_key(keymap_emacs, "C-S-2", reset_search(reset_undo(reset_counter(set_mark_command)))) define_key(keymap_emacs, "C-Space", reset_search(reset_undo(reset_counter(set_mark_command)))) define_key(keymap_emacs, "Ctl-x h", reset_search(reset_undo(reset_counter(mark_whole_buffer)))) define_key(keymap_emacs, "Ctl-x C-p", reset_search(reset_undo(reset_counter(mark_page)))) ## 「バッファ / ウィンドウ操作」のキー設定 define_key(keymap_emacs, "Ctl-x k", reset_search(reset_undo(reset_counter(reset_mark(kill_buffer))))) define_key(keymap_emacs, "Ctl-x b", reset_search(reset_undo(reset_counter(reset_mark(switch_to_buffer))))) define_key(keymap_emacs, "M-k", reset_search(reset_undo(reset_counter(reset_mark(kill_buffer))))) ## 「文字列検索 / 置換」のキー設定 define_key(keymap_emacs, "C-r", reset_undo(reset_counter(reset_mark(isearch_backward)))) define_key(keymap_emacs, "C-s", reset_undo(reset_counter(reset_mark(isearch_forward)))) define_key(keymap_emacs, "M-S-5", reset_search(reset_undo(reset_counter(reset_mark(query_replace))))) ## 「キーボードマクロ」のキー設定 if is_japanese_keyboard: define_key(keymap_emacs, "Ctl-x S-8", kmacro_start_macro) define_key(keymap_emacs, "Ctl-x S-9", kmacro_end_macro) else: define_key(keymap_emacs, "Ctl-x S-9", kmacro_start_macro) define_key(keymap_emacs, "Ctl-x S-0", kmacro_end_macro) define_key(keymap_emacs, "Ctl-x e", reset_search(reset_undo(reset_counter(repeat(kmacro_end_and_call_macro))))) ## 「その他」のキー設定 define_key(keymap_emacs, "Enter", reset_undo(reset_counter(reset_mark(repeat(newline))))) define_key(keymap_emacs, "C-m", reset_undo(reset_counter(reset_mark(repeat(newline))))) define_key(keymap_emacs, "C-j", reset_undo(reset_counter(reset_mark(newline_and_indent)))) define_key(keymap_emacs, "C-o", reset_undo(reset_counter(reset_mark(repeat(open_line))))) define_key(keymap_emacs, "Tab", reset_undo(reset_counter(reset_mark(repeat(indent_for_tab_command))))) define_key(keymap_emacs, "C-g", reset_search(reset_counter(reset_mark(keyboard_quit)))) define_key(keymap_emacs, "Ctl-x C-c", reset_search(reset_undo(reset_counter(reset_mark(kill_emacs))))) if fc.use_ctrl_i_as_tab: define_key(keymap_emacs, "C-i", reset_undo(reset_counter(reset_mark(repeat(indent_for_tab_command))))) ## 「スクロール」のキー設定 if fc.scroll_key: define_key(keymap_emacs, fc.scroll_key[0], reset_search(reset_undo(reset_counter(mark(scroll_up, False))))) define_key(keymap_emacs, fc.scroll_key[1], reset_search(reset_undo(reset_counter(mark(scroll_down, True))))) ## 「カット」のキー設定 if fc.ctl_x_prefix_key != "C-x": define_key(keymap_emacs, "C-x", reset_search(reset_undo(reset_counter(reset_mark(kill_region))))) ## 「IME の切り替え」のキー設定 if fc.toggle_input_method_key: for key in fc.toggle_input_method_key: define_key(keymap_emacs, key, toggle_input_method) define_key(keymap_ime, key, toggle_input_method) ## 「IME の切り替え」のキー設定 if fc.set_input_method_key: for disable_key, enable_key in fc.set_input_method_key: if disable_key: define_key(keymap_emacs, disable_key, disable_input_method) define_key(keymap_ime, disable_key, disable_input_method) if enable_key: define_key(keymap_emacs, enable_key, enable_input_method) define_key(keymap_ime, enable_key, enable_input_method) ## 「再変換」、「確定取り消し」のキー設定 if fc.reconversion_key: if fc.use_Google_IME: # Google日本語入力を利用している時、ime_cancel_key に設定しているキーがキーバインドに # 定義されていると、「確定取り消し」が正常に動作しない場合がある。このため、そのキー # バインドの定義を削除する。 try: del keymap_emacs[addSideOfModifierKey(fc.ime_cancel_key)] except: pass for key in fc.reconversion_key: define_key(keymap_emacs, key, reset_undo(reset_counter(reset_mark(reconversion(fc.ime_reconv_key, fc.ime_cancel_key))))) ########################################################################### ## Emacs日本語入力モードの設定 ########################################################################### if fc.use_emacs_ime_mode: def is_emacs_ime_mode(window): if fakeymacs.ei_last_window == window: return True else: fakeymacs.ei_last_window = None return False def is_emacs_ime_mode2(window): if is_emacs_ime_mode(window): ei_popBalloon(1) return True else: ei_popBalloon(0) return False keymap_ei = keymap.defineWindowKeymap(check_func=is_emacs_ime_mode2) # Emacs日本語入力モードが開始されたときのウィンドウオブジェクトを格納する変数を初期化する fakeymacs.ei_last_window = None ################################################## ## Emacs日本語入力モード の切り替え ################################################## def enable_emacs_ime_mode(): fakeymacs.ei_last_window = keymap.getWindow() fakeymacs.ei_last_func = None ei_updateKeymap() def disable_emacs_ime_mode(): fakeymacs.ei_last_window = None ei_updateKeymap() ################################################## ## IME の切り替え(Emacs日本語入力モード用) ################################################## def ei_enable_input_method(): # IME の状態のバルーンヘルプを表示するために敢えてコールする enable_input_method() def ei_disable_input_method(): disable_emacs_ime_mode() disable_input_method() def ei_enable_input_method2(key, ei_keymap): keyCondition = keyhac_keymap.KeyCondition.fromString(addSideOfModifierKey(key)) if keyCondition in ei_keymap: func = ei_keymap[keyCondition] else: if key.startswith("O-"): func = ei_record_func(self_insert_command("(28)")) # [変換]キー 発行 else: func = ei_record_func(self_insert_command(key)) def _func(): if fakeymacs.ei_last_func == delete_backward_char: ei_enable_input_method() else: func() return _func def ei_disable_input_method2(key, ei_keymap): keyCondition = keyhac_keymap.KeyCondition.fromString(addSideOfModifierKey(key)) if keyCondition in ei_keymap: func = ei_keymap[keyCondition] else: if key.startswith("O-"): func = ei_record_func(self_insert_command("(29)")) # [無変換]キー 発行 else: func = ei_record_func(self_insert_command(key)) def _func(): if fakeymacs.ei_last_func == delete_backward_char: ei_disable_input_method() else: func() return _func ################################################## ## その他(Emacs日本語入力モード用) ################################################## def ei_esc(): self_insert_command("Esc")() def ei_newline(): self_insert_command("Enter")() fakeymacs.ime_cancel = True disable_emacs_ime_mode() def ei_keyboard_quit(): self_insert_command("Esc")() disable_emacs_ime_mode() ################################################## ## 共通関数(Emacs日本語入力モード用) ################################################## def ei_record_func(func): def _func(): func() fakeymacs.ei_last_func = func return _func def ei_popBalloon(ime_mode_status): if not fakeymacs.is_playing_kmacro: if fc.emacs_ime_mode_balloon_message: # LINE は入力文字にバルーンヘルプが被るので、対象外とする if not checkWindow("LINE*.EXE", "Qt5QWindowIcon"): # LINE if ime_mode_status: keymap.popBalloon("emacs_ime_mode", fc.emacs_ime_mode_balloon_message) else: keymap.closeBalloon("emacs_ime_mode") def ei_updateKeymap(): if fakeymacs.is_playing_kmacro: keymap.updateKeymap() else: keymap.delayedCall(keymap.updateKeymap, 100) ################################################## ## キーバインド(Emacs日本語入力モード用) ################################################## ## 全てキーパターンの設定(ei_record_func 関数を通すための設定) for vkey in vkeys(): s_vkey = "({})".format(vkey) define_key(keymap_ei, s_vkey, ei_record_func(self_insert_command( s_vkey))) define_key(keymap_ei, "S-" + s_vkey, ei_record_func(self_insert_command("S-" + s_vkey))) define_key(keymap_ei, "C-" + s_vkey, ei_record_func(self_insert_command("C-" + s_vkey))) define_key(keymap_ei, "C-S-" + s_vkey, ei_record_func(self_insert_command("C-S-" + s_vkey))) define_key(keymap_ei, "A-" + s_vkey, ei_record_func(self_insert_command("A-" + s_vkey))) define_key(keymap_ei, "A-S-" + s_vkey, ei_record_func(self_insert_command("A-S-" + s_vkey))) ## 「IME の切り替え」のキー設定 define_key(keymap_ei, "(243)", ei_disable_input_method) define_key(keymap_ei, "(244)", ei_disable_input_method) define_key(keymap_ei, "A-(25)", ei_disable_input_method) ## Escキーの設定 define_key(keymap_ei, "Esc", ei_record_func(ei_esc)) define_key(keymap_ei, "C-OpenBracket", ei_record_func(ei_esc)) ## 「カーソル移動」のキー設定 define_key(keymap_ei, "C-b", ei_record_func(backward_char)) define_key(keymap_ei, "C-f", ei_record_func(forward_char)) define_key(keymap_ei, "C-p", ei_record_func(previous_line)) define_key(keymap_ei, "C-n", ei_record_func(next_line)) define_key(keymap_ei, "C-a", ei_record_func(move_beginning_of_line)) define_key(keymap_ei, "C-e", ei_record_func(move_end_of_line)) define_key(keymap_ei, "Left", ei_record_func(backward_char)) define_key(keymap_ei, "Right", ei_record_func(forward_char)) define_key(keymap_ei, "Up", ei_record_func(previous_line)) define_key(keymap_ei, "Down", ei_record_func(next_line)) define_key(keymap_ei, "Home", ei_record_func(move_beginning_of_line)) define_key(keymap_ei, "End", ei_record_func(move_end_of_line)) define_key(keymap_ei, "PageUP", ei_record_func(scroll_up)) define_key(keymap_ei, "PageDown", ei_record_func(scroll_down)) ## 「カット / コピー / 削除 / アンドゥ」のキー設定 define_key(keymap_ei, "Back", ei_record_func(delete_backward_char)) define_key(keymap_ei, "C-h", ei_record_func(delete_backward_char)) define_key(keymap_ei, "Delete", ei_record_func(delete_char)) define_key(keymap_ei, "C-d", ei_record_func(delete_char)) ## 「その他」のキー設定 define_key(keymap_ei, "Enter", ei_newline) define_key(keymap_ei, "C-m", ei_newline) define_key(keymap_ei, "Tab", ei_record_func(indent_for_tab_command)) define_key(keymap_ei, "C-g", ei_keyboard_quit) ## 「スクロール」のキー設定 if fc.scroll_key: if fc.scroll_key[0]: define_key(keymap_ei, fc.scroll_key[0].replace("M-", "A-"), ei_record_func(scroll_up)) if fc.scroll_key[1]: define_key(keymap_ei, fc.scroll_key[1].replace("M-", "A-"), ei_record_func(scroll_down)) # 「IME のショートカットの置き換え」のキー設定 if fc.emacs_ime_mode_key: for replace_key, original_key in fc.emacs_ime_mode_key: define_key(keymap_ei, replace_key, ei_record_func(self_insert_command(original_key))) # この時点の keymap_ie のキーマップをコピーする ei_keymap = copy.copy(keymap_ei.keymap) ## 「IME の切り替え」のキー設定 if fc.toggle_input_method_key: for key in fc.toggle_input_method_key: define_key(keymap_ei, key, ei_disable_input_method2(key, ei_keymap)) ## 「IME の切り替え」のキー設定 if fc.set_input_method_key: for disable_key, enable_key in fc.set_input_method_key: if disable_key: define_key(keymap_ei, disable_key, ei_disable_input_method2(disable_key, ei_keymap)) if enable_key: define_key(keymap_ei, enable_key, ei_enable_input_method2(enable_key, ei_keymap)) ########################################################################### ## ファンクションの設定 ########################################################################### keymap_global = keymap.defineWindowKeymap() ################################################## ## キーバインド(ファンクション用) ################################################## ## Alt+数字キー列の設定 if fc.use_alt_digit_key_for_f1_to_f12: for i in range(10): define_key(keymap_global, "A-{}".format((i + 1) % 10), self_insert_command("({})".format(VK_F1 + i))) define_key(keymap_global, "A-Minus", self_insert_command("({})".format(VK_F11))) if is_japanese_keyboard: define_key(keymap_global, "A-Caret", self_insert_command("({})".format(VK_F12))) else: define_key(keymap_global, "A-Plus", self_insert_command("({})".format(VK_F12))) ## Alt+Shift+数字キー列の設定 if fc.use_alt_shift_digit_key_for_f13_to_f24: for i in range(10): define_key(keymap_global, "A-S-{}".format((i + 1) % 10), self_insert_command("({})".format(VK_F13 + i))) define_key(keymap_global, "A-S-Minus", self_insert_command("({})".format(VK_F23))) if is_japanese_keyboard: define_key(keymap_global, "A-S-Caret", self_insert_command("({})".format(VK_F24))) else: define_key(keymap_global, "A-S-Plus", self_insert_command("({})".format(VK_F24))) ########################################################################### ## デスクトップの設定 ########################################################################### ################################################## ## ウィンドウ操作(デスクトップ用) ################################################## def previous_window(): self_insert_command("A-S-Tab")() def next_window(): self_insert_command("A-Tab")() ################################################## ## キーバインド(デスクトップ用) ################################################## # アクティブウィンドウの切り替え for previous_key, next_key in fc.window_switching_key: define_key(keymap_global, previous_key, reset_search(reset_undo(reset_counter(reset_mark(previous_window))))) define_key(keymap_global, next_key, reset_search(reset_undo(reset_counter(reset_mark(next_window))))) # IME の「単語登録」プログラムの起動 define_key(keymap_global, fc.word_register_key, keymap.ShellExecuteCommand(None, fc.word_register_name, fc.word_register_param, "")) ########################################################################### ## タスク切り替え画面の設定 ########################################################################### def is_task_switching_window(window): if window.getClassName() in ("MultitaskingViewFrame", "TaskSwitcherWnd"): return True return False keymap_tsw = keymap.defineWindowKeymap(check_func=is_task_switching_window) ################################################## ## キーバインド(タスク切り替え画面用) ################################################## define_key(keymap_tsw, "A-b", previous_window) define_key(keymap_tsw, "A-f", next_window) define_key(keymap_tsw, "A-p", previous_window) define_key(keymap_tsw, "A-n", next_window) define_key(keymap_tsw, "A-g", self_insert_command("A-Esc")) # 個人設定ファイルのセクション [section-base-2] を読み込んで実行する exec(read_config_personal("[section-base-2]"))