forked from smzht/fakeymacs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconfig.py
executable file
·3155 lines (2575 loc) · 148 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 -*-
#########################################################################
## Fakeymacs
#########################################################################
## Windows の操作を Emacs のキーバインドで行うための設定(Keyhac版)
#########################################################################
fakeymacs_version = "20230907_03"
import time
import os.path
import re
import fnmatch
import copy
import datetime
import ctypes
import pyauto
import winreg
import itertools
import keyhac_keymap
from keyhac import *
def configure(keymap):
####################################################################################################
## 初期設定
####################################################################################################
keymap.editor = r"notepad.exe"
keymap.setFont("MS ゴシック", 12)
# カスタマイズパラメータを格納するクラスを定義する
class FakeymacsConfig:
pass
fc = fakeymacs_config = FakeymacsConfig()
# Fakeymacs を制御する変数を格納するクラスを定義する
class Fakeymacs:
pass
fakeymacs = Fakeymacs()
# OS に設定しているキーボードタイプの設定を行う
# (http://tokovalue.jp/function/GetKeyboardType.htm)
if ctypes.windll.user32.GetKeyboardType(0) == 7:
os_keyboard_type = "JP"
else:
os_keyboard_type = "US"
# 個人設定ファイルを読み込む
try:
with open(rf"{dataPath()}\config_personal.py", "r", encoding="utf-8-sig") as f:
config_personal = f.read()
except:
print("個人設定ファイル config_personal.py は存在しないため、読み込みしていません")
config_personal = ""
def readConfigPersonal(section):
if config_personal:
# https://www.zu-min.com/archives/614
m = re.search(rf"(#\s{re.escape(section)}.*?)(#\s\[section-|\Z)", config_personal,
flags=re.DOTALL)
try:
config_section = m.group(1)
config_section = re.sub(r"^##.*", r"", config_section, flags=re.MULTILINE)
except:
print(f"個人設定ファイルのセクション {section} の読み込みに失敗しました")
config_section = ""
else:
config_section = ""
return config_section
def readConfigExtension(config_file, msg=True):
try:
with open(rf"{dataPath()}\fakeymacs_extensions\{config_file}", "r", encoding="utf-8-sig") as f:
config_extension = f.read()
except:
if msg:
print(f"拡張機能ファイル {config_file} の読み込みに失敗しました")
config_extension = ""
return config_extension
def startupString():
startup_string_formatter = "Fakeymacs version {}:\n https://github.com/smzht/fakeymacs\n"
return startup_string_formatter.format(fakeymacs_version)
# 個人設定ファイルのセクション [section-init] を読み込んで実行する
exec(readConfigPersonal("[section-init]"), dict(globals(), **locals()))
####################################################################################################
## 機能オプションの選択
####################################################################################################
# IMEの設定(次の設定のいずれかを有効にする)
# fc.ime = "old_Microsoft_IME"
fc.ime = "new_Microsoft_IME"
# fc.ime = "Google_IME"
# fc.ime = None
# 日本語キーボード設定をした OS 上で英語キーボードを利用するかどうかを指定する
# (True: 使う、False: 使わない)
# (False に設定した場合でも、OS の設定が日本語キーボードになっていれば、ランチャーメニュー
# の一番最後に表示されるメニューからキーボード種別を切り替えることができます)
fc.use_usjis_keyboard_conversion = False
# IME の状態をテキスト カーソル インジケーターの色で表現するかどうかを指定する
# (True: 表現する、False: 表現しない)
# (テキスト カーソル インジケーターを利用するには、次のページを参考とし設定を行ってください
# https://faq.nec-lavie.jp/qasearch/1007/app/servlet/relatedqa?QID=022081)
fc.use_ime_status_cursor_color = False
# IME が ON のときのテキスト カーソル インジケーターの色を指定する
fc.ime_on_cursor_color = 0x00C800 # 濃い緑
# IME が OFF のときのテキスト カーソル インジケーターの色を指定する
fc.ime_off_cursor_color = 0x0000FF # 赤
# Chromium 系ブラウザで発生する問題の対策を行うかどうかを指定する(True: 対策する、False: 対策しない)
# (Chromium 系ブラウザのバージョン 92 では、アドレスバーにカーソルを移動した際、強制的に ASCII入力
# モードに移行する不具合が発生します。(バージョン 93 で対策済みですが、過去にも度々発生しています。)
# ・https://did2memo.net/2021/07/22/chrome-japanese-ime-off-issue-chrome-92/
# さらに Google 日本語入力を利用している場合、keymap.getWindow().getImeStatus() が True を返すため、
# Emacs 日本語入力モードの挙動がおかしくなります。この対策を行うかどうかを指定します。)
fc.correct_ime_status = False
# 上記の対策を行う Chromium 系ブラウザのプログラム名称を指定する
fc.chromium_browser_list = ["chrome.exe",
"msedge.exe",
]
# 個人設定ファイルのセクション [section-options] を読み込んで実行する
exec(readConfigPersonal("[section-options]"), dict(globals(), **locals()))
####################################################################################################
## 基本設定
####################################################################################################
###########################################################################
## キーボード関連変数の設定
###########################################################################
if os_keyboard_type == "JP":
try:
if keymap.fakeymacs_keyboard == "JP":
is_japanese_keyboard = True
use_usjis_keyboard_conversion = False
else:
is_japanese_keyboard = False
use_usjis_keyboard_conversion = True
except:
if fc.use_usjis_keyboard_conversion:
is_japanese_keyboard = False
use_usjis_keyboard_conversion = True
else:
is_japanese_keyboard = True
use_usjis_keyboard_conversion = False
else:
is_japanese_keyboard = False
use_usjis_keyboard_conversion = False
###########################################################################
## カスタマイズパラメータの設定
###########################################################################
# すべてのキーマップを透過(スルー)するアプリケーションソフトを指定する(全ての設定に優先する)
# (keymap_base、keymap_global を含むすべてのキーマップをスルーします)
fc.transparent_target = []
# すべてのキーマップを透過(スルー)するウィンドウのクラスネームを指定する(全ての設定に優先する)
# (keymap_base、keymap_global を含むすべてのキーマップをスルーします)
fc.transparent_target_class = ["IHWindowClass"] # Remote Desktop
# Emacs のキーバインドにするウィンドウのクラスネームを指定する(fc.not_emacs_target の設定より優先する)
fc.emacs_target_class = ["Edit", # テキスト入力フィールドなどが該当
"Button", # ボタン
"ComboBox", # コンボボックス
"ListBox", # リストボックス
]
# Emacs のキーバインドに“したくない”アプリケーションソフトを指定する
# (Keyhac のメニューから「内部ログ」を ON にすると processname や classname を確認することができます)
fc.not_emacs_target = ["wsl.exe", # WSL
"bash.exe", # WSL
"ubuntu.exe", # WSL
"ubuntu1604.exe", # WSL
"ubuntu1804.exe", # WSL
"ubuntu2004.exe", # WSL
"ubuntu2204.exe", # WSL
"debian.exe", # WSL
"kali.exe", # WSL
"SLES-12.exe", # WSL
"openSUSE-42.exe", # WSL
"openSUSE-Leap-15-1.exe", # WSL
"WindowsTerminal.exe", # Windows Terminal
"mintty.exe", # mintty
"Cmder.exe", # Cmder
"ConEmu.exe", # ConEmu
"ConEmu64.exe", # ConEmu
"emacs.exe", # Emacs
"emacs-X11.exe", # Emacs
"emacs-w32.exe", # Emacs
"gvim.exe", # GVim
"xyzzy.exe", # xyzzy
"msrdc.exe", # WSLg
"XWin.exe", # Cygwin/X
"XWin_MobaX.exe", # MobaXterm/X
"XWin_MobaX_1.16.3.exe", # MobaXterm/X
"XWin_MobaX_1.20.4.exe", # MobaXterm/X
"XWin_Cygwin_1.14.5.exe", # MobaXterm/X
"XWin_Cygwin_1.16.3.exe", # MobaXterm/X
"Xming.exe", # Xming
"vcxsrv.exe", # VcXsrv
"GWSL_vcxsrv.exe", # GWSL
"GWSL_vcxsrv_lowdpi.exe", # GWSL
"X410.exe", # X410
"Xpra-Launcher.exe", # Xpra
"putty.exe", # PuTTY
"ttermpro.exe", # TeraTerm
"MobaXterm.exe", # MobaXterm
"TurboVNC.exe", # TurboVNC
"vncviewer.exe", # UltraVNC
"vncviewer64.exe", # UltraVNC
]
# IME の切り替え“のみをしたい”アプリケーションソフトを指定する
# (指定できるアプリケーションソフトは、not_emacs_target で(除外)指定したものからのみとなります)
fc.ime_target = ["wsl.exe", # WSL
"bash.exe", # WSL
"ubuntu.exe", # WSL
"ubuntu1604.exe", # WSL
"ubuntu1804.exe", # WSL
"ubuntu2004.exe", # WSL
"ubuntu2204.exe", # WSL
"debian.exe", # WSL
"kali.exe", # WSL
"SLES-12.exe", # WSL
"openSUSE-42.exe", # WSL
"openSUSE-Leap-15-1.exe", # WSL
"WindowsTerminal.exe", # Windows Terminal
"mintty.exe", # mintty
"Cmder.exe", # Cmder
"ConEmu.exe", # ConEmu
"ConEmu64.exe", # ConEmu
"gvim.exe", # GVim
"xyzzy.exe", # xyzzy
"putty.exe", # PuTTY
"ttermpro.exe", # TeraTerm
"MobaXterm.exe", # MobaXterm
]
# キーマップ毎にキー設定をスキップするキーを指定する
# (リストに指定するキーは、define_key の第二引数に指定する記法のキーとしてください。"A-v" や "C-v"
# のような指定の他に、"M-f" や "Ctl-x d" などの指定も可能です。"M-g*" のようにワイルドカードも
# 利用することができます。ワイルドカード文字をエスケープしたい場合は、[] で括ってください。)
# (ここで指定したキーに新たに別のキー設定をしたいときには、define_key2 関数を利用してください)
fc.skip_settings_key = {"keymap_base" : ["*W-g"], # ベース Keymap
"keymap_global" : [], # グローバル Keymap
"keymap_emacs" : [], # Emacs キーバインド対象アプリ用 Keymap
"keymap_ime" : [], # IME 切り替え専用アプリ用 Keymap
"keymap_ei" : [], # Emacs 日本語入力モード用 Keymap
"keymap_tsw" : [], # タスク切り替え画面用 Keymap
"keymap_lw" : [], # リストウィンドウ用 Keymap
}
# Emacs のキーバインドにするアプリケーションソフトで、Emacs キーバインドから除外するキーを指定する
# (リストに指定するキーは、Keyhac で指定可能なマルチストロークではないキーとしてください。
# Fakeymacs の記法の "M-f" や "Ctl-x d" などの指定はできません。"A-v"、"C-v" などが指定可能です。)
# (ここで指定しなくとも、左右のモディファイアキーを使い分けることで入力することは可能です)
fc.emacs_exclusion_key = {"chrome.exe" : ["C-l", "C-t"],
"msedge.exe" : ["C-l", "C-t"],
"firefox.exe" : ["C-l", "C-t"],
"Code.exe" : ["C-S-b", "C-S-f", "C-S-p", "C-S-n", "C-S-a", "C-S-e"],
}
# clipboard 監視の対象外とするアプリケーションソフトを指定する
fc.not_clipboard_target = []
fc.not_clipboard_target += ["EXCEL.EXE"] # Microsoft Excel
# clipboard 監視の対象外とするウィンドウのクラスネームを指定する(ワイルドカードの指定可)
fc.not_clipboard_target_class = []
fc.not_clipboard_target_class += ["HwndWrapper*"] # WPF アプリ
# 左右どちらの Ctrl キーを使うかを指定する("L": 左、"R": 右)
fc.side_of_ctrl_key = "L"
# 左右どちらの Alt キーを使うかを指定する("L": 左、"R": 右)
fc.side_of_alt_key = "L"
# 左右どちらの Win キーを使うかを指定する("L": 左、"R": 右)
fc.side_of_win_key = "L"
# C-i キーを Tab キーとして使うかどうかを指定する(True: 使う、False: 使わない)
fc.use_ctrl_i_as_tab = True
# Esc キーを Meta キーとして使うかどうかを指定する(True: 使う、False: 使わない)
# (True(Meta キーとして使う)に設定されている場合、ESC の二回押下で ESC が入力されます)
fc.use_esc_as_meta = False
# C-[ キーを Meta キーとして使うかどうかを指定する(True: 使う、False: 使わない)
# (True(Meta キーとして使う)に設定されている場合、C-[ の二回押下で ESC が入力されます)
fc.use_ctrl_openbracket_as_meta = True
# Ctl-x プレフィックスキーに使うキーを指定する
# (Ctl-x プレフィックスキーのモディファイアキーは、Ctrl または Alt のいずれかから指定してください)
fc.ctl_x_prefix_key = "C-x"
# fc.ctl_x_prefix_key = "A-x"
# スクロールに使うキーの組み合わせ(Up、Down の順)を指定する
# fc.scroll_key = None # PageUp、PageDown キーのみを利用する
fc.scroll_key = ["M-v", "C-v"]
# Emacs 日本語入力モードを使うかどうかを指定する(True: 使う、False: 使わない)
fc.use_emacs_ime_mode = True
# Emacs 日本語入力モードが有効なときに表示するバルーンメッセージを指定する
# fc.emacs_ime_mode_balloon_message = None
fc.emacs_ime_mode_balloon_message = "▲"
# IME の状態を表示するバルーンメッセージを表示するかどうかを指定する(True: 表示する、False: 表示しない)
fc.use_ime_status_balloon = True
# IME の状態を表示するバルーンメッセージの組み合わせ(英数入力、日本語入力)を指定する
fc.ime_status_balloon_message = ["[A]", "[あ]"]
# IME をトグルで切り替えるキーを指定する(複数指定可)
fc.toggle_input_method_key = []
fc.toggle_input_method_key += ["C-Yen"]
fc.toggle_input_method_key += ["C-o"]
# fc.toggle_input_method_key += ["O-LAlt"]
#---------------------------------------------------------------------------------------------------
# IME を切り替えるキーの組み合わせ(disable、enable の順)を指定する(複数指定可)
# (toggle_input_method_key のキー設定より優先します)
fc.set_input_method_key = []
## 日本語キーボードを利用している場合、<無変換> キーで英数入力、<変換> キーで日本語入力となる
fc.set_input_method_key += [["(29)", "(28)"]]
## 日本語キーボードを利用している場合、<A> キーで英数入力、<あ> キーで日本語入力となる
## (https://docs.microsoft.com/ja-jp/windows-hardware/design/component-guidelines/keyboard-japan-ime)
fc.set_input_method_key += [["(26)", "(22)"]]
## LAlt の単押しで英数入力、RAlt の単押しで日本語入力となる
## (JetBrains 製の IDE でこの設定を利用するためには、ツールボタンをオンにする必要があるようです。
## 設定は、View -> Appearance -> Tool Window Bars を有効にしてください。)
# fc.set_input_method_key += [["O-LAlt", "O-RAlt"]]
## C-j や C-j C-j で 英数入力となる(toggle_input_method_key の設定と併せ、C-j C-o で日本語入力となる)
# fc.set_input_method_key += [["C-j", None]]
## C-j で英数入力、C-o で日本語入力となる(toggle_input_method_key の設定より優先)
# fc.set_input_method_key += [["C-j", "C-o"]]
## C-j で英数入力、C-i で日本語入力となる(C-i が Tab として利用できなくなるが、トグルキー C-o との併用可)
# fc.set_input_method_key += [["C-j", "C-i"]]
#---------------------------------------------------------------------------------------------------
#---------------------------------------------------------------------------------------------------
# IME の「再変換」を行うキーを指定する
## IME の「再変換」のために利用するキーを設定する(複数指定可)
## (Google 日本語入力を利用する場合、Ctrl キーと組み合わせたキーを設定してください。「確定取り消し」
## が正常に動作しないアプリケーションソフト(Microsoft Excel、Sakura Editor など)があります。
## ただし、C-Back キーは設定しないでください。)
## (リージョンを選択した状態で Space キーを押下すると「再変換」が機能します)
fc.reconversion_key = []
fc.reconversion_key += ["C-,"] # Comma は < のキーでもあり、変換を戻すイメージを持てるので採用
# fc.reconversion_key += ["(28)"] # <変換> キーを利用する場合でも、本機能を全て使うためには設定が必要
# fc.reconversion_key += ["O-RAlt"] # ワンショットモディファイアの指定も可能
## IME に設定してある「再変換」、「確定取り消し」を行うキーを指定する
## Windows 10 1909 以前の Microsoft IME の場合
if fc.ime == "old_Microsoft_IME":
fc.ime_reconv_key = "W-/" # 「再変換」キー
fc.ime_cancel_key = "C-Back" # 「確定の取り消し」キー
fc.ime_reconv_region = False # 「再変換」の時にリージョンの選択が必要かどうかを指定する
## Windows 10 2004 以降の 新しい Microsoft IME の場合
## (新しい Microsoft IME には確定取り消し(C-Backspace)の設定が無いようなので、「再変換」のキー
## を設定しています)
elif fc.ime == "new_Microsoft_IME":
fc.ime_reconv_key = "W-/" # 「再変換」キー
fc.ime_cancel_key = "W-/" # 「確定の取り消し」キー
fc.ime_reconv_region = False # 「再変換」の時にリージョンの選択が必要かどうかを指定する
## Google 日本語入力の場合
elif fc.ime == "Google_IME":
fc.ime_reconv_key = "W-/" # 「再変換」キー
fc.ime_cancel_key = "C-Back" # 「確定の取り消し」キー
fc.ime_reconv_region = True # 「再変換」の時にリージョンの選択が必要かどうかを指定する
## 上記以外の場合の場合(機能を無効にする)
else:
fc.reconversion_key = []
fc.ime_reconv_key = None
fc.ime_cancel_key = None
fc.ime_reconv_region = False
#---------------------------------------------------------------------------------------------------
#---------------------------------------------------------------------------------------------------
# Emacs 日本語入力モードを利用する際に、IME のショートカットを置き換えるキーの組み合わせ
# (置き換え先、置き換え元)を指定する
# (「ことえり」のキーバインドを利用するための設定例です。Google 日本語入力で「ことえり」の
# キー設定になっている場合には不要ですが、設定を行っていても問題はありません。)
fc.emacs_ime_mode_key = []
fc.emacs_ime_mode_key += [["C-i", "S-Left"], # 文節を縮める
["C-o", "S-Right"], # 文節を伸ばす
["C-j", "F6"], # ひらがなに変換
["C-k", "F7"], # 全角カタカナに変換
["C-l", "F9"], # 全角英数に表示切替
["C-;", "F8"]] # 半角に変換
if is_japanese_keyboard:
fc.emacs_ime_mode_key += [["C-:", "F10"]] # 半角英数に表示切替
else:
fc.emacs_ime_mode_key += [["C-'", "F10"]] # 半角英数に表示切替
#---------------------------------------------------------------------------------------------------
#---------------------------------------------------------------------------------------------------
# IME の「単語登録」プログラムを利用するための設定を行う
## IME の「単語登録」プログラムを起動するキーを指定する
# fc.word_register_key = None
fc.word_register_key = "C-]"
## IME の「単語登録」プログラムとそのパラメータを指定する
## Microsoft IME の場合
if fc.ime in ["old_Microsoft_IME", "new_Microsoft_IME"]:
fc.word_register_name = r"C:\Windows\System32\IME\IMEJP\IMJPDCT.EXE"
fc.word_register_param = ""
## Google 日本語入力の場合
elif fc.ime == "Google_IME":
fc.word_register_name = r"C:\Program Files (x86)\Google\Google Japanese Input\GoogleIMEJaTool.exe"
fc.word_register_param = "--mode=word_register_dialog"
## 上記以外の場合の場合(機能を無効にする)
else:
fc.word_register_key = None
fc.word_register_name = None
fc.word_register_param = None
#---------------------------------------------------------------------------------------------------
# Emacs キーバインドを切り替えるキーを指定する
# (Emacs キーバインドを利用するアプリケーションでかつフォーカスが当たっているアプリケーションソフト
# に対して切り替えが機能します。また、Emacs キーバインドを OFF にしても、IME の切り替えは ime_target
# に登録したアプリケーションソフトと同様に機能するようにしています。)
# (fc.emacs_target_class 変数に指定したクラスに該当するアプリケーションソフト(Windows10版 Notepad など)
# は、Emacs キーバインドを切り替えの対象となりません(常に Emacs キーバインドとなります)。)
fc.toggle_emacs_keybind_key = "C-S-Space"
# アプリケーションキーとして利用するキーを指定する
# (修飾キーに Alt は使えないようです)
fc.application_key = None
# fc.application_key = "O-RCtrl"
# 数引数の指定に Ctrl+数字キーを使うかを指定する(True: 使う、False: 使わない)
# (False に指定しても、C-u 数字キーで数引数を指定することができます)
fc.use_ctrl_digit_key_for_digit_argument = False
# F1 から F12 を Alt+数字キー列として使うかを指定する(True: 使う、False: 使わない)
fc.use_alt_digit_key_for_f1_to_f12 = False
# F13 から F24 を Alt-Shift+数字キー列として使うかを指定する(True: 使う、False: 使わない)
fc.use_alt_shift_digit_key_for_f13_to_f24 = False
# 表示しているウィンドウの中で、一番最近までフォーカスがあったウィンドウに移動するキーを指定する
fc.other_window_key = "A-o"
# アクティブウィンドウを切り替えるキーの組み合わせ(前、後 の順)を指定する(複数指定可)
# (A-Esc キーの動作とは異なり、仮想デスクトップを跨ぎ、最小化されていないウィンドウを順に切り替え
# ます。初期設定は ["A-p", "A-n"] としていますが、Emacs の shell-mode のキーバインドなどと設定が
# 被る場合には、["A-S-p", "A-S-n"] などの異なる設定とするか、Emacs 側に次の設定を入れて、Emacs 側
# のキーの設定を置き換えてご利用ください。
# (define-key key-translation-map (kbd "M-S-p") (kbd "M-p"))
# (define-key key-translation-map (kbd "M-S-n") (kbd "M-n"))
# )
fc.window_switching_key = []
fc.window_switching_key += [["A-p", "A-n"]]
# fc.window_switching_key += [["A-S-p", "A-S-n"]]
# fc.window_switching_key += [["A-Up", "A-Down"]]
# アクティブウィンドウをディスプレイ間で移動するキーの組み合わせ(前、後 の順)を指定する(複数指定可)
# (デフォルトキーは、["W-S-Left", "W-S-Right"])
fc.window_movement_key_for_displays = []
fc.window_movement_key_for_displays += [[None, "W-o"]]
# fc.window_movement_key_for_displays += [[None, "A-S-o"]]
# デュアルディスプレイにそれぞれ表示されているウィンドウを入れ替えるキーを指定する
fc.transpose_windows_key = "W-t"
# ウィンドウを最大化、リストアするキーの組み合わせ(リストア、最大化 の順)を指定する(複数指定可)
# (マルチディスプレイでの最大化にも対応しています)
fc.window_maximize_key = []
fc.window_maximize_key += [["W-S-q", "W-q"]] # Windows ショートカットキーの W-q の機能は、W-s で代用可
# fc.window_maximize_key += [["W-S-m", "W-m"]] # Windows ショートカットキーの W-m の機能は、W-d で代用可
# fc.window_maximize_key += [["W-S-s", "W-s"]] # Windows ショートカットキーの W-s の機能は、W-q で代用可
# ウィンドウを最小化、リストアするキーの組み合わせ(リストア、最小化 の順)を指定する(複数指定可)
fc.window_minimize_key = []
fc.window_minimize_key += [["A-S-m", "A-m"]]
# 仮想デスクトップを切り替えるキーの組み合わせ(前、後 の順)を指定する(複数指定可)
# (仮想デスクトップを切り替えた際にフォーカスのあるウィンドウを適切に処理するため、設定するキーは
# Win キーとの組み合わせとしてください)
# (デフォルトキーは、["W-C-Left", "W-C-Right"])
fc.desktop_switching_key = []
fc.desktop_switching_key += [["W-b", "W-f"]]
# fc.desktop_switching_key += [["W-Left", "W-Right"]]
# アクティブウィンドウを仮想デスクトップ間で移動するキーの組み合わせ(前、後 の順)を指定する(複数指定可)
# (本機能を利用する場合は、次のページから SylphyHornPlus をインストールしてください。
# ・https://github.com/hwtnb/SylphyHornPlusWin11/releases
# SylphyHornPlus は、Microsoft Store からインストール可能な SylphyHorn の Fork で、Windows 11 の
# 対応など、改良が加えられたものとなっています。)
# (アクティブウィンドウを仮想デスクトップ間で移動するためのデフォルトキーは、["W-C-A-Left", "W-C-A-Right"]
# です。この設定は変更しないでください。)
fc.window_movement_key_for_desktops = []
# fc.window_movement_key_for_desktops += [["W-p", "W-n"]]
# fc.window_movement_key_for_desktops += [["W-Up", "W-Down"]]
# ウィンドウ操作(other_window、restore_window など)の対象としたくないアプリケーションソフトの
# “クラス名称”を指定する
# (re.match 関数(先頭からのマッチ)の正規表現に「|」を使って繋げて指定してください。
# 完全マッチとするためには $ の指定が必要です。)
fc.window_operation_exclusion_class = r"Progman$"
# ウィンドウ操作(other_window、restore_window など)の対象としたくないアプリケーションソフトの
# “プロセス名称”を指定する
# (re.match 関数(先頭からのマッチ)の正規表現に「|」を使って繋げて指定してください。
# 完全マッチとするためには $ の指定が必要です。)
fc.window_operation_exclusion_process = r"RocketDock\.exe$" # サンプルとして RocketDock.exe を登録
# クリップボードリストを起動するキーを指定する
fc.clipboardList_key = "A-y"
# ランチャーリストを起動するキーを指定する
fc.lancherList_key = "A-l"
# shell_command 関数で起動するアプリケーションソフトを指定する
# (PATH が通っていない場所にあるコマンドは、絶対パスで指定してください)
fc.command_name = r"cmd.exe"
# コマンドのリピート回数の最大値を指定する
fc.repeat_max = 1024
# Microsoft Excel のセル内で改行を選択可能かを指定する(True: 選択可、False: 選択不可)
# (kill_line 関数の挙動を変えるための変数です。Microsoft Excel 2019 以降では True にして
# ください。)
fc.is_newline_selectable_in_Excel = True
# Ctrl キー単押しで開く Ctrl ボタンを持つアプリケーションソフト(プロセス名称とクラス名称の
# 組み合わせ(ワイルドカード指定可))を指定する
# (Microsoft Word 等では画面に Ctrl ボタンが表示され、Ctrl キーの単押しによりサブウインドウが
# 開く機能があります。その挙動を抑制するアプリケーションソフトのリストを指定してください。)
fc.ctrl_button_app_list = [["WINWORD.EXE", "_WwG"],
["EXCEL.EXE", "EXCEL*"],
["POWERPNT.EXE", "mdiClass"],
]
# ゲームなど、キーバインドの設定を極力行いたくないアプリケーションソフト(プロセス名称と
# クラス名称の組み合わせ(ワイルドカード指定可))を指定する
# (keymap_global 以外のすべてのキーマップをスルーします。ゲームなど、Keyhac によるキー設定と
# 相性が悪いアプリケーションソフトを指定してください。keymap_base の設定もスルーするため、
# 英語 -> 日本語キーボード変換の機能が働かなくなることにご留意ください。)
# (msrdc.exe の行の有効化の必要性については、次のコミットの説明を参照してください。
# https://github.com/smzht/fakeymacs/commit/5ceb921bd754ce348f9cd79b6606086916520945)
fc.game_app_list = [["ffxiv_dx11.exe", "*"], # FINAL FANTASY XIV
# ["msrdc.exe", "RAIL_WINDOW"], # WSLg
]
# 個人設定ファイルのセクション [section-base-1] を読み込んで実行する
exec(readConfigPersonal("[section-base-1]"), dict(globals(), **locals()))
###########################################################################
## ウィンドウフォーカスが変わった時、すぐに Keyhac に検知させるための設定
###########################################################################
# IME の状態をテキスト カーソル インジケーターの色で表現するときに必要となる設定
# (https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwineventhook)
# (https://sites.google.com/site/agkh6mze/howto/winevent)
# (https://stackoverflow.com/questions/15849564/how-to-use-winapi-setwineventhook-in-python)
# (https://github.com/Danesprite/windows-fun/blob/master/window%20change%20listener.py)
# (https://tutorialmore.com/questions-652366.htm)
# (https://www.nicovideo.jp/watch/sm20797948)
def setWinEventHook():
EVENT_SYSTEM_FOREGROUND = 0x0003
WINEVENT_OUTOFCONTEXT = 0x0000
WINEVENT_SKIPOWNPROCESS = 0x0002
user32 = ctypes.windll.user32
ole32 = ctypes.windll.ole32
try:
# 設定されているか?
keymap.fakeymacs_hook
# reload 時の対策
user32.UnhookWinEvent(keymap.fakeymacs_hook)
ole32.CoUninitialize()
except:
pass
ole32.CoInitialize(None)
WinEventProcType = ctypes.WINFUNCTYPE(
None,
ctypes.wintypes.HANDLE,
ctypes.wintypes.DWORD,
ctypes.wintypes.HWND,
ctypes.wintypes.LONG,
ctypes.wintypes.LONG,
ctypes.wintypes.DWORD,
ctypes.wintypes.DWORD
)
def _callback(hWinEventHook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime):
if keymap.hook_enabled:
delay(0.02)
keymap._updateFocusWindow()
else:
setCursorColor(False)
# この設定は必要(この設定がないと、Keyhac が落ちる場合がある)
global WinEventProc
WinEventProc = WinEventProcType(_callback)
user32.SetWinEventHook.restype = ctypes.wintypes.HANDLE
keymap.fakeymacs_hook = user32.SetWinEventHook(
EVENT_SYSTEM_FOREGROUND,
EVENT_SYSTEM_FOREGROUND,
0,
WinEventProc,
0,
0,
WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS
)
# ウィンドウが切り替わるときのイベントフックを設定する
setWinEventHook()
###########################################################################
## 日本語キーボード設定をした OS 上で英語キーボードを利用するための設定
###########################################################################
if use_usjis_keyboard_conversion:
str_vk_table = copy.copy(keyhac_keymap.KeyCondition.str_vk_table_common)
for name in keyhac_keymap.KeyCondition.str_vk_table_jpn:
del str_vk_table[name]
str_vk_table.update(keyhac_keymap.KeyCondition.str_vk_table_std)
vk_str_table = copy.copy(keyhac_keymap.KeyCondition.vk_str_table_common)
for vk in keyhac_keymap.KeyCondition.vk_str_table_jpn:
del vk_str_table[vk]
vk_str_table.update(keyhac_keymap.KeyCondition.vk_str_table_std)
def usjisTableSwap(swap):
if swap:
keyhac_keymap.KeyCondition.str_vk_table = str_vk_table
keyhac_keymap.KeyCondition.vk_str_table = vk_str_table
else:
# table_common は table_jpn で update した状態となっているためこれで良い
keyhac_keymap.KeyCondition.str_vk_table = keyhac_keymap.KeyCondition.str_vk_table_common
keyhac_keymap.KeyCondition.vk_str_table = keyhac_keymap.KeyCondition.vk_str_table_common
def usjisFilter(func, *param):
usjisTableSwap(1)
rtn = func(*param)
usjisTableSwap(0)
return rtn
else:
def usjisFilter(func, *param):
rtn = func(*param)
return rtn
usjis_key_table = {"S-2" : [["S-2"], "Atmark" ], # @
"S-6" : [["S-6"], "Caret" ], # ^
"S-7" : [["S-7"], "S-6" ], # &
"S-8" : [["S-8"], "S-Colon" ], # *
"S-9" : [["S-9"], "S-8" ], # (
"S-0" : [["S-0"], "S-9" ], # )
"S-Minus" : [["S-Minus"], "S-BackSlash" ], # _
"Plus" : [["Caret"], "S-Minus" ], # =
"S-Plus" : [["S-Caret"], "S-Semicolon" ], # +
"OpenBracket" : [["Atmark"], "OpenBracket" ], # [
"S-OpenBracket" : [["S-Atmark"], "S-OpenBracket" ], # {
"CloseBracket" : [["OpenBracket"], "CloseBracket" ], # ]
"S-CloseBracket" : [["S-OpenBracket"], "S-CloseBracket"], # }
"BackSlash" : [["CloseBracket"], "Yen" ], # \
"S-BackSlash" : [["S-CloseBracket"], "S-Yen" ], # |
"S-Semicolon" : [["S-Semicolon"], "Colon" ], # :
"Quote" : [["Colon"], "S-7" ], # '
"S-Quote" : [["S-Colon"], "S-2" ], # "
"BackQuote" : [["(243)", "(244)"], "S-Atmark" ], # `
"S-BackQuote" : [["S-(243)", "S-(244)"], "S-Caret" ], # ~
"(243)" : [[], "(243)" ], # <半角/全角>
"S-(243)" : [[], "S-(243)" ], # S-<半角/全角>
"(244)" : [[], "(244)" ], # <半角/全角>
"S-(244)" : [[], "S-(244)" ], # S-<半角/全角>
}
def keyStrNormalization(key):
nkey = usjisFilter(str, usjisFilter(keyhac_keymap.KeyCondition.fromString, key))
if "D-" not in key:
nkey = nkey.replace("D-", "")
return nkey
def usjisPos(key):
key = keyStrNormalization(key)
key_list = []
match_flg = False
if use_usjis_keyboard_conversion:
for us_key, jis_list in usjis_key_table.items():
if re.search(rf"(^|[^S]-){re.escape(us_key)}$", key):
for jis_pos_key in jis_list[0]:
key_list.append(key.replace(us_key, jis_pos_key))
match_flg = True
break
if not match_flg:
key_list.append(key)
return key_list
def usjisInput(key):
key = keyStrNormalization(key)
if use_usjis_keyboard_conversion:
for us_key, jis_list in usjis_key_table.items():
if re.search(rf"(^|[^S]-){re.escape(us_key)}$", key):
jis_input_key = jis_list[1]
key = key.replace(us_key, jis_input_key)
break
return key
###########################################################################
## 基本機能の設定
###########################################################################
fakeymacs.not_emacs_keybind = []
fakeymacs.ime_cancel = False
fakeymacs.last_window = None
fakeymacs.clipboard_hook = True
fakeymacs.last_keys = [None, None]
fakeymacs.correct_ime_status = False
fakeymacs.window_list = []
def is_base_target(window):
process_name = window.getProcessName()
class_name = window.getClassName()
if window is not fakeymacs.last_window:
if (process_name in fc.not_clipboard_target or
any(checkWindow(None, c, window=window) for c in fc.not_clipboard_target_class)):
# クリップボードの監視用のフックを無効にする
keymap.clipboard_history.enableHook(False)
fakeymacs.clipboard_hook = False
else:
# クリップボードの監視用のフックを有効にする
keymap.clipboard_history.enableHook(True)
fakeymacs.clipboard_hook = True
if fc.correct_ime_status:
if fc.ime == "Google_IME":
if process_name in fc.chromium_browser_list:
fakeymacs.correct_ime_status = True
else:
fakeymacs.correct_ime_status = False
fakeymacs.ctrl_button_app = False
if any(checkWindow(*app, window=window) for app in fc.ctrl_button_app_list):
fakeymacs.ctrl_button_app = True
# Microsoft Word 等では画面に Ctrl ボタンが表示され、Ctrl キーの単押しによりサブウインドウが
# 開く機能がある。その挙動を抑制するための対策。
d_ctrl = f"D-{fc.side_of_ctrl_key}Ctrl"
if fakeymacs.ctrl_button_app:
keymap_base[d_ctrl] = d_ctrl, "(255)"
else:
keymap_base[d_ctrl] = d_ctrl
if (process_name in fc.transparent_target or
class_name in fc.transparent_target_class or
any(checkWindow(*app, window=window) if type(app) is list else
checkWindow(app, window=window) for app in fc.game_app_list)):
fakeymacs.is_base_target = False
fakeymacs.is_keymap_decided = True
return False
else:
fakeymacs.is_base_target = True
fakeymacs.is_keymap_decided = False
return True
def is_emacs_target(window):
last_window = fakeymacs.last_window
process_name = window.getProcessName()
class_name = window.getClassName()
if window is not last_window:
if process_name in fc.emacs_exclusion_key:
fakeymacs.exclution_key = [keyStrNormalization(addSideOfModifierKey(specialCharToKeyStr(key)))
for key in fc.emacs_exclusion_key[process_name]]
else:
fakeymacs.exclution_key = []
reset_undo(reset_counter(reset_mark(lambda: None)))()
fakeymacs.ime_cancel = False
fakeymacs.last_window = window
if is_task_switching_window(window):
fakeymacs.is_keymap_decided = True
return False
if is_list_window(window):
fakeymacs.is_keymap_decided = True
return False
if window is not last_window:
showImeStatus(window.getImeStatus(), window=window)
if (fakeymacs.is_keymap_decided == True or
(class_name not in fc.emacs_target_class and
(process_name in fakeymacs.not_emacs_keybind or
process_name in fc.not_emacs_target))):
fakeymacs.is_emacs_target = False
return False
else:
fakeymacs.is_emacs_target = True
fakeymacs.is_keymap_decided = True
return True
def is_ime_target(window):
if (fakeymacs.is_keymap_decided == False and
(window.getProcessName() in fakeymacs.not_emacs_keybind or
window.getProcessName() in fc.ime_target)):
return True
else:
return False
keymap_base = keymap.defineWindowKeymap(check_func=is_base_target)
if fc.use_emacs_ime_mode:
keymap_emacs = keymap.defineWindowKeymap(check_func=lambda wnd: is_emacs_target(wnd) and not is_emacs_ime_mode(wnd))
keymap_ime = keymap.defineWindowKeymap(check_func=lambda wnd: is_ime_target(wnd) and not is_emacs_ime_mode(wnd))
else:
keymap_emacs = keymap.defineWindowKeymap(check_func=is_emacs_target)
keymap_ime = keymap.defineWindowKeymap(check_func=is_ime_target)
# mark がセットされると True になる
fakeymacs.is_marked = False
# リージョンを拡張する際に、順方向に拡張すると True、逆方向に拡張すると False になる
fakeymacs.forward_direction = None
# 検索が開始されると True になる
fakeymacs.is_searching = False
# キーボードマクロの play 中 は True になる
fakeymacs.is_playing_kmacro = False
# universal-argument コマンドが実行されると True になる
fakeymacs.is_universal_argument = False
# digit-argument コマンドが実行されると True になる
fakeymacs.is_digit_argument = False
# コマンドのリピート回数を設定する
fakeymacs.repeat_counter = 1
# undo のモードの時 True になる(redo のモードの時 False になる)
fakeymacs.is_undo_mode = True
# ウィンドウのリストアが最小化した順番の逆順となるように制御する
fakeymacs.reverse_window_to_restore = False
# Ctl-x プレフィックスキーを構成するキーの仮想キーコードを設定する
if fc.ctl_x_prefix_key:
keyCondition = usjisFilter(keyhac_keymap.KeyCondition.fromString, fc.ctl_x_prefix_key)
if keyCondition.mod == keyhac_keymap.MODKEY_CTRL:
if fc.side_of_ctrl_key == "L":
ctl_x_prefix_vkey = [VK_LCONTROL, keyCondition.vk]
else:
ctl_x_prefix_vkey = [VK_RCONTROL, keyCondition.vk]
elif keyCondition.mod == keyhac_keymap.MODKEY_ALT:
if fc.side_of_alt_key == "L":
ctl_x_prefix_vkey = [VK_LMENU, keyCondition.vk]
else:
ctl_x_prefix_vkey = [VK_RMENU, keyCondition.vk]
else:
print("Ctl-x プレフィックスキーのモディファイアキーは、Ctrl または Alt のいずれかから指定してください")
##################################################
## Emacs キーバインドの切り替え
##################################################
def toggle_emacs_keybind():
class_name = keymap.getWindow().getClassName()
process_name = keymap.getWindow().getProcessName()
if (class_name not in fc.emacs_target_class and
process_name not in fc.not_emacs_target):
if process_name in fakeymacs.not_emacs_keybind:
fakeymacs.not_emacs_keybind.remove(process_name)
keymap.popBalloon("keybind", "[Enable Emacs keybind]", 1000)
else:
fakeymacs.not_emacs_keybind.append(process_name)
keymap.popBalloon("keybind", "[Disable Emacs keybind]", 1000)
keymap.updateKeymap()
##################################################
## IME の操作
##################################################
def enable_input_method():
set_input_method(1)
def disable_input_method():
set_input_method(0)
def toggle_input_method():
set_input_method(getImeStatus() ^ 1)
def set_input_method(ime_status):
correctImeStatus()
if getImeStatus() != ime_status:
# IME を切り替える
# (setImeStatus(ime_status) を使わないのは、キーボードマクロの再生時に影響がでるため)
self_insert_command("(25)")()
if fakeymacs.is_playing_kmacro:
delay(0.2)
showImeStatus(ime_status)
def getImeStatus():
return keymap.getWindow().getImeStatus()
def setImeStatus(ime_status):
keymap.getWindow().setImeStatus(ime_status)
setCursorColor(ime_status)
def showImeStatus(ime_status, force=False, window=None):
setCursorColor(ime_status)
popImeBalloon(ime_status, force, window)
def correctImeStatus():
# Chromium 系ブラウザで発生する問題の対策を行う
if fakeymacs.correct_ime_status:
if getImeStatus():
setImeStatus(0) # この行は必要
setImeStatus(1)
def setCursorColor(ime_status):
if fc.use_ime_status_cursor_color:
if ime_status:
cursor_color = fc.ime_on_cursor_color
else:
cursor_color = fc.ime_off_cursor_color
# https://docs.python.org/ja/3/library/winreg.html
# https://itasuke.hatenablog.com/entry/2018/01/08/133510
with winreg.OpenKeyEx(winreg.HKEY_CURRENT_USER,
r"Software\Microsoft\Accessibility\CursorIndicator",
access=winreg.KEY_WRITE) as key:
winreg.SetValueEx(key, "IndicatorColor", 0, winreg.REG_DWORD, cursor_color)
def popImeBalloon(ime_status, force=False, window=None):
if not fakeymacs.is_playing_kmacro:
if force or fc.use_ime_status_balloon:
# LINE アプリなど、Qt5152QWindowIcon にマッチするクラスをもつアプリは入力文字に
# バルーンヘルプが被るので、バルーンヘルプの表示対象から外す
# (ただし、force が True の場合は除く)
if force or not checkWindow(None, "Qt5152QWindowIcon", window=window):
if ime_status:
message = fc.ime_status_balloon_message[1]
else:
message = fc.ime_status_balloon_message[0]
try:
# IME の状態をバルーンヘルプで表示する
keymap.popBalloon("ime_status", message, 500)
except:
pass