forked from takashisite/keyhac-config
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconfig.py
1611 lines (1319 loc) · 77.4 KB
/
config.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# -*- mode: python; coding: utf-8-with-signature-dos -*-
## nickname: fakeymacs config
##
## Windows の操作を emacs のキーバインドで行うための設定(Keyhac版)ver.20170317_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
from keyhac import *
def configure(keymap):
####################################################################################################
## カスタマイズの設定
####################################################################################################
# emacs のキーバインドに"したくない"アプリケーションソフトを指定する
# (Keyhac のメニューから「内部ログ」を ON にすると processname や classname を確認することができます。)
not_emacs_target = ["cmd.exe", # cmd
"bash.exe", # bash
"mintty.exe", # mintty
"emacs.exe", # Emacs
"emacs-w32.exe", # Emacs
"gvim.exe", # GVim
# "eclipse.exe", # Eclipse
# "firefox.exe", # firefox
"idea64.exe",
"Divvy.exe",
"Cmder.exe",
"ConEmu64.exe",
"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
"idea64.exe",
"Cmder.exe",
"ConEmu64.exe",
"xyzzy.exe", # xyzzy
"putty.exe", # PuTTY
"ttermpro.exe", # TeraTerm
"MobaXterm.exe"] # MobaXterm
# 日本語キーボードかどうかを指定する(True: 日本語キーボード、False: 英語キーボード)
is_japanese_keyboard = False
# 左右どちらの 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 = "A-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-Quote"]
# C-iキーを Tabキーとして使うかどうかを指定する(True: 使う、False: 使わない)
use_ctrl_i_as_tab = True
# Escキーを Metaキーとして使うかどうかを指定する(True: 使う、False: 使わない)
use_esc_as_meta = False
# Ctl-xプレフィックスキーに使うキーを指定する
# (Ctl-xプレフィックスキーのモディファイアキーは、Ctrl または Alt のいずれかから指定してください)
ctl_x_prefix_key = "C-x"
# スクロールに使うキーの組み合わせ(Up、Down の順)を指定する
# scroll_key = None # PageUp、PageDownキーのみを利用する
scroll_key = None
# 表示しているウインドウの中で、一番最近までフォーカスがあったウインドウに移動するキーを指定する
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"]] # 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://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()