-
Notifications
You must be signed in to change notification settings - Fork 219
/
__init__.py
1943 lines (1719 loc) · 115 KB
/
__init__.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
#! python3
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from keycodes import * # for VK_XXX constants
import os.path
import time
import opencc # OpenCC 繁體簡體中文轉換
import io
import math
import copy
import ctypes
import winsound
from .swkb import swkb
from .symbols import symbols
from .dsymbols import dsymbols
from .fsymbols import fsymbols
from .msymbols import msymbols
from .flangs import flangs
from .phrase import phrase
from .userphrase import userphrase
from .emoji import emoji
CHINESE_MODE = 1
ENGLISH_MODE = 0
FULLSHAPE_MODE = 1
HALFSHAPE_MODE = 0
# shift + space 熱鍵的 GUID
SHIFT_SPACE_GUID = "{f1dae0fb-8091-44a7-8a0c-3082a1515447}"
TF_MOD_SHIFT = 0x0004
# 選單項目和語言列按鈕的 command ID
ID_SWITCH_LANG = 1
ID_SWITCH_SHAPE = 2
ID_SETTINGS = 3
ID_MODE_ICON = 4
ID_WEBSITE = 5
ID_BUGREPORT = 6
ID_FORUM = 7
ID_MOEDICT = 8
ID_DICT = 9
ID_SIMPDICT = 10
ID_LITTLEDICT = 11
ID_PROVERBDICT = 12
ID_OUTPUT_SIMP_CHINESE = 13
class CinBase:
def __init__(self):
self.cinbasecurdir = os.path.abspath(os.path.dirname(__file__))
self.icondir = os.path.join(os.path.dirname(__file__), "icons")
self.candselKeys = "1234567890"
self.emoji = emoji
self.emojimenulist = ["表情符號", "圖形符號", "其它符號", "雜錦符號", "交通運輸", "調色盤"]
# 初始化輸入行為設定
def initTextService(self, CinBaseTextService, TextService):
CinBaseTextService.TextService = TextService
CinBaseTextService.TextService.setSelKeys(CinBaseTextService, self.candselKeys)
# 使用 OpenCC 繁體中文轉簡體
CinBaseTextService.opencc = None
CinBaseTextService.keyboardLayout = 0
CinBaseTextService.selKeys = "1234567890"
CinBaseTextService.langMode = -1
CinBaseTextService.shapeMode = -1
CinBaseTextService.switchPageWithSpace = False
CinBaseTextService.outputSimpChinese = False
CinBaseTextService.hidePromptMessages = True
CinBaseTextService.autoClearCompositionChar = False
CinBaseTextService.playSoundWhenNonCand = False
CinBaseTextService.directShowCand = False
CinBaseTextService.directCommitString = False
CinBaseTextService.directCommitSymbol = False
CinBaseTextService.fullShapeSymbols = False
CinBaseTextService.easySymbolsWithShift = False
CinBaseTextService.supportSymbolCoding = False
CinBaseTextService.showPhrase = False
CinBaseTextService.sortByPhrase = False
CinBaseTextService.lastKeyDownCode = 0
CinBaseTextService.lastKeyDownTime = 0.0
CinBaseTextService.menucandidates = []
CinBaseTextService.smenucandidates = []
CinBaseTextService.wildcardcandidates = []
CinBaseTextService.wildcardpagecandidates = []
CinBaseTextService.wildcardcompositionChar = ""
CinBaseTextService.currentCandPage = 0
CinBaseTextService.emojitype = 0
CinBaseTextService.prevmenutypelist = []
CinBaseTextService.prevmenucandlist = []
CinBaseTextService.showmenu = False
CinBaseTextService.switchmenu = False
CinBaseTextService.closemenu = True
CinBaseTextService.multifunctionmode = False
CinBaseTextService.emojimenumode = False
CinBaseTextService.ctrlsymbolsmode = False
CinBaseTextService.phrasemode = False
CinBaseTextService.isSelKeysChanged = False
CinBaseTextService.isWildcardChardefs = False
CinBaseTextService.isLangModeChanged = False
CinBaseTextService.isShapeModeChanged = False
CinBaseTextService.isShowCandidates = False
CinBaseTextService.isShowPhraseCandidates = False
CinBaseTextService.canSetCommitString = True
CinBaseTextService.canUseSelKey = True
CinBaseTextService.canUseSpaceAsPageKey = True
CinBaseTextService.endKeyList = []
CinBaseTextService.useEndKey = False
CinBaseTextService.useDayiSymbols = False
CinBaseTextService.dayisymbolsmode = False
CinBaseTextService.autoShowCandWhenMaxChar = False
CinBaseTextService.lastCommitString = ""
CinBaseTextService.lastCompositionCharLength = 0
CinBaseTextService.menutype = 0
CinBaseTextService.resetMenuCand = False
CinBaseTextService.capsStates = True if self.getKeyState(VK_CAPITAL) else False
# 輸入法被使用者啟用
def onActivate(self, CinBaseTextService):
# 向系統宣告 Shift + Space 這個組合為特殊用途 (全半形切換)
# 當 Shift + Space 被按下的時候,onPreservedKey() 會被呼叫
CinBaseTextService.addPreservedKey(VK_SPACE, TF_MOD_SHIFT, SHIFT_SPACE_GUID); # shift + space
# 切換中英文
icon_name = "chi.ico" if CinBaseTextService.langMode == CHINESE_MODE else "eng.ico"
CinBaseTextService.addButton("switch-lang",
icon=os.path.join(self.icondir, icon_name),
tooltip="中英文切換",
commandId=ID_SWITCH_LANG
)
# Windows 8 以上已取消語言列功能,改用 systray IME mode icon
if CinBaseTextService.client.isWindows8Above:
if CinBaseTextService.langMode == CHINESE_MODE:
if CinBaseTextService.shapeMode == FULLSHAPE_MODE:
icon_name = "chi_full_capson.ico" if CinBaseTextService.capsStates else "chi_full_capsoff.ico"
else:
icon_name = "chi_half_capson.ico" if CinBaseTextService.capsStates else "chi_half_capsoff.ico"
else:
if CinBaseTextService.shapeMode == FULLSHAPE_MODE:
icon_name = "eng_full_capson.ico" if CinBaseTextService.capsStates else "eng_full_capsoff.ico"
else:
icon_name = "eng_half_capson.ico" if CinBaseTextService.capsStates else "eng_half_capsoff.ico"
CinBaseTextService.addButton("windows-mode-icon",
icon=os.path.join(self.icondir, icon_name),
tooltip="中英文切換",
commandId=ID_MODE_ICON
)
# 切換全半形
icon_name = "full.ico" if CinBaseTextService.shapeMode == FULLSHAPE_MODE else "half.ico"
CinBaseTextService.addButton("switch-shape",
icon = os.path.join(self.icondir, icon_name),
tooltip = "全形/半形切換",
commandId = ID_SWITCH_SHAPE
)
# 設定
CinBaseTextService.addButton("settings",
icon = os.path.join(self.icondir, "config.ico"),
tooltip = "設定",
type = "menu"
)
# 使用者離開輸入法
def onDeactivate(self, CinBaseTextService):
CinBaseTextService.lastKeyDownCode = 0
# 向系統宣告移除 Shift + Space 這個組合鍵用途 (全半形切換)
CinBaseTextService.removePreservedKey(SHIFT_SPACE_GUID); # shift + space
CinBaseTextService.removeButton("switch-lang")
CinBaseTextService.removeButton("switch-shape")
CinBaseTextService.removeButton("settings")
if CinBaseTextService.client.isWindows8Above:
CinBaseTextService.removeButton("windows-mode-icon")
# 使用者按下按鍵,在 app 收到前先過濾那些鍵是輸入法需要的。
# return True,系統會呼叫 onKeyDown() 進一步處理這個按鍵
# return False,表示我們不需要這個鍵,系統會原封不動把按鍵傳給應用程式
def filterKeyDown(self, CinBaseTextService, keyEvent):
# 紀錄最後一次按下的鍵和按下的時間,在 filterKeyUp() 中要用
CinBaseTextService.lastKeyDownCode = keyEvent.keyCode
if CinBaseTextService.lastKeyDownTime == 0.0:
CinBaseTextService.lastKeyDownTime = time.time()
# 使用者開始輸入,還沒送出前的編輯區內容稱 composition string
# isComposing() 是 False,表示目前編輯區是空的
# 若正在編輯中文,則任何按鍵我們都需要送給輸入法處理,直接 return True
# 另外,若使用 "`" key 輸入特殊符號,可能會有編輯區是空的
# 但選字清單開啟,輸入法需要處理的情況
if CinBaseTextService.isComposing() or CinBaseTextService.showCandidates:
return True
# -------------- 以下都是「沒有」正在輸入中文的狀況 --------------
# 如果按下 Alt,可能是應用程式熱鍵,輸入法不做處理
if keyEvent.isKeyDown(VK_MENU):
return False
# 如果按下 Ctrl 鍵
if keyEvent.isKeyDown(VK_CONTROL):
# 若按下的是指定的符號鍵,輸入法需要處理此按鍵
if self.isCtrlSymbolsChar(keyEvent.keyCode) and CinBaseTextService.langMode == CHINESE_MODE:
return True
else:
return False
# 若按下 Shift 鍵
if keyEvent.isKeyDown(VK_SHIFT):
if CinBaseTextService.langMode == CHINESE_MODE and not keyEvent.isKeyDown(VK_CONTROL):
# 若開啟 Shift 快速輸入符號,輸入法需要處理此按鍵
if CinBaseTextService.easySymbolsWithShift and self.isLetterChar(keyEvent.keyCode):
return True
# 若開啟 Shift 輸入全形標點,輸入法需要處理此按鍵
if CinBaseTextService.fullShapeSymbols and (self.isSymbolsChar(keyEvent.keyCode) or self.isNumberChar(keyEvent.keyCode)):
return True
# 若萬用字元使用*,輸入法需要處理*按鍵
if CinBaseTextService.selWildcardChar == '*' and keyEvent.keyCode == 0x38:
return True
# 不論中英文模式,NumPad 都允許直接輸入數字,輸入法不處理
if keyEvent.isKeyToggled(VK_NUMLOCK): # NumLock is on
# if this key is Num pad 0-9, +, -, *, /, pass it back to the system
if keyEvent.keyCode >= VK_NUMPAD0 and keyEvent.keyCode <= VK_DIVIDE:
return False # bypass IME
# 不管中英文模式,只要是全形可見字元或空白,輸入法都需要進一步處理(半形轉為全形)
if CinBaseTextService.shapeMode == FULLSHAPE_MODE:
return (keyEvent.isPrintableChar() or keyEvent.keyCode == VK_SPACE)
# -------------- 以下皆為半形模式 --------------
# 如果是英文半形模式,輸入法不做任何處理
if CinBaseTextService.langMode == ENGLISH_MODE:
return False
# -------------- 以下皆為中文模式 --------------
# 中文模式下,當中文編輯區是空的,輸入法只需處理倉頡字根
# 檢查按下的鍵是否為倉頡字根
if CinBaseTextService.cin.isInKeyName(chr(keyEvent.charCode).lower()):
return True
# 中文模式下,當中文編輯區是空的,且不是預設鍵盤,輸入法需處理其它鍵盤所定義的字根
# 檢查按下的鍵是否為其它鍵盤定義的字根
if not CinBaseTextService.keyboardLayout == 0:
if chr(keyEvent.charCode).lower() in CinBaseTextService.kbtypelist[CinBaseTextService.keyboardLayout]:
return True
# 中文模式下,若按下 ` 鍵,讓輸入法進行處理
if keyEvent.isKeyDown(VK_OEM_3):
return True
if CinBaseTextService.useDayiSymbols and keyEvent.isKeyDown(VK_OEM_PLUS):
return True
# 其餘狀況一律不處理,原按鍵輸入直接送還給應用程式
return False
def onKeyDown(self, CinBaseTextService, keyEvent):
charCode = keyEvent.charCode
keyCode = keyEvent.keyCode
charStr = chr(charCode)
# 不論中英文模式,NumPad 都允許直接輸入數字,輸入法不處理
if keyEvent.isKeyToggled(VK_NUMLOCK): # NumLock is on
# if this key is Num pad 0-9, +, -, *, /, pass it back to the system
if keyEvent.keyCode >= VK_NUMPAD0 and keyEvent.keyCode <= VK_DIVIDE:
return True # bypass IME
# 鍵盤對映 (注音)
if not CinBaseTextService.keyboardLayout == 0 and charStr.lower() in CinBaseTextService.kbtypelist[CinBaseTextService.keyboardLayout]:
if not keyEvent.isKeyDown(VK_SHIFT) and not keyEvent.isKeyDown(VK_CONTROL):
charIndex = CinBaseTextService.kbtypelist[CinBaseTextService.keyboardLayout].index(charStr.lower())
charStr = CinBaseTextService.kbtypelist[0][charIndex]
# 檢查選字鍵
if not CinBaseTextService.imeDirName == "chedayi":
CinBaseTextService.selKeys = "1234567890"
if not self.candselKeys == "1234567890":
self.candselKeys = "1234567890"
CinBaseTextService.TextService.setSelKeys(CinBaseTextService, self.candselKeys)
CinBaseTextService.isSelKeysChanged = True
candidates = []
charStrLow = charStr.lower()
CinBaseTextService.isWildcardChardefs = False
CinBaseTextService.canSetCommitString = True
CinBaseTextService.showMessage("", 0)
if CinBaseTextService.langMode == ENGLISH_MODE:
if CinBaseTextService.isComposing() or CinBaseTextService.showCandidates:
CinBaseTextService.setCommitString(charStr)
self.resetComposition(CinBaseTextService)
return True
# 多功能前導字元 ---------------------------------------------------------
if CinBaseTextService.multifunctionmode:
CinBaseTextService.canUseSelKey = True
if CinBaseTextService.langMode == CHINESE_MODE and not CinBaseTextService.showmenu:
if len(CinBaseTextService.compositionChar) == 0 and charStr == '`' and not CinBaseTextService.imeDirName == "cheez":
CinBaseTextService.compositionChar += charStr
CinBaseTextService.setCompositionString(CinBaseTextService.compositionChar)
if not CinBaseTextService.hidePromptMessages:
messagestr = '多功能前導字元'
CinBaseTextService.showMessage(messagestr, 5)
CinBaseTextService.multifunctionmode = True
elif len(CinBaseTextService.compositionChar) == 1 and CinBaseTextService.multifunctionmode:
if charStrLow == 'm':
CinBaseTextService.compositionChar = ''
CinBaseTextService.setCompositionString('')
CinBaseTextService.multifunctionmode = False
CinBaseTextService.closemenu = False
elif charStrLow == 'u':
CinBaseTextService.compositionChar += charStr.upper()
CinBaseTextService.setCompositionString(CinBaseTextService.compositionChar)
elif charStrLow == 'e':
CinBaseTextService.compositionChar = ''
CinBaseTextService.setCompositionString('')
CinBaseTextService.multifunctionmode = False
CinBaseTextService.closemenu = False
CinBaseTextService.emojimenumode = True
elif self.isSymbolsChar(keyCode) or self.isNumberChar(keyCode):
if self.isNumberChar(keyCode):
CinBaseTextService.canUseSelKey = False
CinBaseTextService.compositionChar += charStr
elif len(CinBaseTextService.compositionChar) > 1 and CinBaseTextService.multifunctionmode:
if CinBaseTextService.msymbols.isInCharDef(CinBaseTextService.compositionChar[1:] + charStr):
CinBaseTextService.compositionChar += charStr
elif CinBaseTextService.compositionChar[:2] == '`U':
if keyCode >= 0x30 and keyCode <= 0x46:
CinBaseTextService.compositionChar += charStr.upper()
CinBaseTextService.setCompositionString(CinBaseTextService.compositionChar)
elif CinBaseTextService.compositionChar[:2] == '``':
if keyCode == VK_OEM_3:
CinBaseTextService.compositionChar += charStr
if len(CinBaseTextService.compositionChar) == 3 and CinBaseTextService.multifunctionmode:
if CinBaseTextService.compositionChar == '```':
CinBaseTextService.compositionChar = ''
CinBaseTextService.setCompositionString('')
CinBaseTextService.multifunctionmode = False
CinBaseTextService.closemenu = False
if CinBaseTextService.multifunctionmode:
# 按下 ESC 鍵
if keyCode == VK_ESCAPE and (CinBaseTextService.showCandidates or len(CinBaseTextService.compositionChar) > 0):
self.resetComposition(CinBaseTextService)
return True
# 刪掉一個字根
if keyCode == VK_BACK:
if CinBaseTextService.compositionString != '':
CinBaseTextService.setCompositionString(CinBaseTextService.compositionString[:-1])
CinBaseTextService.compositionChar = CinBaseTextService.compositionChar[:-1]
CinBaseTextService.setCandidateCursor(0)
CinBaseTextService.setCandidatePage(0)
if CinBaseTextService.compositionString == '':
self.resetComposition(CinBaseTextService)
return True
# Unicode 編碼字元超過 5 + 2 個
if CinBaseTextService.compositionChar[:2] == '`U' and len(CinBaseTextService.compositionChar) > 7:
CinBaseTextService.setCompositionString(CinBaseTextService.compositionString[:-1])
CinBaseTextService.compositionChar = CinBaseTextService.compositionChar[:-1]
# 按下的鍵為微軟有定義的字根
if CinBaseTextService.msymbols.isInCharDef(CinBaseTextService.compositionChar[1:]) and CinBaseTextService.closemenu and len(CinBaseTextService.compositionChar) >= 2:
candidates = CinBaseTextService.msymbols.getCharDef(CinBaseTextService.compositionChar[1:])
CinBaseTextService.setCompositionString(candidates[0])
# 輕鬆輸入法進入選單模式
if CinBaseTextService.imeDirName == "cheez" and CinBaseTextService.compositionChar + charStrLow == 'menu':
CinBaseTextService.compositionChar = ''
CinBaseTextService.setCompositionString('')
CinBaseTextService.multifunctionmode = False
CinBaseTextService.closemenu = False
# 功能選單 ----------------------------------------------------------------
if CinBaseTextService.langMode == CHINESE_MODE and len(CinBaseTextService.compositionChar) == 0:
menu_OutputSimpChinese = "輸出繁體" if CinBaseTextService.outputSimpChinese else "輸出簡體"
menu_fullShapeSymbols = "☑ Shift 輸入全形標點" if CinBaseTextService.fullShapeSymbols else "☐ Shift 輸入全形標點"
menu_easySymbolsWithShift = "☑ Shift 快速輸入符號" if CinBaseTextService.easySymbolsWithShift else "☐ Shift 快速輸入符號"
menu_supportSymbolCoding = "☑ Cin 碼表的符號編碼" if CinBaseTextService.supportSymbolCoding else "☐ Cin 碼表的符號編碼"
menu_supportWildcard = "☑ 以萬用字元代替組字字根" if CinBaseTextService.supportWildcard else "☐ 以萬用字元代替組字字根"
menu_autoClearCompositionChar = "☑ 拆錯字碼時自動清除輸入字串" if CinBaseTextService.autoClearCompositionChar else "☐ 拆錯字碼時自動清除輸入字串"
menu_playSoundWhenNonCand = "☑ 拆錯字碼時發出警告嗶聲提示" if CinBaseTextService.playSoundWhenNonCand else "☐ 拆錯字碼時發出警告嗶聲提示"
menu_showPhrase = "☑ 輸出字串後顯示聯想字詞" if CinBaseTextService.showPhrase else "☐ 輸出字串後顯示聯想字詞"
menu_sortByPhrase = "☑ 優先以聯想字詞排序候選清單" if CinBaseTextService.sortByPhrase else "☐ 優先以聯想字詞排序候選清單"
if CinBaseTextService.imeDirName == "chephonetic":
CinBaseTextService.smenucandidates = [menu_fullShapeSymbols, menu_easySymbolsWithShift, menu_autoClearCompositionChar, menu_playSoundWhenNonCand, menu_showPhrase, menu_sortByPhrase]
CinBaseTextService.smenuitems = ["fullShapeSymbols", "easySymbolsWithShift", "autoClearCompositionChar", "playSoundWhenNonCand", "showPhrase", "sortByPhrase"]
elif CinBaseTextService.imeDirName == "cheez":
CinBaseTextService.smenucandidates = [menu_supportWildcard, menu_autoClearCompositionChar, menu_playSoundWhenNonCand, menu_showPhrase, menu_sortByPhrase]
CinBaseTextService.smenuitems = ["supportWildcard", "autoClearCompositionChar", "playSoundWhenNonCand", "showPhrase", "sortByPhrase"]
elif CinBaseTextService.imeDirName == "chearray" or CinBaseTextService.imeDirName == "chedayi":
CinBaseTextService.smenucandidates = [menu_fullShapeSymbols, menu_easySymbolsWithShift, menu_supportWildcard, menu_autoClearCompositionChar, menu_playSoundWhenNonCand, menu_showPhrase, menu_sortByPhrase]
CinBaseTextService.smenuitems = ["fullShapeSymbols", "easySymbolsWithShift", "supportWildcard", "autoClearCompositionChar", "playSoundWhenNonCand", "showPhrase", "sortByPhrase"]
else:
CinBaseTextService.smenucandidates = [menu_fullShapeSymbols, menu_easySymbolsWithShift, menu_supportSymbolCoding, menu_supportWildcard, menu_autoClearCompositionChar, menu_playSoundWhenNonCand, menu_showPhrase, menu_sortByPhrase]
CinBaseTextService.smenuitems = ["fullShapeSymbols", "easySymbolsWithShift", "supportSymbolCoding", "supportWildcard", "autoClearCompositionChar", "playSoundWhenNonCand", "showPhrase", "sortByPhrase"]
if not CinBaseTextService.closemenu:
CinBaseTextService.setCandidateCursor(0)
CinBaseTextService.setCandidatePage(0)
# 大易須更換選字鍵
if CinBaseTextService.imeDirName == "chedayi":
CinBaseTextService.selKeys = "1234567890"
if not self.candselKeys == "1234567890":
self.candselKeys = "1234567890"
CinBaseTextService.TextService.setSelKeys(CinBaseTextService, self.candselKeys)
CinBaseTextService.isShowCandidates = True
CinBaseTextService.isSelKeysChanged = True
if not CinBaseTextService.emojimenumode:
CinBaseTextService.menutype = 0
menu = ["功能設定", menu_OutputSimpChinese, "功能開關", "特殊符號", "注音符號", "外語文字", "表情符號"]
CinBaseTextService.setCandidateList(menu)
else:
CinBaseTextService.menutype = 7
CinBaseTextService.setCandidateList(self.emojimenulist)
CinBaseTextService.menucandidates = CinBaseTextService.candidateList
CinBaseTextService.prevmenutypelist = []
CinBaseTextService.prevmenucandlist = []
CinBaseTextService.showmenu = True
if CinBaseTextService.showmenu:
CinBaseTextService.closemenu = False
candidates = CinBaseTextService.menucandidates
candCursor = CinBaseTextService.candidateCursor # 目前的游標位置
candCount = len(CinBaseTextService.candidateList) # 目前選字清單項目數
currentCandPageCount = math.ceil(len(candidates) / CinBaseTextService.candPerPage) # 目前的選字清單總頁數
currentCandPage = CinBaseTextService.currentCandPage # 目前的選字清單頁數
# 候選清單分頁
pagecandidates = list(self.chunks(candidates, CinBaseTextService.candPerPage))
CinBaseTextService.setCandidateList(pagecandidates[currentCandPage])
if not CinBaseTextService.isSelKeysChanged:
CinBaseTextService.setShowCandidates(True)
CinBaseTextService.resetMenuCand = False
itemName = ""
# 選單按鍵處理
if keyCode == VK_UP: # 游標上移
if (candCursor - CinBaseTextService.candPerRow) < 0:
if currentCandPage > 0:
currentCandPage -= 1
candCursor = 0
else:
if (candCursor - CinBaseTextService.candPerRow) >= 0:
candCursor = candCursor - CinBaseTextService.candPerRow
elif keyCode == VK_DOWN: # 游標下移
if (candCursor + CinBaseTextService.candPerRow) >= CinBaseTextService.candPerPage:
if (currentCandPage + 1) < currentCandPageCount:
currentCandPage += 1
candCursor = 0
else:
if (candCursor + CinBaseTextService.candPerRow) < len(pagecandidates[currentCandPage]):
candCursor = candCursor + CinBaseTextService.candPerRow
elif keyCode == VK_LEFT: # 游標左移
if candCursor > 0:
candCursor -= 1
elif keyCode == VK_RIGHT: # 游標右移
if (candCursor + 1) < candCount:
candCursor += 1
elif keyCode == VK_HOME: # Home 鍵
candCursor = 0
elif keyCode == VK_END: # End 鍵
candCursor = len(pagecandidates[currentCandPage]) - 1
elif keyCode == VK_PRIOR: # Page UP 鍵
if currentCandPage > 0:
currentCandPage -= 1
candCursor = 0
elif keyCode == VK_NEXT: # Page Down 鍵
if (currentCandPage + 1) < currentCandPageCount:
currentCandPage += 1
candCursor = 0
elif keyCode == VK_ESCAPE: # ESC 鍵
candCursor = 0
currentCandPage = 0
CinBaseTextService.showmenu = False
CinBaseTextService.emojimenumode = False
CinBaseTextService.menutype = 0
CinBaseTextService.prevmenutypelist = []
CinBaseTextService.prevmenucandlist = []
self.resetComposition(CinBaseTextService)
elif self.isInSelKeys(CinBaseTextService, charCode) and not keyEvent.isKeyDown(VK_SHIFT): # 使用選字鍵執行項目或輸出候選字
if CinBaseTextService.selKeys.index(charStr) < CinBaseTextService.candPerPage and CinBaseTextService.selKeys.index(charStr) < len(CinBaseTextService.candidateList):
candCursor = CinBaseTextService.selKeys.index(charStr)
itemName = CinBaseTextService.candidateList[candCursor]
CinBaseTextService.switchmenu = True
elif keyCode == VK_RETURN: # 按下 Enter 鍵
itemName = CinBaseTextService.candidateList[candCursor]
CinBaseTextService.switchmenu = True
elif keyCode == VK_SPACE: # 按下空白鍵
if CinBaseTextService.switchPageWithSpace and currentCandPageCount > 1:
if (currentCandPage + 1) < currentCandPageCount:
currentCandPage += 1
candCursor = 0
else:
currentCandPage = 0
candCursor = 0
else:
itemName = CinBaseTextService.candidateList[candCursor]
CinBaseTextService.switchmenu = True
elif keyCode == VK_BACK:
if CinBaseTextService.prevmenutypelist:
prevmenulist =[]
prevmenutype = len(CinBaseTextService.prevmenutypelist) - 1
prevmenulist = CinBaseTextService.prevmenutypelist[prevmenutype].split(',', 2)
CinBaseTextService.menutype = int(prevmenulist[0], 10)
CinBaseTextService.prevmenucandlist = []
CinBaseTextService.prevmenucandlist.append(int(prevmenulist[1], 10))
CinBaseTextService.prevmenucandlist.append(int(prevmenulist[2], 10))
CinBaseTextService.prevmenutypelist.remove(CinBaseTextService.prevmenutypelist[prevmenutype])
pagecandidates = self.switchMenuCand(CinBaseTextService, CinBaseTextService.menutype)
# 選單切換及執行
if CinBaseTextService.switchmenu and not itemName == "":
CinBaseTextService.switchmenu = False
if CinBaseTextService.menutype == 0 and itemName == "功能開關": # 切至功能開關頁面
CinBaseTextService.menucandidates = CinBaseTextService.smenucandidates
pagecandidates = list(self.chunks(CinBaseTextService.menucandidates, CinBaseTextService.candPerPage))
CinBaseTextService.resetMenuCand = self.switchMenuType(CinBaseTextService, 1, ["0," + str(candCursor) + "," + str(currentCandPage)])
elif CinBaseTextService.menutype == 0 and itemName == "特殊符號": # 切至特殊符號頁面
CinBaseTextService.menucandidates = CinBaseTextService.symbols.getKeyNames()
pagecandidates = list(self.chunks(CinBaseTextService.menucandidates, CinBaseTextService.candPerPage))
CinBaseTextService.resetMenuCand = self.switchMenuType(CinBaseTextService, 2, ["0," + str(candCursor) + "," + str(currentCandPage)])
elif CinBaseTextService.menutype == 0 and itemName == "注音符號": # 切至注音符號頁面
bopomofolist = []
for i in range(0x3105,0x311A):
bopomofolist.append(chr(i))
for i in range(0x3127,0x312A):
bopomofolist.append(chr(i))
for i in range(0x311A,0x3127):
bopomofolist.append(chr(i))
bopomofolist.append(chr(0x02D9))
bopomofolist.append(chr(0x02CA))
bopomofolist.append(chr(0x02C7))
bopomofolist.append(chr(0x02CB))
CinBaseTextService.menucandidates = bopomofolist
pagecandidates = list(self.chunks(CinBaseTextService.menucandidates, CinBaseTextService.candPerPage))
CinBaseTextService.resetMenuCand = self.switchMenuType(CinBaseTextService, 4, ["0," + str(candCursor) + "," + str(currentCandPage)])
elif CinBaseTextService.menutype == 0 and itemName == "外語文字": # 切至外語文字頁面
CinBaseTextService.menucandidates = CinBaseTextService.flangs.getKeyNames()
pagecandidates = list(self.chunks(CinBaseTextService.menucandidates, CinBaseTextService.candPerPage))
CinBaseTextService.resetMenuCand = self.switchMenuType(CinBaseTextService, 5, ["0," + str(candCursor) + "," + str(currentCandPage)])
elif CinBaseTextService.menutype == 0 and itemName == "表情符號": # 切至表情符號頁面
CinBaseTextService.menucandidates = self.emojimenulist
pagecandidates = list(self.chunks(CinBaseTextService.menucandidates, CinBaseTextService.candPerPage))
if not CinBaseTextService.emojimenumode:
CinBaseTextService.resetMenuCand = self.switchMenuType(CinBaseTextService, 7, ["0," + str(candCursor) + "," + str(currentCandPage)])
else:
CinBaseTextService.resetMenuCand = self.switchMenuType(CinBaseTextService, 7, [])
elif CinBaseTextService.menutype == 0: # 執行主頁面其它項目
menu = ["功能設定", menu_OutputSimpChinese, "功能開關", "特殊符號", "注音符號", "外語文字", "表情符號"]
i = menu.index(itemName)
self.onMenuCommand(CinBaseTextService, i, 0)
CinBaseTextService.resetMenuCand = self.closeMenuCand(CinBaseTextService)
elif CinBaseTextService.menutype == 1: # 執行功能開關頁面項目
i = CinBaseTextService.smenucandidates.index(itemName)
self.onMenuCommand(CinBaseTextService, i, 1)
CinBaseTextService.resetMenuCand = self.closeMenuCand(CinBaseTextService)
elif CinBaseTextService.menutype == 2: # 切至特殊符號子頁面
CinBaseTextService.menucandidates = CinBaseTextService.symbols.getCharDef(CinBaseTextService.candidateList[candCursor])
pagecandidates = list(self.chunks(CinBaseTextService.menucandidates, CinBaseTextService.candPerPage))
CinBaseTextService.resetMenuCand = self.switchMenuType(CinBaseTextService, 3, ["2," + str(candCursor) + "," + str(currentCandPage)])
elif CinBaseTextService.menutype == 3: # 執行特殊符號子頁面項目
CinBaseTextService.setCommitString(CinBaseTextService.candidateList[candCursor])
CinBaseTextService.resetMenuCand = self.closeMenuCand(CinBaseTextService)
elif CinBaseTextService.menutype == 4: # 執行注音符號頁面項目
CinBaseTextService.setCommitString(CinBaseTextService.candidateList[candCursor])
CinBaseTextService.resetMenuCand = self.closeMenuCand(CinBaseTextService)
elif CinBaseTextService.menutype == 5: # 切至外語文字子頁面
CinBaseTextService.menucandidates = CinBaseTextService.flangs.getCharDef(CinBaseTextService.candidateList[candCursor])
pagecandidates = list(self.chunks(CinBaseTextService.menucandidates, CinBaseTextService.candPerPage))
CinBaseTextService.resetMenuCand = self.switchMenuType(CinBaseTextService, 6, ["5," + str(candCursor) + "," + str(currentCandPage)])
elif CinBaseTextService.menutype == 6: # 執行外語文字子頁面項目
CinBaseTextService.setCommitString(CinBaseTextService.candidateList[candCursor])
CinBaseTextService.resetMenuCand = self.closeMenuCand(CinBaseTextService)
elif CinBaseTextService.menutype == 7: # 切換至表情符號分類頁面
menutype = 8
i = self.emojimenulist.index(CinBaseTextService.candidateList[candCursor])
if i == 0:
CinBaseTextService.emojitype = 0
CinBaseTextService.menucandidates = self.emoji.emoticons_keynames
elif i == 1:
CinBaseTextService.emojitype = 1
CinBaseTextService.menucandidates = self.emoji.pictographs_keynames
elif i == 2:
CinBaseTextService.emojitype = 2
CinBaseTextService.menucandidates = self.emoji.miscellaneous_keynames
elif i == 3:
CinBaseTextService.emojitype = 3
CinBaseTextService.menucandidates = self.emoji.dingbats_keynames
elif i == 4:
CinBaseTextService.emojitype = 4
CinBaseTextService.menucandidates = self.emoji.transport_keynames
elif i == 5:
CinBaseTextService.emojitype = 5
CinBaseTextService.menucandidates = self.emoji.modifiercolor
menutype = 9
pagecandidates = list(self.chunks(CinBaseTextService.menucandidates, CinBaseTextService.candPerPage))
CinBaseTextService.resetMenuCand = self.switchMenuType(CinBaseTextService, menutype, ["7," + str(candCursor) + "," + str(currentCandPage)])
elif CinBaseTextService.menutype == 8: # 切換至表情符號分類子頁面
if CinBaseTextService.emojitype == 0:
CinBaseTextService.menucandidates = self.emoji.getCharDef("emoticons", CinBaseTextService.candidateList[candCursor])
elif CinBaseTextService.emojitype == 1:
CinBaseTextService.menucandidates = self.emoji.getCharDef("pictographs", CinBaseTextService.candidateList[candCursor])
elif CinBaseTextService.emojitype == 2:
CinBaseTextService.menucandidates = self.emoji.getCharDef("miscellaneous", CinBaseTextService.candidateList[candCursor])
elif CinBaseTextService.emojitype == 3:
CinBaseTextService.menucandidates = self.emoji.getCharDef("dingbats", CinBaseTextService.candidateList[candCursor])
elif CinBaseTextService.emojitype == 4:
CinBaseTextService.menucandidates = self.emoji.getCharDef("transport", CinBaseTextService.candidateList[candCursor])
pagecandidates = list(self.chunks(CinBaseTextService.menucandidates, CinBaseTextService.candPerPage))
CinBaseTextService.resetMenuCand = self.switchMenuType(CinBaseTextService, 9, ["8," + str(candCursor) + "," + str(currentCandPage)])
elif CinBaseTextService.menutype == 9: # 執行表情符號分類子頁面項目
CinBaseTextService.setCommitString(CinBaseTextService.candidateList[candCursor])
CinBaseTextService.resetMenuCand = self.closeMenuCand(CinBaseTextService)
if CinBaseTextService.prevmenucandlist:
candCursor = CinBaseTextService.prevmenucandlist[0]
currentCandPage = CinBaseTextService.prevmenucandlist[1]
CinBaseTextService.prevmenucandlist = []
if CinBaseTextService.resetMenuCand:
candCursor = 0
currentCandPage = 0
# 更新選字視窗游標位置
CinBaseTextService.setCandidateCursor(candCursor)
CinBaseTextService.setCandidatePage(currentCandPage)
CinBaseTextService.setCandidateList(pagecandidates[currentCandPage])
# 按鍵處理 ----------------------------------------------------------------
# 某些狀況須要特別處理或忽略
# 如果輸入編輯區為空且選單未開啟過,不處理 Enter 及 Backspace 鍵
if not CinBaseTextService.isComposing() and CinBaseTextService.closemenu and not CinBaseTextService.multifunctionmode:
if keyCode == VK_RETURN or keyCode == VK_BACK:
return False
# 若按下 Shift 鍵,且沒有按下其它的按鍵
if keyEvent.isKeyDown(VK_SHIFT) and not keyEvent.isPrintableChar():
return False
# 若按下 Ctrl 鍵
if keyEvent.isKeyDown(VK_CONTROL):
# 若按下的是指定的符號鍵,輸入法需要處理此按鍵
if self.isCtrlSymbolsChar(keyCode):
if CinBaseTextService.msymbols.isInCharDef(charStr) and CinBaseTextService.closemenu and not CinBaseTextService.multifunctionmode:
if not CinBaseTextService.ctrlsymbolsmode:
CinBaseTextService.ctrlsymbolsmode = True
CinBaseTextService.compositionChar = charStr
elif CinBaseTextService.msymbols.isInCharDef(CinBaseTextService.compositionChar + charStr):
CinBaseTextService.compositionChar += charStr
candidates = CinBaseTextService.msymbols.getCharDef(CinBaseTextService.compositionChar)
CinBaseTextService.setCompositionString(candidates[0])
# 大易須換回選字鍵
if not CinBaseTextService.showmenu:
if CinBaseTextService.imeDirName == "chedayi":
CinBaseTextService.selKeys = "'[]-\\"
if not self.candselKeys == "0123456789":
self.candselKeys = "0123456789"
CinBaseTextService.TextService.setSelKeys(CinBaseTextService, self.candselKeys)
CinBaseTextService.isSelKeysChanged = True
# 按下的鍵為 CIN 內有定義的字根
if CinBaseTextService.cin.isInKeyName(charStrLow) and CinBaseTextService.closemenu and not CinBaseTextService.multifunctionmode and not keyEvent.isKeyDown(VK_CONTROL) and not CinBaseTextService.ctrlsymbolsmode and not CinBaseTextService.dayisymbolsmode:
# 若按下 Shift 鍵
if keyEvent.isKeyDown(VK_SHIFT) and CinBaseTextService.langMode == CHINESE_MODE and not CinBaseTextService.imeDirName == "cheez":
CommitStr = charStr
# 使用 Shift 鍵做全形輸入 (easy symbol input)
# 這裡的 easy symbol input,是定義在 swkb.dat 設定檔中的符號
if CinBaseTextService.easySymbolsWithShift and self.isLetterChar(keyCode):
if CinBaseTextService.swkb.isInCharDef(charStr.upper()):
candidates = CinBaseTextService.swkb.getCharDef(charStr.upper())
CommitStr = candidates[0]
candidates = []
else: # 不在快速符號表裡
if CinBaseTextService.shapeMode == FULLSHAPE_MODE: # 全形模式
CommitStr = self.charCodeToFullshape(CinBaseTextService, charCode, keyCode)
else:
if CinBaseTextService.outputSmallLetterWithShift:
CommitStr = charStr.upper() if CinBaseTextService.capsStates else charStr.lower()
CinBaseTextService.setCommitString(CommitStr)
self.resetComposition(CinBaseTextService)
# 如果啟用 Shift 輸入全形標點
elif CinBaseTextService.fullShapeSymbols:
if charStr == '*' and CinBaseTextService.supportWildcard and CinBaseTextService.selWildcardChar == charStr: # 如果按鍵及萬用字元為*
CinBaseTextService.compositionChar += '*'
keyname = '*'
CinBaseTextService.setCompositionString(CinBaseTextService.compositionString + keyname)
# 如果是符號或數字,將字串轉為全形再輸出
elif self.isSymbolsChar(keyCode) or self.isNumberChar(keyCode):
if CinBaseTextService.fsymbols.isInCharDef(charStr):
CinBaseTextService.compositionChar = charStr
fullShapeSymbolsList = CinBaseTextService.fsymbols.getCharDef(CinBaseTextService.compositionChar)
CinBaseTextService.setCompositionString(fullShapeSymbolsList[0])
CinBaseTextService.setCompositionCursor(len(CinBaseTextService.compositionString))
else:
if CinBaseTextService.cin.isInKeyName(charStrLow): # 如果是 CIN 所定義的字根
CinBaseTextService.compositionChar = charStrLow
keyname = CinBaseTextService.cin.getKeyName(charStrLow)
CinBaseTextService.setCompositionString(keyname)
CinBaseTextService.setCompositionCursor(len(CinBaseTextService.compositionString))
else:
if CinBaseTextService.shapeMode == FULLSHAPE_MODE: # 全形模式
CommitStr = self.SymbolscharCodeToFullshape(charCode)
CinBaseTextService.setCommitString(CommitStr)
self.resetComposition(CinBaseTextService)
else: #如果是字母
if CinBaseTextService.shapeMode == FULLSHAPE_MODE: # 全形模式
CommitStr = self.charCodeToFullshape(CinBaseTextService, charCode, keyCode)
else:
if CinBaseTextService.outputSmallLetterWithShift:
CommitStr = charStr.upper() if CinBaseTextService.capsStates else charStr.lower()
CinBaseTextService.setCommitString(CommitStr)
self.resetComposition(CinBaseTextService)
else: # 如果未使用 SHIFT 輸入快速符號或全形標點
if charStr == '*' and CinBaseTextService.supportWildcard and CinBaseTextService.selWildcardChar == charStr: # 如果按鍵及萬用字元為*
CinBaseTextService.compositionChar += '*'
keyname = '*'
CinBaseTextService.setCompositionString(CinBaseTextService.compositionString + keyname)
else:
if CinBaseTextService.cin.isInKeyName(charStrLow) and (self.isSymbolsChar(keyCode) or self.isNumberChar(keyCode)): # 如果是 CIN 所定義的字根
CinBaseTextService.compositionChar = charStrLow
keyname = CinBaseTextService.cin.getKeyName(charStrLow)
CinBaseTextService.setCompositionString(keyname)
CinBaseTextService.setCompositionCursor(len(CinBaseTextService.compositionString))
else:
if CinBaseTextService.shapeMode == FULLSHAPE_MODE: # 全形模式
# 如果是符號或數字,將字串轉為全形再輸出
if self.isSymbolsChar(keyCode) or self.isNumberChar(keyCode):
CommitStr = self.SymbolscharCodeToFullshape(charCode)
else:
CommitStr = self.charCodeToFullshape(CinBaseTextService, charCode, keyCode)
else:
if self.isLetterChar(keyCode) and CinBaseTextService.outputSmallLetterWithShift:
CommitStr = charStr.upper() if CinBaseTextService.capsStates else charStr.lower()
CinBaseTextService.setCommitString(CommitStr)
self.resetComposition(CinBaseTextService)
else: # 若沒按下 Shift 鍵
# 如果是英文全形模式,將字串轉為全形再輸出
if CinBaseTextService.shapeMode == FULLSHAPE_MODE and CinBaseTextService.langMode == ENGLISH_MODE:
# 如果是符號或數字,將字串轉為全形再輸出
if self.isSymbolsChar(keyCode) or self.isNumberChar(keyCode):
CommitStr = self.SymbolscharCodeToFullshape(charCode)
else:
CommitStr = self.charCodeToFullshape(CinBaseTextService, charCode, keyCode)
CinBaseTextService.setCommitString(CommitStr)
self.resetComposition(CinBaseTextService)
else: # 送出 CIN 所定義的字根
if not CinBaseTextService.directShowCand and CinBaseTextService.showCandidates and self.isInSelKeys(CinBaseTextService, charCode):
# 不送出 CIN 所定義的字根
CinBaseTextService.compositionChar = CinBaseTextService.compositionChar
elif CinBaseTextService.imeDirName == "chedayi" and CinBaseTextService.showCandidates and self.isInSelKeys(CinBaseTextService, charCode):
# 不送出 CIN 所定義的字根
CinBaseTextService.compositionChar = CinBaseTextService.compositionChar
else:
# 如果是注音輸入法
if CinBaseTextService.imeDirName == "chephonetic":
if not CinBaseTextService.keyboardLayout == 0 and not chr(charCode).lower() in CinBaseTextService.kbtypelist[CinBaseTextService.keyboardLayout]:
CinBaseTextService.compositionChar = CinBaseTextService.compositionChar
else:
if len(CinBaseTextService.compositionChar) > 0:
CinBaseTextService.updateCompositionChar(charStrLow)
else:
CinBaseTextService.compositionChar += charStrLow
keyname = CinBaseTextService.cin.getKeyName(charStrLow)
CinBaseTextService.setCompositionString(CinBaseTextService.compositionString + keyname)
CinBaseTextService.setCompositionCursor(len(CinBaseTextService.compositionString))
else:
CinBaseTextService.compositionChar += charStrLow
keyname = CinBaseTextService.cin.getKeyName(charStrLow)
CinBaseTextService.setCompositionString(CinBaseTextService.compositionString + keyname)
CinBaseTextService.setCompositionCursor(len(CinBaseTextService.compositionString))
# 按下的鍵不存在於 CIN 所定義的字根
elif not CinBaseTextService.cin.isInKeyName(charStrLow) and CinBaseTextService.closemenu and not CinBaseTextService.multifunctionmode and not keyEvent.isKeyDown(VK_CONTROL) and not CinBaseTextService.ctrlsymbolsmode and not CinBaseTextService.dayisymbolsmode:
# 若按下 Shift 鍵
if keyEvent.isKeyDown(VK_SHIFT) and CinBaseTextService.langMode == CHINESE_MODE:
# 如果停用 Shift 輸入全形標點
if not CinBaseTextService.fullShapeSymbols:
# 如果是全形模式,將字串轉為全形再輸出
if CinBaseTextService.shapeMode == FULLSHAPE_MODE:
if charStr == '*' and CinBaseTextService.supportWildcard and CinBaseTextService.selWildcardChar == charStr: # 如果按鍵及萬用字元為*
CinBaseTextService.compositionChar += '*'
keyname = '*'
CinBaseTextService.setCompositionString(CinBaseTextService.compositionString + keyname)
else:
# 如果是符號或數字,將字串轉為全形再輸出
if self.isSymbolsChar(keyCode) or self.isNumberChar(keyCode):
CommitStr = self.SymbolscharCodeToFullshape(charCode)
else:
CommitStr = self.charCodeToFullshape(CinBaseTextService, charCode, keyCode)
CinBaseTextService.setCommitString(CommitStr)
self.resetComposition(CinBaseTextService)
else: # 半形模式直接輸出不作處理
if charStr == '*' and CinBaseTextService.supportWildcard and CinBaseTextService.selWildcardChar == charStr: # 如果按鍵及萬用字元為*
CinBaseTextService.compositionChar += '*'
keyname = '*'
CinBaseTextService.setCompositionString(CinBaseTextService.compositionString + keyname)
else:
CommitStr = charStr
if self.isLetterChar(keyCode) and CinBaseTextService.outputSmallLetterWithShift:
CommitStr = charStr.upper() if CinBaseTextService.capsStates else charStr.lower()
CinBaseTextService.setCommitString(CommitStr)
self.resetComposition(CinBaseTextService)
else: # 如果啟用 Shift 輸入全形標點
# 如果是符號或數字鍵,將字串轉為全形再輸出
if self.isSymbolsChar(keyCode) or self.isNumberChar(keyCode):
# 如果該鍵有定義在 fsymbols
if CinBaseTextService.fsymbols.isInCharDef(charStr):
if charStr == '*' and CinBaseTextService.supportWildcard and CinBaseTextService.selWildcardChar == charStr: # 如果按鍵及萬用字元為*
CinBaseTextService.compositionChar += '*'
keyname = '*'
CinBaseTextService.setCompositionString(CinBaseTextService.compositionString + keyname)
else:
CinBaseTextService.compositionChar = charStr
fullShapeSymbolsList = CinBaseTextService.fsymbols.getCharDef(CinBaseTextService.compositionChar)
CinBaseTextService.setCompositionString(fullShapeSymbolsList[0])
CinBaseTextService.setCompositionCursor(len(CinBaseTextService.compositionString))
else: # 沒有定義在 fsymbols 裡
if charStr == '*' and CinBaseTextService.supportWildcard and CinBaseTextService.selWildcardChar == charStr: # 如果按鍵及萬用字元為*
CinBaseTextService.compositionChar += '*'
keyname = '*'
CinBaseTextService.setCompositionString(CinBaseTextService.compositionString + keyname)
else:
if self.isSymbolsChar(keyCode) or self.isNumberChar(keyCode):
CommitStr = self.SymbolscharCodeToFullshape(charCode)
else:
CommitStr = self.charCodeToFullshape(CinBaseTextService, charCode, keyCode)
CinBaseTextService.setCommitString(CommitStr)
self.resetComposition(CinBaseTextService)
else: # 若沒按下 Shift 鍵
# 如果是全形模式,將字串轉為全形再輸出
if CinBaseTextService.shapeMode == FULLSHAPE_MODE and len(CinBaseTextService.compositionChar) == 0:
if self.isSymbolsChar(keyCode) or self.isNumberChar(keyCode):
CommitStr = self.SymbolscharCodeToFullshape(charCode)
else:
CommitStr = self.charCodeToFullshape(CinBaseTextService, charCode, keyCode)
CinBaseTextService.setCommitString(CommitStr)
self.resetComposition(CinBaseTextService)
if CinBaseTextService.langMode == CHINESE_MODE and len(CinBaseTextService.compositionChar) >= 1 and not CinBaseTextService.multifunctionmode:
CinBaseTextService.showmenu = False
if not CinBaseTextService.directShowCand:
if not CinBaseTextService.lastCompositionCharLength == len(CinBaseTextService.compositionChar):
CinBaseTextService.lastCompositionCharLength = len(CinBaseTextService.compositionChar)
CinBaseTextService.isShowCandidates = False
CinBaseTextService.setShowCandidates(False)
# 按下 ESC 鍵
if keyCode == VK_ESCAPE and (CinBaseTextService.showCandidates or len(CinBaseTextService.compositionChar) > 0):
CinBaseTextService.lastCompositionCharLength = 0
if not CinBaseTextService.directShowCand:
CinBaseTextService.isShowCandidates = False
self.resetComposition(CinBaseTextService)
# 刪掉一個字根
if keyCode == VK_BACK:
if CinBaseTextService.compositionString != "":
if CinBaseTextService.cin.isInKeyName(CinBaseTextService.compositionChar[len(CinBaseTextService.compositionChar)-1:]):
keyLength = len(CinBaseTextService.cin.getKeyName(CinBaseTextService.compositionChar[len(CinBaseTextService.compositionChar)-1:]))
else:
keyLength = 1
CinBaseTextService.setCompositionString(CinBaseTextService.compositionString[:-keyLength])
CinBaseTextService.compositionChar = CinBaseTextService.compositionChar[:-1]
CinBaseTextService.lastCompositionCharLength = CinBaseTextService.lastCompositionCharLength - 1
CinBaseTextService.setCandidateCursor(0)
CinBaseTextService.setCandidatePage(0)
CinBaseTextService.wildcardcandidates = []
CinBaseTextService.wildcardpagecandidates = []
if not CinBaseTextService.directShowCand:
CinBaseTextService.isShowCandidates = False
CinBaseTextService.setShowCandidates(False)
if CinBaseTextService.compositionString == '':
self.resetComposition(CinBaseTextService)
# 組字字根超過最大值
if len(CinBaseTextService.compositionChar) > CinBaseTextService.maxCharLength:
if CinBaseTextService.cin.isInKeyName(CinBaseTextService.compositionChar[len(CinBaseTextService.compositionChar)-1:]):
keyLength = len(CinBaseTextService.cin.getKeyName(CinBaseTextService.compositionChar[len(CinBaseTextService.compositionChar)-1:]))
else:
keyLength = 1
CinBaseTextService.setCompositionString(CinBaseTextService.compositionString[:-keyLength])
CinBaseTextService.compositionChar = CinBaseTextService.compositionChar[:-1]
if CinBaseTextService.cin.isInCharDef(CinBaseTextService.compositionChar) and CinBaseTextService.closemenu and not CinBaseTextService.ctrlsymbolsmode:
candidates = CinBaseTextService.cin.getCharDef(CinBaseTextService.compositionChar)
if CinBaseTextService.sortByPhrase and candidates:
candidates = self.sortByPhrase(CinBaseTextService, copy.deepcopy(candidates))
elif CinBaseTextService.imeDirName == "chepinyin" and CinBaseTextService.cinFileList[CinBaseTextService.cfg.selCinType] == "thpinyin.cin":
if CinBaseTextService.cin.isInCharDef(CinBaseTextService.compositionChar + "1") and CinBaseTextService.closemenu and not CinBaseTextService.ctrlsymbolsmode:
candidates = CinBaseTextService.cin.getCharDef(CinBaseTextService.compositionChar + '1')
if CinBaseTextService.sortByPhrase and candidates:
candidates = self.sortByPhrase(CinBaseTextService, copy.deepcopy(candidates))
elif CinBaseTextService.fullShapeSymbols and CinBaseTextService.fsymbols.isInCharDef(CinBaseTextService.compositionChar) and CinBaseTextService.closemenu:
candidates = CinBaseTextService.fsymbols.getCharDef(CinBaseTextService.compositionChar)
elif CinBaseTextService.msymbols.isInCharDef(CinBaseTextService.compositionChar) and CinBaseTextService.closemenu and CinBaseTextService.ctrlsymbolsmode:
candidates = CinBaseTextService.msymbols.getCharDef(CinBaseTextService.compositionChar)
elif CinBaseTextService.dayisymbolsmode and CinBaseTextService.closemenu:
if CinBaseTextService.dsymbols.isInCharDef(CinBaseTextService.compositionChar[1:]):
candidates = CinBaseTextService.dsymbols.getCharDef(CinBaseTextService.compositionChar[1:])
CinBaseTextService.setCompositionString(candidates[0])
elif CinBaseTextService.supportWildcard and CinBaseTextService.selWildcardChar in CinBaseTextService.compositionChar and CinBaseTextService.closemenu:
if CinBaseTextService.wildcardcandidates and CinBaseTextService.wildcardcompositionChar == CinBaseTextService.compositionChar:
candidates = CinBaseTextService.wildcardcandidates
else:
CinBaseTextService.setCandidateCursor(0)
CinBaseTextService.setCandidatePage(0)
CinBaseTextService.wildcardcandidates = CinBaseTextService.cin.getWildcardCharDefs(CinBaseTextService.compositionChar, CinBaseTextService.selWildcardChar, CinBaseTextService.candMaxItems)
if CinBaseTextService.imeDirName == "chepinyin" and CinBaseTextService.cinFileList[CinBaseTextService.cfg.selCinType] == "thpinyin.cin":
if not CinBaseTextService.wildcardcandidates:
CinBaseTextService.wildcardcandidates = CinBaseTextService.cin.getWildcardCharDefs(CinBaseTextService.compositionChar + "1", CinBaseTextService.selWildcardChar, CinBaseTextService.candMaxItems)
CinBaseTextService.wildcardpagecandidates = []
CinBaseTextService.wildcardcompositionChar = CinBaseTextService.compositionChar
candidates = CinBaseTextService.wildcardcandidates
CinBaseTextService.isWildcardChardefs = True
if CinBaseTextService.sortByPhrase and candidates:
candidates = self.sortByPhrase(CinBaseTextService, copy.deepcopy(candidates))
if CinBaseTextService.langMode == CHINESE_MODE and len(CinBaseTextService.compositionChar) >= 1:
# 候選清單處理
if candidates and not CinBaseTextService.phrasemode:
if not CinBaseTextService.directShowCand:
# EndKey 處理 (拼音、注音)
if CinBaseTextService.useEndKey:
if charStr in CinBaseTextService.endKeyList:
if not CinBaseTextService.isShowCandidates:
CinBaseTextService.isShowCandidates = True
CinBaseTextService.canUseSelKey = False
else:
CinBaseTextService.canUseSelKey = True
else:
if CinBaseTextService.isShowCandidates:
CinBaseTextService.canUseSelKey = True
# 字滿及符號處理 (大易、注音、輕鬆)
if CinBaseTextService.autoShowCandWhenMaxChar or CinBaseTextService.dayisymbolsmode:
if len(CinBaseTextService.compositionChar) == CinBaseTextService.maxCharLength or CinBaseTextService.dayisymbolsmode:
if len(candidates) == 1 and CinBaseTextService.directCommitString:
commitStr = candidates[0]
CinBaseTextService.lastCommitString = commitStr
# 如果使用萬用字元解碼
if CinBaseTextService.isWildcardChardefs:
if not CinBaseTextService.hidePromptMessages:
messagestr = CinBaseTextService.cin.getCharEncode(commitStr)
CinBaseTextService.showMessage(messagestr, 5)
CinBaseTextService.wildcardcandidates = []
CinBaseTextService.wildcardpagecandidates = []
CinBaseTextService.isWildcardChardefs = False
# 如果使用打繁出簡,就轉成簡體中文
if CinBaseTextService.outputSimpChinese:
commitStr = CinBaseTextService.opencc.convert(commitStr)
CinBaseTextService.setCommitString(commitStr)
if CinBaseTextService.showPhrase:
CinBaseTextService.phrasemode = True
self.resetComposition(CinBaseTextService)
candCursor = 0
currentCandPage = 0
CinBaseTextService.isShowCandidates = False
CinBaseTextService.canSetCommitString = True
else:
if not CinBaseTextService.isShowCandidates:
CinBaseTextService.isShowCandidates = True
CinBaseTextService.canUseSelKey = False
else:
if not CinBaseTextService.imeDirName == "chephonetic":