ほかのキーと同じように再アサインできない’M’キー

ファイラーとして、2画面キーボードファイラーの内骨格を愛用しているのですが、Mキーの再アサインがver. 2.45現在、ほかのキーと同じように再アサインしようとしても、できない状態になっています(私の環境ではファイル非選択状態だとデフォルト動作が、選択状態だと設定変更した動作になりました)。(Githubにはイシューをあげました。)

# config.py (正常動作しない)
def configure(window):
    window.keymap["M"]=window.command_JumpList

Mキーの再アサインをする

結論を先に書くと、以下のようなコードを追記すれば通常の再アサインが可能になります

# config.py
import ckit
from ckit.ckit_const import *

def configure(window):
    original_delitem = ckit.Keymap.__delitem__
    def monkeypatch_delitem(self, expression):
        if isinstance(expression, str):
            original_delitem(self, expression)
        else:
            del self.table[expression]
    ckit.Keymap.__delitem__=monkeypatch_delitem

    del window.keymap[ckit.KeyEvent(ord('M'),0,extra=0)]
    del window.keymap[ckit.KeyEvent(ord('M'),0,extra=1)]
    del window.keymap[ckit.KeyEvent(ord('M'),MODKEY_SHIFT,extra=1)] # S-Mも変えたい場合は必要
    
    window.keymap["M"]=window.command_JumpList # 好きなコマンドに差し替え

なぜ? (細かい話)

Mキーは、デフォルトではファイル未選択状態ではディレクトリ作成、選択状態では移動と、状態により異なる操作が割り当てられています。この割り当てのためにほかのキーと異なるキーアサインをされているようです。具体的には、window.keymapに対してMキー以外は文字列をキーに、ファンクションを値に設定しているのですが、Mキーだけはckit.KeyEventオブジェクトをキーとしています。そのため、config.pyにて文字列”M”をキーに設定を上書きしようとしてもデフォルト設定が残ってしまい、予期した動作にならないようです。そのため、事前にKeyEventのがキーとなっているエントリを削除しているのが、del window.keymap の部分です。

しかしckit.Keymapの実装で、del時の同値性比較に入力を文字列と仮定して必ずstrからKeyEventオブジェクトへの変換をしてしまっています。なので、delをそのまま実行すると、以下のようなエラーがでてしまいます。

ERROR : 設定ファイルの実行中にエラーが発生しました.
Traceback (most recent call last):
  File "../ckit\ckit_userconfig.py", line 42, in callConfigFunc
  File "config.py", line 65, in configure
  File "../ckit\ckit_key.py", line 439, in \_\_delitem\_\_
  File "../ckit\ckit_key.py", line 338, in fromString
AttributeError: 'KeyEvent' object has no attribute 'upper'

これを回避するため、ckit.Keymap.__delitem__メソッドにモンキーパッチを当てて、str以外の場合はわたってきた型のまま、delを行うようにしています。