Windows の操作を emacs のキーバインドで行うための設定 (Keyhac版)

【お知らせ】


<2016/11/16 追記>
「認識はしているが対策できていない課題」のところに記載していましたが、新しめのバージョンの Excel を使っているとクリップボードに関連する競合エラーが発生します。Excel の問題と思い放置していましたが、あまりにも不便なので対策を行ってみました。この対策により、Excel ではクリップボードリストへのクリップボードの記録が行われなくなっています。

<2016/11/14 追記>
Keyhac for Windows が ver 1.75 になり、keymap.updateKeymap() がサポートされました。本設定で利用していた keymap._updateKeymap() は廃止となりましたので、設定を見直しました。この修正により、本設定の Keyhac のサポートバージョは ver 1.75 以降 となります。

<2016/10/28 追記>
本設定を公開して4年が経過しようとしています。その間改善を続け、keyhac の config で xkeymacs の代わりになるものを実現するという当初の目標は概ね達成できたのではないかと思っています。そこで、本設定にニックネームを付けることとしました。
nickname: fakeymacs config
今後も末永くご利用いただければと思います。

<2016/10/12 追記>
IME を 「Google 日本語入力」とし、プロパティの「キー設定」を「ことえり」にすると、C-i(文節を縮める)、C-o(文節を伸ばす)、C-j(ひらがなに表示切替)、C-k(全角カタカナに表示切替)、C-l(全角英数に表示切替)、C-;(半角に表示切替)が近い位置(io と jkl; はそれぞれ横並びの位置)のキーに設定され、emacs日本語入力モードで有効としているキーとも被らない設定となるので、具合が良いです。(被らない設定となるのは、「ことえり」が emacsキーバインドをベースとしたキー設定となっており、emacs日本語入力モードで有効としているキーが 「ことえり」でも同じ目的のキーの設定となっているためです。またこのことは、本設定により emacsキーバインドを有効としていないアプリケーションソフトで日本語入力する場合でも emacsキーバインドを使えるということにもなります。)
もし、Windows の emacs で「emacs-mozc を動かすための設定(emacs 設定編)」を利用されている場合は、<2016/09/13 追記> の内容も確認をお願いします。

<2016/09/15 追記>
ESC を素の ESC として使いたい場合は、use_esc_as_meta 変数を False に設定してください。
C-v をペーストとして使いたい場合は、scroll_key 変数を None に設定してください。
その他のカスタマイズ設定については、configure 関数の初めの方でカスタマイズ用の変数の設定をしていますので、そのコメントを参照してください。

<2016/06/04 追記>
以前に一度 akinosign というソフトを紹介し、その後 Windows 7 でクリップボードリストとの相性問題が発生することが分かったため紹介を取りやめていましたが、Windows 10 ではこの問題が発生しないようですので改めて紹介します。Windows 10 を利用されている方は是非お試しください。

<2016/05/18 追記>
use_emacs_ime_mode 変数の設定により、emacs日本語入力モードを使うかどうかを指定できるようにしました。emacs日本語入力モードは、IME が ON の時に文字(英数字かスペースを除く特殊文字)を入力すると起動するモードです。(モードに入ると、▲のマークが表示されます。) emacs日本語入力モードになると、以下のキーのみが emacsキーバインドとして利用でき、その他のキーは Windows にそのまま渡されるようになります。このため、以下のキー以外は IME のショートカットキーとして利用することができるようになります。
  • 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 変数で指定したスクロールキー
・toggle_emacs_ime_mode_key 変数で指定したキー(emacsキーバインド用のキーではないが、emacs日本語入力モードを切り替えるキー)
emacs日本語入力モードは、以下の操作で終了します。
・Enter、C-m または C-g が押された場合
・[半角/全角] キー、A-` キーが押された場合
・BS、C-h 押下直後に toggle_input_method_key 変数で指定したキーが押された場合(間違って日本語入力をしてしまった時のキー操作を想定しての対策)
・toggle_emacs_ime_mode_key 変数で指定したキーが押された場合
利用する上での注意点としては、日本語入力を上記に記載している「emacs日本語入力モードを終了する操作」(Enter や C-g などの押下)で終えないと、emacs日本語入力モードが終了しないことです。例えば、文字を入力し BSキーで入力した文字を消したり Esc でキャンセルしたりすると日本語入力中ではなくなりますが emacs日本語入力モードは終了していません。この場合は、C-g を押下することで明示的に emacs日本語入力モードを終了させる必要があります。(BS、C-h 押下直後に toggle_input_method_key 変数に設定されているキーが押された場合についても、emacs日本語入力モードを終了させるようにしています。半角文字を入力するつもりで間違って日本語入力をしてしまった場合、BS、C-h で入力した文字を削除した後に IME を OFF にする操作をすることが想定されるため、その対策です。) 逆に、変換候補表示中に C-g を押下すると、日本語入力が終了していな状態でも emacs日本語入力モードが終了してしまいます。変換候補表示をキャンセルする場合には Esc を使うようにし、C-g と使い分けて利用するようにしてください。
なお、この機能を追加したことより、C-S-[a-z] -> C-[a-z]、A-S-[a-z] -> A-[a-z] の置き換えの機能(emacsシフトモード)を使うかどうかを use_emacs_shift_mode 変数で指定できるようにし、初期値を False(使わない)にしました。emacs日本語入力モードが気に入らない場合(emacs日本語入力モードは日本語の入力中の状態をシステム的に判定できている訳ではありませんので、どうしても想定外の動作が発生することがあります)、代わりにこちらの機能を有効にすることもできます。

これで、Windows のキーを直接的に入力する方法は以下の5とおりとなっています。
  1. 本設定で置き換えしていないキーを入力する。(置き換えしていないので、入力したキーがそのまま Windows に渡される。C-c など。)
  2. side_of_ctrl_key 変数や side_of_alt_key 変数で設定した側でない Ctrlキーや Altキーと組み合せたキーを入力する。
  3. C-q を入力した後にキーを入力する。(C-q の後に入力したキーが Windows に入力される。)
  4. (use_emacs_ime_mode 変数が True の場合) emacs日本語入力モード時に、C-[、C-b、C-f、C-p、C-n、C-a、C-e、C-h、C-d、C-m、C-g、scroll_key 変数で指定したスクロールキー、toggle_emacs_ime_mode_key 変数で指定したキー以外のキーを入力する。
  5. (use_emacs_shift_mode 変数が True の場合) Ctrlキー + [a-z] と Altキー + [a-z] の入力に限るが、Shiftキー(S-)と併せて入力する。(S- をとったキーが Windows に入力される。)

<2016/04/29 追記>
アクティブウィンドウを切り替えるキーを指定する window_switching_key 変数の初期値を変更しました。A-p、A-n は NTEmacs の shell-mode 等で使うキーであるため、window_switching_key 変数の設定は A-S-p、A-S-n を使う設定としていましたが、NTEmacs で A-S-p、A-S-n が A-p、A-n の代替として使えることが分かりましたので、利用頻度を考え、window_switching_key 変数を shift 無しのキー設定(A-p、A-n)に変更しました。

<2016/03/28 追記>
ウィンドウ操作関数での動作に統一性を持たせるため、操作対象とするウィンドウのリストを getWindowList 関数で生成し、その生成したウィンドウリストに対して操作を行うように処理を変更しました。getWindowList 関数によるウィンドウリストの生成結果はランチャーリスト(A-l で起動)で表示されるものと(<Desktop> 行以外は)一緒ですので、もし操作対象とすべきでないウィンドウ(非表示のウィンドウなど)がリスト含まれている場合には、getWindowList 関数内で調整してください。
なお、以前に、本設定を Windows 10 で使った場合、表示されていないストアアプリがランチャーリストに表示されることの報告をし、暫定対策としてリストからの強制削除を行っている旨の報告をしておりましたが、この問題についてもスマートな対処方法が見つかりましたので併せて対応を行いました。

<2015/11/09 追記>
redo をサポートしてみました。undo キー(C-x u や C-/)で undo している時に、C-g を押下すると 以降の動作が redo に切り替わります。その後は、C-g を押すごとに undo と redo をトグルする動きとなります。
なお、redo は Windows に C-y キーを発行することで実現しているのですが、アプリケーションソフトによっては、C-y をサポートしていません。(NotePad など。)このため、このようなソフトで redo に移行すると、undo キーを押してもだんまりとなる場合があります。この場合は再度 C-g を押すことで復帰してください。(undo キー と C-g 以外のキーを入力することでも、undo のモードに復帰します。)また、アプリケーションソフト単位で redo の動作を無効にすることができます。undo 関数の中で行っていますので、必要であれば設定を追加してください。(初期設定では、NotePad を登録しています。)

<2015/10/31 追記>
Keyhac のクリップボードリスト画面で migemo 検索を可能とするためには、辞書ファイルを登録する必要があります。次の URL の説明が参考となります。(dictフォルダの中をすべてコピーするのではなく、dict/utf-8 の中のファイルをコピーするところがポイントです。また、migemo 検索するには、検索文字列の一文字目を大文字で指定する必要があります。)

<2014/10/17 追記>
検索の繰り返し機能をサポートしました。C-g 等のコマンド入力で、検索のやり直しが可能です。検索の繰り返しは F3キー で行っているのですが、F3キーをサポートしていないアプリがあるため、繰り返し検索時にダンマリとなることがあります。その際は、C-g を押下後、C-s や C-r で検索を再開し、Windows の割当キー(Enter 等)を使って検索の繰り返しを行ってください。

【認識はしているが対策できていない課題】


  • 仮想デスクトップでの利用を踏まえ、ウィンドウの最小化は現在のデスクトップ内に表示しているウィンドウに対してのみ行われるようにしているが、最小化しているウィンドウのリストアは複数のデスクトップに渡って行われてしまう。
  • TeraPad の行末削除ができない。(対策は不可能と思われますので、C-d をお使いください。)
  • キーボードマクロで記録した操作を Ctl-x e で再生する場合、数引数を指定して再生すると、再生により表示される文字列に「e」の文字が混入する場合がある。Keyhac 内部で発生している問題と思われ、本設定での対策は不可能と思われます。

【本題】


Windows の操作を emacs のキーバインドで行うための設定です。使い方は以下で紹介していただいておりますので、そちらを参照ください。

なお、Keyhac は xkeymacs と異なり、IME による日本語入力中であることを判定することができません。このため、日本語入力中に IME の変換操作を行う方法として、以下の3つの方法を提供しています。

1) emacs日本語入力モード (利用するかは use_emacs_ime_mode 変数で設定。初期値:True(使う))

IME が ON の時に文字(英数字かスペースを除く特殊文字)を入力すると起動するモードです。(モードに入ると、▲のマークが表示されます。) emacs日本語入力モードになると emacsキーバインドとして利用できるキーが限定され、その他のキーは Windows にそのまま渡されるようになるため、IME のショートカットキーを利用できるようになります。詳しい仕様は、本ページの初めの方にある <2016/05/18 追記> の内容を参照ください。

2) emacsシフトモード (利用するかは use_emacs_shift_mode 変数で設定。初期値:False(使わない))

本設定のキーバインドと IME のショートカットキーが被って設定されている場合、日本語入力中にそのキーを Shiftキーと一緒に押すことで IME のショートカットキーを利用することができます。このモードを Windows 8 以降の OS で利用する場合には、次の設定を行う必要があるようです。

3) その他の方法 (本設定の仕様としてデフォルトで利用可能)

  • 本設定で置き換えしていないキーを入力する。(但し、Ctrl とアルファベットを組み合わせたキーは、ほぼ全て置き換えがされています。)
  • side_of_ctrl_key 変数や side_of_alt_key 変数で設定した側でない Ctrlキーや Altキーと組み合わせたキーを使う。
  • 入力するキーに先行して C-q を入力する。(emacs日本語入力モードを使っていない場合に有効な方法です。)

# -*- mode: python; coding: utf-8-with-signature-dos -*-

##                          nickname: fakeymacs config
##
## Windows の操作を emacs のキーバインドで行うための設定(Keyhac版)ver.20161120_01
##

# このスクリプトは、Keyhac for Windows ver 1.75 以降で動作します。
#   https://sites.google.com/site/craftware/keyhac-ja
# スクリプトですので、使いやすいようにカスタマイズしてご利用ください。
#
# この内容は、utf-8-with-signature-dos の coding-system で config.py の名前でセーブして
# 利用してください。
#
# 本設定を利用するための仕様は、以下を参照してください。
#
# <共通の仕様>
# ・not_emacs_target 変数と ime_target 変数で、emacsキーバインドや IME の切り替えキーバインド
#   の対象とするアプリケーションソフトを指定できる。
# ・日本語と英語のどちらのキーボードを利用するかを is_japanese_keyboard 変数で指定できる。
# ・左右どちらの 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 変数の設定により、IME を切り替えるキーを指定できる。
# ・use_emacs_ime_mode 変数の設定により、emacs日本語入力モードを使うかどうかを指定
#   できる。emacs日本語入力モードは、IME が ON の時に文字(英数字かスペースを除く
#   特殊文字)を入力すると起動する。
#   emacs日本語入力モードでは、以下のキーのみが emacsキーバインドとして利用でき、
#   その他のキーは Windows にそのまま渡されるようになるため、IME のショートカットキー
#   として利用することができる。
#   ・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 変数で指定したスクロールキー
#     ・toggle_emacs_ime_mode_key 変数で指定したキー
#      (emacsキーバインド用のキーではないが、emacs日本語入力モードを切り替えるキー)
#   emacs日本語入力モードは、以下の操作で終了する。
#   ・Enter、C-m または C-g が押された場合
#   ・[半角/全角] キー、A-` キーが押された場合
#   ・BS、C-h 押下直後に toggle_input_method_key 変数で指定したキーが押された場合
#     (間違って日本語入力をしてしまった時のキー操作を想定しての対策)
#   ・toggle_emacs_ime_mode_key 変数で指定したキーが押された場合
# ・emacs日本語入力モードの使用を有効にした際、emacs_ime_mode_balloon_message 変数の
#   設定でバルーンメッセージとして表示する文字列を指定できる。
# ・use_emacs_shift_mode 変数の設定により、emacsシフトモードを使うかどうかを指定できる。
#   emacsシフトモードを使う場合は以下の動きとなる。
#   ・C-[a-z]キーを Shiftキーと一緒に押した時は、Shiftキーをとったキー(C-[a-z])が
#     Windows に入力される。
#   ・A-[a-z]キーを Shiftキーと一緒に押した時は、Shiftキーをとったキー(A-[a-z])が
#     Windows に入力される。
#
# <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 変数の設定により、スクロールに使うキーを指定できる。
# ・C-c、C-z は、Windows の「コピー」、「取り消し」が機能するようにしている。
#   ctl_x_prefix_key 変数が C-x 以外に設定されている場合には、C-x が Windows の
#   「カット」として機能するようにしている。
# ・C-k を連続して実行しても、クリップボードへの削除文字列の蓄積は行われない。
#   複数行を一括してクリップボードに入れたい場合は、削除の範囲をマークして削除するか
#   前置引数を指定して削除する。
# ・C-y を前置引数を指定して実行すると、ヤンク(ペースト)の繰り返しが行われる。
# ・C-l は、アプリケーションソフト個別対応とする。recenter 関数で個別に指定すること。
#   この設定では、Sakura Editor のみ対応している。
# ・キーボードマクロは emacs の挙動と異なり、IME の変換キーも含めた入力したキーそのものを
#   記録する。このため、キーボードマクロ記録時や再生時、IME の状態に留意した利用が必要。
#
# <全てのアプリケーションソフトで共通の動き>
# ・other_window_key 変数に設定したキーにより、表示しているウインドウの中で、一番最近
#   までフォーカスがあったウインドウに移動する。NTEmacs の機能やランチャーの機能から
#   Windows アプリケーションソフトを起動した際に、起動元のアプリケーションソフトに戻る
#   のに便利。この機能は Ctl-x o にも割り当てているが、こちらは emacs のキーバインドを
#   適用したアプリケーションソフトのみで有効となる。
# ・clipboardList_key 変数に設定したキーにより、クリップボードリストが起動する。
#   (C-f、C-b でリストの変更、C-n、C-p でリスト内を移動し、Enter で確定する。
#     C-s、C-r で検索も可能。migemo 辞書を登録してあれば、検索文字を大文字で始める
#     ことで migemo 検索も可能。emacs キーバインドを適用しないアプリケーションソフト
#     でもクリップボードリストは起動し、選択した項目を Enter で確定することで、
#     クリップボードへの格納(テキストの貼り付けではない)が行われる。)
# ・lancherList_key 変数に設定したキーにより、ランチャーリストが起動する。
#   (全てのアプリケーションソフトで利用可能。操作方法は、クリップボードリストと同じ。)
# ・クリップボードリストやランチャーリストのリストボックス内では、基本、Altキーを
#   Ctrlキーと同じキーとして扱っている。(C-v と A-v の置き換えのみ行っていない。)
# ・window_switching_key 変数に設定したキーにより、アクティブウィンドウの切り替えが行われ
#   る。アクティブウィンドウを切り替える際、切り替わったウィンドウが最小化されている場合は、
#   ウィンドウのリストアも併せて行われる。
# ・マルチディスプレイを利用している際に、window_movement_key 変数に設定したキーにより、
#   アクティブウィンドウのディスプレイ間の移動が行われる。
# ・window_minimize_key 変数に設定したキーにより、ウィンドウの最小化、リストアが行われる。
# ・desktop_switching_key 変数に設定したキーにより、仮想デスクトップの切り替えが行われる。
#   (仮想デスクトップの利用については、以下を参照ください。
#     ・http://pc-karuma.net/windows-10-virtual-desktops/
#     ・http://pc-karuma.net/windows-10-virtual-desktop-show-all-window-app/
#     仮想デスクトップ切替時のアニメーションを止める方法は以下を参照ください。
#     ・http://www.jw7.org/2015/11/03/windows10_virtualdesktop_animation_off/ )

import time
import sys
import os.path
import re

import keyhac_keymap
import keyhac_hook
from keyhac import *

def configure(keymap):

    ####################################################################################################
    ## カスタマイズの設定
    ####################################################################################################

    # emacs のキーバインドに"したくない"アプリケーションソフトを指定する
    # (Keyhac のメニューから「内部ログ」を ON にすると processname や classname を確認することができます。)
    not_emacs_target = ["cmd.exe",            # cmd
                        "mintty.exe",         # mintty
                        "emacs.exe",          # Emacs
                        "emacs-w32.exe",      # Emacs
                        "gvim.exe",           # GVim
                        # "eclipse.exe",        # Eclipse
                        # "firefox.exe",        # firefox
                        "xyzzy.exe",          # xyzzy
                        "VirtualBox.exe",     # VirtualBox
                        "XWin.exe",           # Cygwin/X
                        "Xming.exe",          # Xming
                        "putty.exe",          # PuTTY
                        "ttermpro.exe",       # TeraTerm
                        "MobaXterm.exe",      # MobaXterm
                        "TurboVNC.exe",       # TurboVNC
                        "vncviewer.exe"]      # UltraVNC

    # IME の切り替えのみをしたいアプリケーションソフトを指定する
    # (指定できるアプリケーションソフトは、not_emacs_target で(除外)指定したものからのみとなります。)
    ime_target       = ["cmd.exe",            # cmd
                        "mintty.exe",         # mintty
                        "gvim.exe",           # GVim
                        # "eclipse.exe",        # Eclipse
                        # "firefox.exe",        # firefox
                        "xyzzy.exe",          # xyzzy
                        "putty.exe",          # PuTTY
                        "ttermpro.exe",       # TeraTerm
                        "MobaXterm.exe"]      # MobaXterm

    # 日本語キーボードかどうかを指定する(True: 日本語キーボード、False: 英語キーボード)
    is_japanese_keyboard = True

    # 左右どちらの Ctrlキーを使うかを指定する("L": 左、"R": 右)
    side_of_ctrl_key = "L"

    # 左右どちらの Altキーを使うかを指定する("L": 左、"R": 右)
    side_of_alt_key = "L"

    # emacs日本語入力モードを使うかどうかを指定する(True: 使う、False: 使わない)
    use_emacs_ime_mode = True

    # emacs日本語入力モードを切り替える(トグルする)キーを指定する
    toggle_emacs_ime_mode_key = "C-t"

    # emacs日本語入力モードが有効なときに表示するバルーンメッセージを指定する
    # emacs_ime_mode_balloon_message = None
    emacs_ime_mode_balloon_message = "▲"

    # emacsシフトモードを使うかどうかを指定する(True: 使う、False: 使わない)
    use_emacs_shift_mode = False

    # IME を切り替えるキーを指定する(複数指定可)
    # toggle_input_method_key = ["C-Yen"]
    toggle_input_method_key = ["C-Yen", "C-o"]

    # C-iキーを Tabキーとして使うかどうかを指定する(True: 使う、False: 使わない)
    use_ctrl_i_as_tab = True

    # Escキーを Metaキーとして使うかどうかを指定する(True: 使う、False: 使わない)
    use_esc_as_meta = True

    # Ctl-xプレフィックスキーに使うキーを指定する
    # (Ctl-xプレフィックスキーのモディファイアキーは、Ctrl または Alt のいずれかから指定してください)
    ctl_x_prefix_key = "C-x"

    # スクロールに使うキーの組み合わせ(Up、Down の順)を指定する
    # scroll_key = None # PageUp、PageDownキーのみを利用する
    scroll_key = ["M-v", "C-v"]

    # 表示しているウインドウの中で、一番最近までフォーカスがあったウインドウに移動するキーを指定する
    other_window_key = "A-o"

    # クリップボードリストを起動するキーを指定する
    clipboardList_key = "A-y"

    # ランチャーリストを起動するキーを指定する
    lancherList_key = "A-l"

    # アクティブウィンドウを切り替えるキーの組み合わせ(前、後 の順)を指定する(複数指定可)
    window_switching_key = [["A-p", "A-n"], ["A-Up", "A-Down"]]

    # アクティブウィンドウをディスプレイ間で移動するキーの組み合わせ(前、後 の順)を指定する(複数指定可)
    # (other_window_key に割り当てている A-o との連係した利用を想定し、A-C-o を割り当てています。)
    # window_movement_key = None # Single display
    window_movement_key = [[None, "A-C-o"], ["A-Left", "A-Right"]] # Multi-display

    # ウィンドウを最小化、リストアするキーの組み合わせ(リストア、最小化 の順)を指定する(複数指定可)
    window_minimize_key = [["A-r", "A-m"]]

    # 仮想デスクトップを切り替えるキーの組み合わせ(前、後 の順)を指定する(複数指定可)
    # desktop_switching_key = None # for Windows 7 or 8.1
    desktop_switching_key = [["A-C-p", "A-C-n"], ["A-C-Left", "A-C-Right"]] # for Windows 10

    # shell_command 関数で起動するアプリケーションソフトを指定する
    # (パスが通っていない場所にあるコマンドは、絶対パスで指定してください。)
    command_name = r"cmd.exe"


    ####################################################################################################
    ## 基本設定
    ####################################################################################################

    # 変数を格納するクラスを定義する
    class Fakeymacs:
        pass

    fakeymacs = Fakeymacs()

    fakeymacs.last_window = None

    def is_emacs_target(window):
        if window != fakeymacs.last_window:
            if window.getProcessName() == "EXCEL.EXE": # Microsoft Excel
                # クリップボードの監視用のフックを無効にする
                keymap.clipboard_history.enableHook(False)
            else:
                # クリップボードの監視用のフックを有効にする
                keymap.clipboard_history.enableHook(True)

            fakeymacs.last_window = window

        if is_list_window(window):
            return False

        if window.getProcessName() in not_emacs_target:
            fakeymacs.keybind = "not_emacs"
            return False

        fakeymacs.keybind = "emacs"
        return True

    def is_ime_target(window):
        if window.getProcessName() in ime_target:
            return True
        return False

    if 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 になる
    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 ctl_x_prefix_key:
        keyCondition = keyhac_keymap.KeyCondition.fromString(ctl_x_prefix_key)

        if keyCondition.mod == MODKEY_CTRL:
            if 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 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 toggle_input_method():
        self_insert_command("A-(25)")()
        delay(0.05)

        # IME の状態を格納する
        ime_status = keymap.getWindow().getImeStatus()
        if use_emacs_ime_mode:
            fakeymacs.ei_ime_status = ime_status

        if not fakeymacs.is_playing_kmacro:
            if ime_status:
                message = "[あ]"
            else:
                message = "[A]"

            # IME の状態をバルーンヘルプで表示する
            keymap.popBalloon("ime_status", message, 500)

    ##################################################
    ## ファイル操作
    ##################################################

    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$"): # Microsoft Word
            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$|SakuraView166$"): # 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):
        fakeymacs.is_marked = True
        def move_beginning_of_region():
            for i in range(repeat):
                backward_word()
        mark(move_beginning_of_region)()
        delay()
        kill_region()

    def kill_word(repeat=1):
        fakeymacs.is_marked = True
        def move_end_of_region():
            for i in range(repeat):
                forward_word()
        mark(move_end_of_region)()
        delay()
        kill_region()

    def kill_line(repeat=1):
        fakeymacs.is_marked = True
        if repeat == 1:
            mark(move_end_of_line)()
            delay()
            if checkWindow("Hidemaru.exe$", "HM32CLIENT$"): # Hidemaru Editor
                self_insert_command("C-x")()
                delay()
                if getClipboardText() == "":
                    self_insert_command("Delete")()
            else:
                self_insert_command("C-c", "Delete")() # 改行を消せるようにするため C-x にはしていない
        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)()
            delay()
            kill_region()

    def kill_region():
        self_insert_command("C-x")()

    def kill_ring_save():
        self_insert_command("C-c")()
        if (checkWindow("sakura.exe$", "EditorClient$|SakuraView166$") or # Sakura Editor
            checkWindow("Code.exe$", "Chrome_WidgetWin_1$")):             # Visual Studio Code
            # 選択されているリージョンのハイライトを解除するために Esc を発行する
            self_insert_command("Esc")()

    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:
            fakeymacs.is_marked = False
        else:
            fakeymacs.is_marked = True

    def mark_whole_buffer():
        if checkWindow("EXCEL.EXE$", "EXCEL"): # Microsoft Excel
            # Excel のセルの中でも機能するようにする対策
            self_insert_command("C-End", "C-S-Home")()
        else:
            self_insert_command("C-Home", "C-a")()

    def mark_page():
        mark_whole_buffer()

    def open_line():
        self_insert_command("Enter", "Up", "End")()

    ##################################################
    ## バッファ / ウインドウ操作
    ##################################################

    def kill_buffer():
        self_insert_command("C-F4")()

    def switch_to_buffer():
        self_insert_command("C-Tab")()

    def other_window():
        window_list = getWindowList()
        for wnd in window_list[1:]:
            if not wnd.isMinimized():
                wnd.getLastActivePopup().setForeground()
                break

    ##################################################
    ## 文字列検索 / 置換
    ##################################################

    def isearch(direction):
        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$|SakuraView166$") or # Sakura Editor
            checkWindow("Hidemaru.exe$", "HM32CLIENT$")):                 # Hidemaru Editor
            self_insert_command("C-r")()
        else:
            self_insert_command("C-h")()

    ##################################################
    ## キーボードマクロ
    ##################################################

    def kmacro_start_macro():
        keymap.command_RecordStart()

    def kmacro_end_macro():
        keymap.command_RecordStop()
        # キーボードマクロの終了キー「Ctl-xプレフィックスキー + ")"」の Ctl-xプレフィックスキーがマクロに
        # 記録されてしまうのを対策する(キーボードマクロの終了キーの前提を「Ctl-xプレフィックスキー + ")"」
        # としていることについては、とりえず了承ください。)
        if 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():
        fakeymacs.is_playing_kmacro = True
        keymap.command_RecordPlay()
        fakeymacs.is_playing_kmacro = False

    ##################################################
    ## その他
    ##################################################

    def newline():
        self_insert_command("Enter")()

    def newline_and_indent():
        self_insert_command("Enter", "Tab")()

    def indent_for_tab_command():
        self_insert_command("Tab")()

    def keyboard_quit():
        # Microsoft Excel または Evernote 以外の場合、Esc を発行する
        if not (checkWindow("EXCEL.EXE$", "EXCEL") or checkWindow("Evernote.exe$", "WebViewHost$")):
            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():
        self_insert_command("A-F4")()

    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 shell_command():
        def popCommandWindow(wnd, command):
            if wnd.isVisible() and not wnd.getOwner() and wnd.getProcessName() == command:
                popWindow(wnd)()
                fakeymacs.is_executing_command = True
                return False
            return True

        fakeymacs.is_executing_command = False
        Window.enum(popCommandWindow, os.path.basename(command_name))

        if not fakeymacs.is_executing_command:
            keymap.ShellExecuteCommand(None, command_name, "", "")()

    ##################################################
    ## 共通関数
    ##################################################

    def checkWindow(processName, className):
        return ((processName is None or re.match(processName, keymap.getWindow().getProcessName())) and
                (className is None or re.match(className, keymap.getWindow().getClassName())))

    def delay(sec=0.02):
        time.sleep(sec)

    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 addSideModifier(key):
        key = key.replace("C-", side_of_ctrl_key + "C-")
        key = key.replace("A-", side_of_alt_key + "A-")
        return key

    def kbd(keys):
        if keys:
            keys_lists = [keys.split()]

            if keys_lists[0][0] == "Ctl-x":
                if ctl_x_prefix_key:
                    keys_lists[0][0] = 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 use_esc_as_meta:
                    keys_lists.append(["Esc", key])

            for keys_list in keys_lists:
                keys_list[0] = addSideModifier(keys_list[0])
        else:
            keys_lists = []

        return keys_lists

    def define_key(keymap, keys, command):
        for keys_list in kbd(keys):
            if len(keys_list) == 1:
                keymap[keys_list[0]] = command
            else:
                keymap[keys_list[0]][keys_list[1]] = command

    def self_insert_command(*keys):
        return keymap.InputKeyCommand(*list(map(addSideModifier, keys)))

    if use_emacs_ime_mode:
        def self_insert_command2(*keys):
            func = self_insert_command(*keys)
            def _func():
                func()
                if fakeymacs.ei_ime_status:
                    enable_emacs_ime_mode()
            return _func
    else:
        def self_insert_command2(*keys):
            return self_insert_command(*keys)

    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 mark(func):
        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")()
            else:
                func()
        return _func

    def reset_mark(func):
        def _func():
            func()
            fakeymacs.is_marked = False
        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():
            # 以下の2行は、キーボードマクロの繰り返し実行の際に必要な設定
            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():
            func(fakeymacs.repeat_counter)
        return _func

    ##################################################
    ## キーバインド
    ##################################################

    # キーバインドの定義に利用している表記の意味は以下のとおりです。
    # ・S-    : Shiftキー
    # ・C-    : Ctrlキー
    # ・A-    : Altキー
    # ・M-    : Altキー と Esc、C-[ のプレフィックスキーを利用する3パターンを定義(emacs の Meta と同様)
    # ・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://homepage3.nifty.com/ic/help/rmfunc/vkey.htm
    # http://www.azaelia.net/factory/vk.html

    ## マルチストロークキーの設定
    define_key(keymap_emacs, "Ctl-x",         keymap.defineMultiStrokeKeymap(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 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))
        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 = "(" + str(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))

    ## 特殊文字キーの設定
    s_vkey = "(" + str(VK_SPACE) + ")"
    define_key(keymap_emacs,        s_vkey, reset_undo(reset_counter(reset_mark(repeat(self_insert_command(       s_vkey))))))
    define_key(keymap_emacs, "S-" + s_vkey, reset_undo(reset_counter(reset_mark(repeat(self_insert_command("S-" + s_vkey))))))

    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 = "(" + str(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 = "(" + str(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 = "(" + str(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))))))

    ## C-S-[a-z] -> C-[a-z]、A-S-[a-z] -> A-[a-z] の置き換え設定(emacsシフトモードの設定)
    if use_emacs_shift_mode:
        for vkey in range(VK_A, VK_Z + 1):
            s_vkey = "(" + str(vkey) + ")"
            define_key(keymap_emacs, "C-S-" + s_vkey, reset_search(reset_undo(reset_counter(reset_mark(self_insert_command("C-" + s_vkey))))))
            define_key(keymap_emacs, "A-S-" + s_vkey, reset_search(reset_undo(reset_counter(reset_mark(self_insert_command("A-" + s_vkey))))))
            define_key(keymap_ime,   "C-S-" + s_vkey, self_insert_command("C-" + s_vkey))
            define_key(keymap_ime,   "A-S-" + s_vkey, self_insert_command("A-" + s_vkey))

    ## Escキーの設定
    define_key(keymap_emacs, "C-OpenBracket C-OpenBracket", reset_undo(reset_counter(self_insert_command("Esc"))))
    if 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))))))
    define_key(keymap_emacs, "C-f",        reset_search(reset_undo(reset_counter(mark(repeat(forward_char))))))
    define_key(keymap_emacs, "M-b",        reset_search(reset_undo(reset_counter(mark(repeat(backward_word))))))
    define_key(keymap_emacs, "M-f",        reset_search(reset_undo(reset_counter(mark(repeat(forward_word))))))
    define_key(keymap_emacs, "C-p",        reset_search(reset_undo(reset_counter(mark(repeat(previous_line))))))
    define_key(keymap_emacs, "C-n",        reset_search(reset_undo(reset_counter(mark(repeat(next_line))))))
    define_key(keymap_emacs, "C-a",        reset_search(reset_undo(reset_counter(mark(move_beginning_of_line)))))
    define_key(keymap_emacs, "C-e",        reset_search(reset_undo(reset_counter(mark(move_end_of_line)))))
    define_key(keymap_emacs, "M-S-Comma",  reset_search(reset_undo(reset_counter(mark(beginning_of_buffer)))))
    define_key(keymap_emacs, "M-S-Period", reset_search(reset_undo(reset_counter(mark(end_of_buffer)))))
    define_key(keymap_emacs, "C-l",        reset_search(reset_undo(reset_counter(recenter))))

    define_key(keymap_emacs, "Left",     reset_search(reset_undo(reset_counter(mark(repeat(backward_char))))))
    define_key(keymap_emacs, "Right",    reset_search(reset_undo(reset_counter(mark(repeat(forward_char))))))
    define_key(keymap_emacs, "Up",       reset_search(reset_undo(reset_counter(mark(repeat(previous_line))))))
    define_key(keymap_emacs, "Down",     reset_search(reset_undo(reset_counter(mark(repeat(next_line))))))
    define_key(keymap_emacs, "PageUP",   reset_search(reset_undo(reset_counter(mark(scroll_up)))))
    define_key(keymap_emacs, "PageDown", reset_search(reset_undo(reset_counter(mark(scroll_down)))))
    define_key(keymap_emacs, "Home",     reset_search(reset_undo(reset_counter(mark(move_beginning_of_line)))))
    define_key(keymap_emacs, "End",      reset_search(reset_undo(reset_counter(mark(move_end_of_line)))))

    ## 「カット / コピー / 削除 / アンドゥ」のキー設定
    define_key(keymap_emacs, "Back",     reset_search(reset_undo(reset_counter(reset_mark(repeat2(delete_backward_char))))))
    define_key(keymap_emacs, "C-h",      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-d",      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, "M-Delete", 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, "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-c",      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-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))))
    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))))

    # 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(reset_mark(mark_whole_buffer)))))
    define_key(keymap_emacs, "Ctl-x C-p", reset_search(reset_undo(reset_counter(reset_mark(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, "Ctl-x o", reset_search(reset_undo(reset_counter(reset_mark(other_window)))))

    ## 「文字列検索 / 置換」のキー設定
    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, "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)))))
    define_key(keymap_emacs, "M-S-1",     reset_search(reset_undo(reset_counter(reset_mark(shell_command)))))

    if use_ctrl_i_as_tab:
        define_key(keymap_emacs, "C-i", reset_undo(reset_counter(reset_mark(repeat(indent_for_tab_command)))))

    ## 「IME の切り替え」のキー設定(上書きされないように最後に設定する)
    if toggle_input_method_key:
        for key in toggle_input_method_key:
            define_key(keymap_emacs, key, toggle_input_method)
            define_key(keymap_ime,   key, toggle_input_method)

    ## 「スクロール」のキー設定(上書きされないように最後に設定する)
    if scroll_key:
        define_key(keymap_emacs, scroll_key[0], reset_search(reset_undo(reset_counter(mark(scroll_up)))))
        define_key(keymap_emacs, scroll_key[1], reset_search(reset_undo(reset_counter(mark(scroll_down)))))

    ## 「カット」のキー設定(上書きされないように最後に設定する)
    if ctl_x_prefix_key != "C-x":
        define_key(keymap_emacs, "C-x", reset_search(reset_undo(reset_counter(reset_mark(kill_region)))))


    ####################################################################################################
    ## emacs日本語入力モードの設定
    ####################################################################################################
    if use_emacs_ime_mode:

        def is_emacs_ime_mode(window):
            fakeymacs.ei_ime_status = window.getImeStatus()

            if fakeymacs.ei_last_window:
                if fakeymacs.ei_last_window == window:
                    return True
                else:
                    disable_emacs_ime_mode(False)
                    return False
            else:
                return False

        keymap_ei = keymap.defineWindowKeymap(check_func=is_emacs_ime_mode)

        # IME の状態を格納する
        fakeymacs.ei_ime_status = False

        # emacs日本語入力モードが開始されたときのウィンドウオブジェクトを格納する変数を初期化する
        fakeymacs.ei_last_window = None

        ##################################################
        ## emacs日本語入力モード の切り替え
        ##################################################

        def enable_emacs_ime_mode(update=True, toggle=False):
            fakeymacs.ei_last_window = keymap.getWindow()
            fakeymacs.ei_last_func = None
            ei_popBalloon(toggle)
            if update:
                keymap.updateKeymap()

        def disable_emacs_ime_mode(update=True, toggle=False):
            fakeymacs.ei_last_window = None
            ei_popBalloon(toggle)
            if update:
                keymap.updateKeymap()

        def toggle_emacs_ime_mode():
            if fakeymacs.ei_last_window:
                disable_emacs_ime_mode(True, True)
            else:
                enable_emacs_ime_mode(True, True)

        ##################################################
        ## IME の切り替え(emacs日本語入力モード用)
        ##################################################

        def ei_toggle_input_method():
            disable_emacs_ime_mode()
            toggle_input_method()

        def ei_toggle_input_method2(key):
            def _func():
                if fakeymacs.ei_last_func == delete_backward_char:
                    ei_toggle_input_method()
                else:
                    ei_record_func(self_insert_command(key)())
            return _func

        ##################################################
        ## その他(emacs日本語入力モード用)
        ##################################################

        def ei_esc():
            self_insert_command("Esc")()

        def ei_newline():
            self_insert_command("Enter")()
            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(toggle):
            if not fakeymacs.is_playing_kmacro:
                if emacs_ime_mode_balloon_message:
                    if fakeymacs.ei_last_window:
                        keymap.popBalloon("emacs_ime_mode", emacs_ime_mode_balloon_message)
                    else:
                        keymap.closeBalloon("emacs_ime_mode")
                else:
                    if toggle:
                        if fakeymacs.ei_last_window:
                            message = "[IME]"
                        else:
                            message = "[main]"
                        keymap.popBalloon("emacs_ime_mode", message, 500)

        def ei_hook_mouseup(x, y, vk):
            if fakeymacs.ei_last_window:
                disable_emacs_ime_mode()
            else:
                keymap.updateKeymap()

            fakeymacs.ei_hook_mouseup(x, y, vk)

        # マウスのボタンが離されたときに呼び出されるフック関数を設定する
        keymap.enableHook(True) # 設定のリロード時にフックの設定がネストしないようにコール
        fakeymacs.ei_hook_mouseup = keyhac_hook.hook.mouseup
        keyhac_hook.hook.mouseup = ei_hook_mouseup

        ##################################################
        ## キーバインド(emacs日本語入力モード用)
        ##################################################

        ## 全てキーパターンの設定(ei_record_func 関数を通すための設定)
        for vkey in vkeys():
            s_vkey = "(" + str(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)))

        ## C-S-[a-z] -> C-[a-z]、A-S-[a-z] -> A-[a-z] の置き換え設定(emacsシフトモードの設定)
        if use_emacs_shift_mode:
            for vkey in range(VK_A, VK_Z + 1):
                s_vkey = "(" + str(vkey) + ")"
                define_key(keymap_ei, "C-S-" + s_vkey, ei_record_func(self_insert_command("C-" + s_vkey)))
                define_key(keymap_ei, "A-S-" + s_vkey, ei_record_func(self_insert_command("A-" + s_vkey)))

        ## 「IME の切り替え」のキー設定
        define_key(keymap_ei, "(243)",  ei_toggle_input_method)
        define_key(keymap_ei, "(244)",  ei_toggle_input_method)
        define_key(keymap_ei, "A-(25)", ei_toggle_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, "PageUP",   ei_record_func(scroll_up))
        define_key(keymap_ei, "PageDown", ei_record_func(scroll_down))
        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, "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)

        ## 「IME の切り替え」のキー設定(上書きされないように最後に設定する)
        if toggle_input_method_key:
            for key in toggle_input_method_key:
                define_key(keymap_ei, key, ei_toggle_input_method2(key))

        ## 「スクロール」のキー設定(上書きされないように最後に設定する)
        if scroll_key:
            define_key(keymap_ei, scroll_key[0].replace("M-", "A-"), ei_record_func(scroll_up))
            define_key(keymap_ei, scroll_key[1].replace("M-", "A-"), ei_record_func(scroll_down))

        ## emacs日本語入力モードを切り替える(トグルする)
        define_key(keymap_emacs, toggle_emacs_ime_mode_key, toggle_emacs_ime_mode)
        define_key(keymap_ime,   toggle_emacs_ime_mode_key, toggle_emacs_ime_mode)
        define_key(keymap_ei,    toggle_emacs_ime_mode_key, toggle_emacs_ime_mode)


    ####################################################################################################
    ## デスクトップの設定
    ####################################################################################################

    keymap_global = keymap.defineWindowKeymap()

    ##################################################
    ## ウインドウ操作(デスクトップ用)
    ##################################################

    def popWindow(wnd):
        def _func():
            try:
                if wnd.isMinimized():
                    wnd.restore()
                wnd.getLastActivePopup().setForeground()
            except:
                print("選択したウィンドウは存在しませんでした")
        return _func

    def getWindowList():
        def makeWindowList(wnd, arg):
            if wnd.isVisible() and not wnd.getOwner():

                class_name = wnd.getClassName()
                title = wnd.getText()

                if class_name == "Emacs" or title != "":

                    # 操作の対象としたくないアプリケーションソフトのクラス名称を、re.match 関数
                    # (先頭からのマッチ)の正規表現に「|」を使って繋げて指定してください。
                    # (完全マッチとするためには $ の指定が必要です。)
                    if not re.match(r"Progman$", class_name):

                        process_name = wnd.getProcessName()

                        # 操作の対象としたくないアプリケーションソフトのプロセス名称を、re.match 関数
                        # (先頭からのマッチ)の正規表現に「|」を使って繋げて指定してください。
                        # (完全マッチとするためには $ の指定が必要です。)
                        if not re.match(r"RocketDock.exe$", process_name): # サンプルとして RocketDock.exe を登録

                            # 表示されていないストアアプリ(「設定」等)が window_list に登録されるのを抑制する
                            if class_name == "Windows.UI.Core.CoreWindow":
                                if title in window_dict:
                                    window_list.remove(window_dict[title])
                                else:
                                    window_dict[title] = wnd
                            elif class_name == "ApplicationFrameWindow":
                                if title not in window_dict:
                                    window_dict[title] = wnd
                                    window_list.append(wnd)
                            else:
                                window_list.append(wnd)

                            # print(process_name + " : " + class_name + " : " + title + " : " + str(wnd.isMinimized()))
            return True

        window_dict = {}
        window_list = []
        # print("----------------------------------------------------------------------------------------------------")
        Window.enum(makeWindowList, None)

        return window_list

    def restoreWindow():
        wnd = keymap.getTopLevelWindow()
        if wnd and wnd.isMinimized():
            wnd.restore()

    def previous_desktop():
        self_insert_command("W-C-Left")()

    def next_desktop():
        self_insert_command("W-C-Right")()

    def previous_window():
        self_insert_command("A-S-Esc")()
        delay(0.2)
        keymap.delayedCall(restoreWindow, 0)

    def next_window():
        self_insert_command("A-Esc")()
        delay(0.2)
        keymap.delayedCall(restoreWindow, 0)

    def previous_display():
        self_insert_command("W-S-Left")()

    def next_display():
        self_insert_command("W-S-Right")()

    def minimize_window():
        wnd = keymap.getTopLevelWindow()
        if wnd and not wnd.isMinimized():
            wnd.minimize()

    def restore_window():
        window_list = getWindowList()
        if not (sys.getwindowsversion().major == 6 and
                sys.getwindowsversion().minor == 1):
            window_list.reverse()
        for wnd in window_list:
            if wnd.isMinimized():
                wnd.restore()
                break

    ##################################################
    ## キーバインド(デスクトップ用)
    ##################################################

    # 表示しているウインドウの中で、一番最近までフォーカスがあったウインドウに移動
    define_key(keymap_global, other_window_key, reset_search(reset_undo(reset_counter(reset_mark(other_window)))))

    # アクティブウィンドウの切り替え
    if window_switching_key:
        for previous_key, next_key in 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)))))

    # アクティブウィンドウのディスプレイ間移動
    if window_movement_key:
        for previous_key, next_key in window_movement_key:
            define_key(keymap_global, previous_key, reset_search(reset_undo(reset_counter(reset_mark(previous_display)))))
            define_key(keymap_global, next_key,     reset_search(reset_undo(reset_counter(reset_mark(next_display)))))

    # ウィンドウの最小化、リストア
    if window_minimize_key:
        for restore_key, minimize_key in window_minimize_key:
            define_key(keymap_global, restore_key,  reset_search(reset_undo(reset_counter(reset_mark(restore_window)))))
            define_key(keymap_global, minimize_key, reset_search(reset_undo(reset_counter(reset_mark(minimize_window)))))

    # 仮想デスクトップの切り替え
    if desktop_switching_key:
        for previous_key, next_key in desktop_switching_key:
            define_key(keymap_global, previous_key, reset_search(reset_undo(reset_counter(reset_mark(previous_desktop)))))
            define_key(keymap_global, next_key,     reset_search(reset_undo(reset_counter(reset_mark(next_desktop)))))


    ####################################################################################################
    ## リストウィンドウの設定
    ####################################################################################################

    # リストウィンドウはクリップボードリストで利用していますが、クリップボードリストの機能を
    # emacsキーバインドを適用していないアプリケーションソフトでも利用できるようにするため、
    # クリップボードリストで Enter を押下した際の挙動を、以下のとおりに切り分けています。
    #
    # 1)emacsキーバインドを適用しているアプリケーションソフトからクリップボードリストを起動
    #   →   Enter(テキストの貼り付け)
    # 2)emacsキーバインドを適用していないアプリケーションソフトからクリップボードリストを起動
    #   → S-Enter(テキストをクリップボードに格納)
    #
    # (emacsキーバインドを適用しないアプリケーションソフトには、キーの入出力の方式が特殊な
    #  ものが多く指定されているため、テキストの貼り付けがうまく機能しないものがあります。
    #  このため、アプリケーションソフトにペーストする場合は、そのアプリケーションソフトの
    #  ペースト操作で行うことを前提とし、上記のとおりの仕様としてます。もし、どうしても
    #  Enter(テキストの貼り付け)の入力を行いたい場合には、C-m の押下により対応できます。
    #  なお、C-Enter(引用記号付で貼り付け)の置き換えは、対応が複雑となるため行っておりません。)

    keymap.setFont("MS ゴシック", 12)

    def is_list_window(window):
        if window.getClassName() == "KeyhacWindowClass" and window.getText() != "Keyhac":
            return True
        return False

    keymap_lw = keymap.defineWindowKeymap(check_func=is_list_window)

    # リストウィンドウで検索が開始されると True になる
    fakeymacs.lw_is_searching = False

    ##################################################
    ## 文字列検索 / 置換(リストウィンドウ用)
    ##################################################

    def lw_isearch(direction):
        if fakeymacs.lw_is_searching:
            self_insert_command({"backward":"Up", "forward":"Down"}[direction])()
        else:
            self_insert_command("f")()
            fakeymacs.lw_is_searching = True

    def lw_isearch_backward():
        lw_isearch("backward")

    def lw_isearch_forward():
        lw_isearch("forward")

    ##################################################
    ## その他(リストウィンドウ用)
    ##################################################

    def lw_keyboard_quit():
        self_insert_command("Esc")()

    ##################################################
    ## 共通関数(リストウィンドウ用)
    ##################################################

    def lw_newline():
        if fakeymacs.keybind == "emacs":
            self_insert_command("Enter")()
        else:
            self_insert_command("S-Enter")()

    def lw_exit_search(func):
        def _func():
            if fakeymacs.lw_is_searching:
                self_insert_command("Enter")()
            func()
        return _func

    def lw_reset_search(func):
        def _func():
            func()
            fakeymacs.lw_is_searching = False
        return _func

    ##################################################
    ## キーバインド(リストウィンドウ用)
    ##################################################

    ## Escキーの設定
    define_key(keymap_lw, "Esc",           lw_reset_search(self_insert_command("Esc")))
    define_key(keymap_lw, "C-OpenBracket", lw_reset_search(self_insert_command("Esc")))

    ## 「カーソル移動」のキー設定
    define_key(keymap_lw, "C-b", backward_char)
    define_key(keymap_lw, "A-b", backward_char)

    define_key(keymap_lw, "C-f", forward_char)
    define_key(keymap_lw, "A-f", forward_char)

    define_key(keymap_lw, "C-p", previous_line)
    define_key(keymap_lw, "A-p", previous_line)

    define_key(keymap_lw, "C-n", next_line)
    define_key(keymap_lw, "A-n", next_line)

    if scroll_key:
        define_key(keymap_lw, scroll_key[0].replace("M-", "A-"), scroll_up)
        define_key(keymap_lw, scroll_key[1].replace("M-", "A-"), scroll_down)

    ## 「カット / コピー / 削除 / アンドゥ」のキー設定
    define_key(keymap_lw, "C-h", delete_backward_char)
    define_key(keymap_lw, "A-h", delete_backward_char)

    define_key(keymap_lw, "C-d", delete_char)
    define_key(keymap_lw, "A-d", delete_char)

    ## 「文字列検索 / 置換」のキー設定
    define_key(keymap_lw, "C-r", lw_isearch_backward)
    define_key(keymap_lw, "A-r", lw_isearch_backward)

    define_key(keymap_lw, "C-s", lw_isearch_forward)
    define_key(keymap_lw, "A-s", lw_isearch_forward)

    ## 「その他」のキー設定
    define_key(keymap_lw, "Enter", lw_exit_search(lw_newline))
    define_key(keymap_lw, "C-m",   lw_exit_search(lw_newline))
    define_key(keymap_lw, "A-m",   lw_exit_search(lw_newline))

    define_key(keymap_lw, "C-g", lw_reset_search(lw_keyboard_quit))
    define_key(keymap_lw, "A-g", lw_reset_search(lw_keyboard_quit))

    define_key(keymap_lw, "S-Enter", lw_exit_search(self_insert_command("S-Enter")))
    define_key(keymap_lw, "C-Enter", lw_exit_search(self_insert_command("C-Enter")))
    define_key(keymap_lw, "A-Enter", lw_exit_search(self_insert_command("C-Enter")))


    ####################################################################################################
    ## クリップボードリストの設定
    ####################################################################################################
    if 1:
        # クリップボードリストを利用するための設定です。クリップボードリストは clipboardList_key 変数で
        # 設定したキーの押下により起動します。クリップボードリストを開いた後、C-f(→)や C-b(←)
        # キーを入力することで画面を切り替えることができます。
        # (参考:https://github.com/crftwr/keyhac/blob/master/_config.py)

        # リストウィンドウのフォーマッタを定義する
        list_formatter = "{:30}"

        # 定型文
        fixed_items = [
            ["---------+ x 8", "---------+" * 8],
            ["メールアドレス", "user_name@domain_name"],
            ["住所",           "〒999-9999 NNNNNNNNNN"],
            ["電話番号",       "99-999-9999"],
        ]
        fixed_items[0][0] = list_formatter.format(fixed_items[0][0])

        import datetime

        # 日時をペーストする機能
        def dateAndTime(fmt):
            def _func():
                return datetime.datetime.now().strftime(fmt)
            return _func

        # 日時
        datetime_items = [
            ["YYYY/MM/DD HH:MM:SS", dateAndTime("%Y/%m/%d %H:%M:%S")],
            ["YYYY/MM/DD",          dateAndTime("%Y/%m/%d")],
            ["HH:MM:SS",            dateAndTime("%H:%M:%S")],
            ["YYYYMMDD_HHMMSS",     dateAndTime("%Y%m%d_%H%M%S")],
            ["YYYYMMDD",            dateAndTime("%Y%m%d")],
            ["HHMMSS",              dateAndTime("%H%M%S")],
        ]
        datetime_items[0][0] = list_formatter.format(datetime_items[0][0])

        keymap.cblisters += [
            ["定型文",  cblister_FixedPhrase(fixed_items)],
            ["日時",    cblister_FixedPhrase(datetime_items)],
        ]

        def lw_clipboardList():
            keymap.command_ClipboardList()

        # クリップボードリストを起動する
        define_key(keymap_global, clipboardList_key, lw_reset_search(reset_search(reset_undo(reset_counter(reset_mark(lw_clipboardList))))))


    ####################################################################################################
    ## ランチャーリストの設定
    ####################################################################################################
    if 1:
        # ランチャー用のリストを利用するための設定です。ランチャーリストは lancherList_key 変数で
        # 設定したキーの押下により起動します。ランチャーリストを開いた後、C-f(→)や C-b(←)
        # キーを入力することで画面を切り替えることができます。
        # (参考:https://github.com/crftwr/keyhac/blob/master/_config.py)

        def lw_lancherList():
            def popLancherList():

                # リストウィンドウのフォーマッタを定義する
                list_formatter = "{:30}"

                # 既にリストが開いていたら閉じるだけ
                if keymap.isListWindowOpened():
                    keymap.cancelListWindow()
                    return

                # ウィンドウ
                window_list = getWindowList()
                window_items = []
                if window_list:
                    processName_length = max(map(len, map(Window.getProcessName, window_list)))

                    formatter = "{0:" + str(processName_length) + "} | {1}"
                    for wnd in window_list:
                        window_items.append((formatter.format(wnd.getProcessName(), wnd.getText()), popWindow(wnd)))

                window_items.append((list_formatter.format("<Desktop>"), keymap.ShellExecuteCommand(None, r"shell:::{3080F90D-D7AD-11D9-BD98-0000947B0257}", "", "")))

                # アプリケーションソフト
                application_items = [
                    ["notepad",     keymap.ShellExecuteCommand(None, r"notepad.exe", "", "")],
                    ["sakura",      keymap.ShellExecuteCommand(None, r"C:\Program Files (x86)\sakura\sakura.exe", "", "")],
                    ["explorer",    keymap.ShellExecuteCommand(None, r"explorer.exe", "", "")],
                    ["cmd",         keymap.ShellExecuteCommand(None, r"cmd.exe", "", "")],
                    ["chrome",      keymap.ShellExecuteCommand(None, r"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe", "", "")],
                    ["firefox",     keymap.ShellExecuteCommand(None, r"C:\Program Files (x86)\Mozilla Firefox\firefox.exe", "", "")],
                    ["thunderbird", keymap.ShellExecuteCommand(None, r"C:\Program Files (x86)\Mozilla Thunderbird\thunderbird.exe", "", "")],
                ]
                application_items[0][0] = list_formatter.format(application_items[0][0])

                # ウェブサイト
                website_items = [
                    ["Google",          keymap.ShellExecuteCommand(None, r"https://www.google.co.jp/", "", "")],
                    ["Facebook",        keymap.ShellExecuteCommand(None, r"https://www.facebook.com/", "", "")],
                    ["Twitter",         keymap.ShellExecuteCommand(None, r"https://twitter.com/", "", "")],
                    ["Keyhac",          keymap.ShellExecuteCommand(None, r"https://sites.google.com/site/craftware/keyhac-ja", "", "")],
                    ["NTEmacs@ウィキ", keymap.ShellExecuteCommand(None, r"http://www49.atwiki.jp/ntemacs/", "", "")],
                ]
                website_items[0][0] = list_formatter.format(website_items[0][0])

                # その他
                other_items = [
                    ["Edit   config.py", keymap.command_EditConfig],
                    ["Reload config.py", keymap.command_ReloadConfig],
                ]
                other_items[0][0] = list_formatter.format(other_items[0][0])

                listers = [
                    ["Window",  cblister_FixedPhrase(window_items)],
                    ["App",     cblister_FixedPhrase(application_items)],
                    ["Website", cblister_FixedPhrase(website_items)],
                    ["Other",   cblister_FixedPhrase(other_items)],
                ]

                try:
                    select_item = keymap.popListWindow(listers)

                    if not select_item:
                        Window.find("Progman", None).setForeground()
                        select_item = keymap.popListWindow(listers)

                    if select_item and select_item[0] and select_item[0][1]:
                        select_item[0][1]()
                except:
                    print("エラーが発生しました")

            # キーフックの中で時間のかかる処理を実行できないので、delayedCall() を使って遅延実行する
            keymap.delayedCall(popLancherList, 0)

        # ランチャーリストを起動する
        define_key(keymap_global, lancherList_key, lw_reset_search(reset_search(reset_undo(reset_counter(reset_mark(lw_lancherList))))))


    ####################################################################################################
    ## Excel の場合、C-Enter に F2(セル編集モード移行)を割り当てる(オプション)
    ####################################################################################################
    if 0:
        keymap_excel = keymap.defineWindowKeymap(class_name="EXCEL*")

        # C-Enter 押下で、「セル編集モード」に移行する
        define_key(keymap_excel, "C-Enter", reset_search(reset_undo(reset_counter(reset_mark(self_insert_command("F2"))))))


    ####################################################################################################
    ## Emacs の場合、IME 切り替え用のキーを C-\ に置き換える(オプション)
    ####################################################################################################
    if 0:
        # NTEmacs の利用時に Windows の IME の切換えを無効とするための設定です。(mozc.el を利用する場合など)
        # 追加したいキーがある場合は、次の方法で追加するキーの名称もしくはコードを確認し、
        # スクリプトを修正してください。
        #  1) タスクバーにある Keyhac のアイコンを左クリックしてコンソールを開く。
        #  2) アイコンを右クリックしてメニューを開き、「内部ログ ON」を選択する。
        #  3) 確認したいキーを押す。

        keymap_real_emacs = keymap.defineWindowKeymap(class_name="Emacs")

        # IME 切り替え用のキーを C-\ に置き換える
        keymap_real_emacs["(28)"]   = keymap.InputKeyCommand("C-Yen") # [変換] キー
        keymap_real_emacs["(29)"]   = keymap.InputKeyCommand("C-Yen") # [無変換] キー
        keymap_real_emacs["(240)"]  = keymap.InputKeyCommand("C-Yen") # [英数] キー
        keymap_real_emacs["(242)"]  = keymap.InputKeyCommand("C-Yen") # [カタカナ・ひらがな] キー
        keymap_real_emacs["(243)"]  = keymap.InputKeyCommand("C-Yen") # [半角/全角] キー
        keymap_real_emacs["(244)"]  = keymap.InputKeyCommand("C-Yen") # [半角/全角] キー
        keymap_real_emacs["A-(25)"] = keymap.InputKeyCommand("C-Yen") # Alt-` キー

最後に、CapsLockキー への Ctrlキー の割当ては、次の URL にある KeySwap というソフトが便利です。
http://www.vector.co.jp/soft/winnt/util/se228667.html

side_of_ctrl_key 変数を "R"(右)とし、CapsLockキーに RCtrlキーを割り当てることで、LCtrlキーで利用可能な Windowsショートカットキーとの共存が容易になると思います。(RCtrlキーも Windowsショートカット用のキーとして使いたい場合は、RCtrlキーに LCtrlキーを割り当てる必要があります。)

また、Altキーは親指で操作できる場所にキーを割り当てると使い勝手が良いように思います。


<変更履歴>
  • 2012/11/02 C-o をIMEの切替の設定とした。
  • 2012/11/02 C-k を C-u と連携可能とした。
  • 2012/11/05 C-u の対応を強化した。
  • 2012/11/06 マークの方法を見直した。
  • 2012/11/26 キーボードマクロに対応した。
  • 2012/11/30 Eclipse の ClassName が間違っていたのを訂正した。( SWT_Windows0 -> SWT_Window0 )
  • 2013/07/20 keyhac ver 1.60(Python3系)でも動くスクリプトに修正した。
  • 2013/07/25 C-x o ( other_window : 一つ前にフォーカスがあったウインドウに移動する)が正常に機能するように対策した。
  • 2013/07/28 無効とするアプリケーションソフトに xyzzy を追加した。
  • 2013/07/28 input method の切り替えだけができる設定の仕組みを追加した。
  • 2013/08/19 キーバインドを設定するアプリケーションソフトの指定方法にプロセス名も使えるように設定を追加した。
  • 2013/08/19 Sakura Editor のみ C-l に対応した。
  • 2014/04/22 除外するアプリケーションソフトの指定方法等を processname で指定する方法にまとめた。
  • 2014/06/02 前置引数付きで行削除した場合の動作に不具合があったので修正した。また、数点の改善を行った。
  • 2014/09/17 repeat関数内にreset関数のコードとダブる部分があったので改善した。(機能の変更はない)
  • 2014/09/30 「emacs で指定したファイルを eclipse で開くための設定」と連携するため、eclipse.exe の除外設定を解除(コメント化)した。
  • 2014/10/07 ワードを操作するコマンドを追加した。
  • 2014/10/14 キーボードマクロの実行処理に不具合(デグレード)が発生していたので修正した。
  • 2014/10/15 左の Ctrlキー と Altキー のみを emacs用のキー として使う様にし、左のキーは Windows のショートカットキー用として使えるようにした。
  • 2014/10/15 仮想キーコードの指定方法を10進から16進に変更し、一部指定コードの見直しを行った。
  • 2014/10/07 検索の繰り返し機能をサポートした。
  • 2014/10/18 数引数による数字の繰り返し入力をサポートした。"C-u 数字 C-u 数字" で対応可能。
  • 2014/10/18 キーボードマクロの記録後の C-x 削除処理に改善点があったので修正した。
  • 2014/10/18 IME 切替時に現在の IME の状態を balloonヘルプ で表示するようにした。
  • 2014/10/19 quoted-insertコマンド(C-q)で利用可能なキーに Ctrl-Shift-<*>キー と Alt-Shift-<*>キー を追加した。
  • 2014/10/19 数引数の指定に Ctrl と Meta を利用できるようにした。
  • 2014/10/21 キーボードマクロ実行時は、IME の状態表示バールーンを表示しないようにした。
  • 2014/10/30 スクリプトのコメントを追記した。機能に変更はありません。
  • 2014/11/24 Emacs 利用時に角/全角」(日本語キーボード用)と Alt-`(英語キーボード用)を C-\ に置き換える設定(オプション)を追加した。
  • 2014/11/26 「半角/全角」(日本語キーボード用)と Alt-`(英語キーボード用)押下時に toggle_input_method 関数をコールするようにした。
  • 2014/12/03 Emacs 利用時に C-\ に置き換えるキーを追加した。(但し、「if 0」でデフォルト無効とした。)また、普段英語キーボードを使っているため確認が甘かった部分を、日本語キーボードを接続して確認・調整した。
  • 2014/12/05 日本語キーボードで C-o による IME の切り替えを素早く2回行おうとした際、「ファイルを開く..」のダイアログが開くことがあったのでこれを改善した。
  • 2015/01/21 「「IMEの切替え」のキー設定」の箇所の keymap_im の設定で、「(244)」のキーの設定が漏れていたのを追加した。
  • 2015/01/22 IME 切替時の balloonヘルプ の表示で、半角英数直接入力の表示内容を「[_A]」から「[A]」に変更した。
  • 2015/02/23 日本語キーボード用に Ctrl+@ の対応を行った。
  • 2015/02/26 mark_whole_buffer() と mark_page() を Excel 以外の時は C-Home -> C-a として機能するように変更した。
  • 2015/03/11 Excel については個別に検索の繰り返しをサポートした。
  • 2015/03/12 kill_ring_save を実行した際、Excel 以外では ESC も発行していたが、これを Sakura Editor の時のみに限定した。
  • 2015/07/04 Emacs のキー設定(オプション)に「英数キー」を追加した。
  • 2015/07/05 「C-k, A-d, C-BSなど範囲選択後に切り取りをするスクリプトのタイミング依存の問題」について対策した。
  • 2015/07/17 backward_kill_word、kill_word、kill_line コマンドの repeat の指定方法を変更した。
  • 2015/07/23 2015/07/17 の修正においてデグレ(Microsoft Word で kill_line を利用した際の不具合)が発生していた。これを修正した。
  • 2015/09/18 LC-Underscore が正常に機能していなかったので対策した。併せて、日本語キーボードか英語キーボードかの指定方法を変更した。(スクリプトの最初の方にある is_japanese_keybord という変数の設定で切り替えるように対応した。)
  • 2015/09/18 LC-Atmark の指定方法を変更した。
  • 2015/10/11 C-[a-z]キーを Shiftキーと一緒に押した時は、Shiftキーをとったキー(C-[a-z])が Windows に入力される設定を追加した。
  • 2015/10/20 キーボードマクロの繰り返し実行(C-u を付けての実行)にバグがあったので対策した。
  • 2015/10/31 クリップボードリストでの検索機能を実装した。
  • 2015/11/01 クリップボードリストでの検索機能の実装を改善した。
  • 2015/11/02 クリップボードリストを拡張する設定の説明を追加した。
  • 2015/11/04 クリップボードリストとは別に、LA-l で起動するランチャーリストを作成した。
  • 2015/11/04 コードの一部リファクタリングを行った。
  • 2015/11/06 クリップボードリストとランチャーリストの項目の横幅を決めるダミー行の設定方法を変更した。
  • 2015/11/09 redo をサポートしてみた。
  • 2015/11/15 other_window(C-x o)が Windows8 以降の OS で動かなかったのを対策した。
  • 2015/11/15 クリップボードリストの機能を emacs キーバインドを適用していないアプリケーションソフトでも利用できるようにする機能を追加した。
  • 2015/11/15 ランチャーリストに現在開いているウィンドウを選択する機能を追加した。
  • 2015/11/15 リファクタリングを実施した。また、設定を一つに固め、設定を取り込みやすくした。
  • 2015/11/17 ランチャーリストの設定にある getWindowList 関数にて、ランチャーリストに載せたくないアプリケーションソフトを正規表現で指定できるようにした。
  • 2015/11/19 other_window と popWindow 関数で、setForeground 関数を呼ぶ前に getLastActivePopup 関数を呼ぶようにした。
  • 2015/11/20 ランチャーリストの Window リストにデスクトップを表示するための項目を追加した。また、ランチャーリストでフォーカスのあるウィンドウがなくなった際のエラー対策を追加した。
  • 2015/11/20 switch_to_buffer(C-x b)と query_replace(M-%)をサポートした。
  • 2015/11/21 shell_command(M-!)をサポートした。
  • 2015/11/22 keymap.command_ShellExecute 関数の第二引数を raw文字列での指定方法に統一して変更した。
  • 2015/11/27 ランチャーリストのウィンドウリストの表示にフォーマッターを噛ませた。
  • 2015/11/28 ランチャーリストのウィンドウリストの表示用に適用したフォーマッターの改善を行った。
  • 2015/11/29 ウィンドウリストの表示改善に不具合があったので対策した。
  • 2015/12/07 ランチャーリストによるアプリケーションソフト切替え時に、諸々の変数を初期化するようにした。
  • 2015/12/09 リストウィンドウで検索を行い、選択した行を確定したい場合、一回の Enter で済むように対応した。
  • 2015/12/10 OS を Windows 10 にしたところ、クリップボードリストのフォントが乱れた表示となったので対応した。
  • 2015/12/11 OS を Windows 10 にしたところ、ウィンドウリストに表示される不要と思われるアプリケーションソフトが増えていたので、多少の改善を行った。
  • 2015/12/15 ランチャーリストのウィンドウリストに既に存在しないウィンドウの行が存在する場合、その行を選択してもエラーとならないように対策した。
  • 2015/12/15 仮想デスクトップの切り替えるためのキーとして、LA-p と LA-n を割り当てた。(Windows 10 用)
  • 2015/12/15 ランチャーリストの <Desktop> の機能と仮想デスクトップの切り替えを交互に利用した際などにエラーが発生することがあるため、その対策を行った。
  • 2015/12/17 クリップボードリストやランチャーリストのリストウィンドウ内のみの対応として、基本、Altキーを Ctrlキーと同じキーとして扱うように対応した。
  • 2015/12/17 テスクトップ内のウィンドウを切り替えるためのキーとして、LA-S-p と LA-S-n を割り当てた。
  • 2015/12/18 use_virtual_desktop 変数を追加し、仮想デスクトップを切り替えるキー設定をするかどうかを指定できるようにした。
  • 2015/12/23 クリップボードリストを起動するためのキーとして、LC-x C-y と LA-y を登録していたが、LC-x C-y の設定を廃止とした。
  • 2015/12/23 use_virtual_desktop 変数の初期設定値を False(仮想デスクトップを切り替えるキー設定を“しない”)に変更した。
  • 2015/12/24 仮想デスクトップを利用する場合のキー設定を選択するための virtual_desktop_mode 変数を追加した。
  • 2015/12/28 keyhac のバージョン 1.70 に対応し、一部関数名の変更を行った。
  • 2015/12/31 restore_window 関数がエラーとなる場合があったので、対策した。
  • 2015/12/31 command_ShellExecute も廃止予定の関数となっていたので、ShellExecuteCommand に関数名を変更した。
  • 2016/01/04 use_virtual_desktop 変数とvirtual_desktop_mode 変数を廃止し、desktop_switching_key 変数と window_switching_key 変数で切り替えキーを直接指定できるようにした。
  • 2016/01/04 keyhac が ver 1.70 になり、k が大文字の Keyhac となった。アプリケーションソフトのクラス名等も変更となっていたため、スクリプトが正常に動作していなかった箇所があり、その対策を行った。
  • 2016/01/08 Windows 10 を利用していると、ランチャーリストのウィンドウリストに直接は起動していない、プロセス名が ApplicationFrameHost.exe でタイトル名が「設定」、「ストア」もしくは「フォト」というウィンドウが表示される。これを表示されないように対策した。
  • 2016/02/19 query_replace 関数内で、Sakura Editor と Hidemaru Editor は C-h ではなく C-r を発行するように対応した。
  • 2016/02/20 秀丸で、行末での C-k による行削除に対応した。
  • 2016/03/22 マルチディスプレイを利用している際に、表示しているウィンドウをディスプレイ間で移動するためのキーを window_movement_key 変数で指定できるようにした。
  • 2016/03/23 other_window 関数に A-o キーを設定した。
  • 2016/03/28 ウィンドウ操作関数での動作に統一性を持たせるため、操作対象とするウィンドウのリストを getWindowList 関数で生成し、そのウィンドウリストに対して操作するように処理を変更した。
  • 2016/04/24 アクティブウィンドウの最小化、最小化されているウィンドウのリストアのキーを window_minimize_key 変数で指定するようにした。
  • 2016/04/05 新たにother_window_key 変数、clipboardList_key 変数、lancherList_key 変数を導入し、設定の汎用化を行った。
  • 2016/04/07 仮想デスクトップでの利用を踏まえ、ウィンドウの最小化を現在のデスクトップ内に表示しているウィンドウに対してのみ行われるように変更した。
  • 2016/04/14 window_switching_key 変数と window_movement_key 変数に割り当てているキーを変更した。
  • 2016/04/18 リストウィンドウのフォーマット(リスト幅の指定)の方法を変更した。
  • 2016/04/25 use_esc_as_meta 変数により、Escキーを Metaキーとして使うかどうかを指定できるようにした。
  • 2016/04/28 Ctrl-x を Windows のショートカット(cut)として利用する選択肢を持たせるため、emacs の Ctl-xプレフィックスキーに使うキーを ctl_x_prefix_key 変数で指定できるようにした。
  • 2016/04/29 アクティブウィンドウを切り替えるキーを指定する window_switching_key 変数の初期値を変更した。
  • 2016/05/03 Ctrl-v を Windows のショートカット(paste)として利用する選択肢を持たせるため、スクロールキーに使うキーを scroll_key 変数で指定できるようにした。
  • 2016/05/07 左右どちらの Ctrlキーや Altキーを使うかを side_of_ctrl_key 変数と side_of_alt_key 変数で指定できるようにした。
  • 2016/05/08 A-[a-z]キーを Shiftキーと一緒に押した時は、Shiftキーをとったキー(A-[a-z])が Windows に入力される設定を追加した。
  • 2016/05/15 toggle_input_method_key 変数の設定により、IME を切り替えるキーを指定できるようにした。
  • 2016/05/18 use_emacs_ime_mode 変数の設定により、emacs日本語入力モードを使うかどうかを指定できるようにした。また、C-S-[a-z] -> C-[a-z]、A-S-[a-z] -> A-[a-z] の置き換えの機能(emacsシフトモード)を使うかどうかを use_emacs_shift_mode 変数で指定できるようにした。
  • 2016/05/18 emacs日本語入力モードが起動している状況で C-g を押下した場合は、Esc を2回発行してから emacs日本語入力モードを抜けるようにした。
  • 2016/05/19 toggle_emacs_ime_mode_key 変数の設定により、明示的に emacs日本語入力モードを切り替える(トグルする)キーを指定でできるようにした。
  • 2016/05/22 フォーカスウィンドウが切り替わった際、emacs日本語入力モードが OFF となるように調整した。
  • 2016/05/24 emacs日本語入力モードの時に漢字キーを押した時、emacs日本語入力モードを終了してから IME を OFF とするように調整した。
  • 2016/05/25 emacs日本語入力モードの時の誤動作を少なくするため、マウスクリック時に emacs日本語入力モードが OFF となるように調整した。
  • 2016/05/26 カーソルキー(←、→、↑、↓)が、C-b、C-f、C-p、C-n と同じ振る舞いとなるように設定した。
  • 2016/05/27 use_ctrl_i_as_tab 変数の設定により、C-iキーを Tabキーとして使うかどうかを指定できるようにした。
  • 2016/05/31 emacs日本語入力モードの時、常に「I」の文字(Input の頭文字)がポップアップするようにし、emacs日本語入力モードの状態が分かるように対応した。
  • 2016/06/01 Evernote で C-g を押下した際、Esc を発行しないようにした。
  • 2016/06/03 emacs日本語入力モードの時に C-a、C-e、C-d そして scroll_key 変数で指定したスクロールキーも利用できるようにした。
  • 2016/06/04 emacs日本語入力モードの使用を有効にした際、emacs_ime_mode_balloon_message 変数の設定でバルーンメッセージとして表示する文字列を指定できるようにした。
  • 2016/06/04 emacs_ime_mode_balloon_message 変数の初期値を「▲」に変更した。
  • 2016/06/04 is_ime_target 関数で指定した IME の切り替えのみをしたいアプリケーションソフトでも、emacs日本語入力モードと emacsシフトモードが動作するように設定した。
  • 2016/06/09 Windows 10 の Internet Explorer で本設定が正常に動作していなかったのを改善した。
  • 2016/06/09 emacs の挙動とは異なるようですが、ヤンク(C-y)の数引数による繰り返しをサポートした。
  • 2016/06/17 「Excel の場合、C-Enter に F2(セル編集モード移行)を割り当てる(オプション)」の機能を初期値では"無効"とした。
  • 2016/06/27 mark の際のカーソルの動きが遅いなどの問題があったので、delay の入れ方を全面的に見直した。
  • 2016/07/28 emacs日本語入力モードを使っている際に、文字が重なって入力されることがあったので、その対策を行った。
  • 2016/08/05 IMEツールバーにより入力モードの切り替えが行われた際、emacs日本語入力モードの切替えが適切に行われていなかったので、その対策を行った。
  • 2016/09/23 scroll_key 変数が None の場合、C-v に yank の設定を行うように調整した。
  • 2016/10/27 変数の管理方法を変更した。
  • 2016/11/04 ウィンドウの判定に関する3点の改善を行いました。
  • 2016/11/14 Keyhac for Windows が ver 1.75 になり、keymap.updateKeymap() がサポートされたので設定を見直した。
  • 2016/11/16 新しめのバージョンの Excel を使っているとクリップボードに関連する競合エラーが発生するので、その対策を行った。