@@ -479,6 +479,8 @@ <h2>查碼練習</h2>
479479 let currentCodemap = { } ;
480480 let currentReverseCodemap = { } ;
481481
482+ const codeKeys = "abcdefghijklmnopqrstuvwxyz;'./," ;
483+
482484 const keyname_map_upper = {
483485 'a' : 'A' , 'b' : 'B' , 'c' : 'C' , 'd' : 'D' , 'e' : 'E' , 'f' : 'F' , 'g' : 'G' ,
484486 'h' : 'H' , 'i' : 'I' , 'j' : 'J' , 'k' : 'K' , 'l' : 'L' , 'm' : 'M' , 'n' : 'N' ,
@@ -498,7 +500,6 @@ <h2>查碼練習</h2>
498500 'shift' : 'Shift' , 'enter' : 'Enter' , 'backspace' : '刪除鍵' ,
499501 } ;
500502
501- // 中文模式下,長按 Shift 顯示的對應字元(全數改為半形)
502503 const keyname_map_chinese_shifted = {
503504 '1' : '!' , '2' : '@' , '3' : '#' , '4' : '$' , '5' : '%' , '6' : '^' , '7' : '&' , '8' : '*' , '9' : '(' , '0' : ')' ,
504505 'q' : 'Q' , 'w' : 'W' , 'e' : 'E' , 'r' : 'R' , 't' : 'T' , 'y' : 'Y' , 'u' : 'U' , 'i' : 'I' , 'o' : 'O' , 'p' : 'P' ,
@@ -508,7 +509,6 @@ <h2>查碼練習</h2>
508509 ',' : '<' , '.' : '>' , '/' : '?' ,
509510 } ;
510511
511- // 英文模式下,長按 Shift 顯示的對應字元(全數改為半形)
512512 const keyname_map_english_shifted = {
513513 '1' : '!' , '2' : '@' , '3' : '#' , '4' : '$' , '5' : '%' , '6' : '^' , '7' : '&' , '8' : '*' , '9' : '(' , '0' : ')' ,
514514 'q' : 'Q' , 'w' : 'W' , 'e' : 'E' , 'r' : 'R' , 't' : 'T' , 'y' : 'Y' , 'u' : 'U' , 'i' : 'I' , 'o' : 'O' , 'p' : 'P' ,
@@ -615,11 +615,9 @@ <h2>查碼練習</h2>
615615 }
616616 resetInputState ( ) ;
617617 updateModeDisplay ( ) ;
618- // 重新載入碼表後,更新查碼練習區
619618 updatePhraseLookup ( ) ;
620619 }
621620
622- // 模式切換單選鈕事件監聽
623621 modeRadioButtons . forEach ( radio => {
624622 radio . addEventListener ( 'change' , ( event ) => {
625623 switchInputMethod ( event . target . value ) ;
@@ -646,23 +644,8 @@ <h2>查碼練習</h2>
646644 element . focus ( ) ;
647645 }
648646 }
649-
650- // --- 處理長按 Shift 虛擬鍵盤點擊的輔助函數 ---
651- function handleShiftedVirtualInput ( code ) {
652- let outputChar = '' ;
653- if ( isEnglishMode ) {
654- outputChar = keyname_map_english_shifted [ code ] ;
655- } else {
656- outputChar = keyname_map_chinese_shifted [ code ] ;
657- }
658- if ( outputChar ) {
659- insertTextAtCursor ( textOutput , outputChar ) ;
660- return true ;
661- }
662- return false ;
663- }
664647
665- // --- 虛擬鍵盤點擊事件 ---
648+ // --- 虛擬鍵盤點擊事件處理 ---
666649 keyboardContainer . addEventListener ( 'click' , ( event ) => {
667650 const key = event . target . closest ( '.key' ) ;
668651 if ( ! key ) return ;
@@ -681,50 +664,51 @@ <h2>查碼練習</h2>
681664 return ;
682665 }
683666
667+ // 處理長按Shift模式下的輸入
684668 if ( isLongPressActive ) {
685- if ( handleShiftedVirtualInput ( code ) ) {
669+ let outputChar = isEnglishMode ? keyname_map_english_shifted [ code ] : keyname_map_chinese_shifted [ code ] ;
670+ if ( outputChar ) {
671+ insertTextAtCursor ( textOutput , outputChar ) ;
672+ resetInputState ( ) ; // 長按Shift後輸入應該清空編碼
673+ updatePhraseLookup ( ) ;
686674 return ;
687675 }
688676 }
677+
678+ // 處理一般點擊輸入
679+ const char = keyname_map_lower [ code ] ;
680+ if ( char ) {
681+ processInput ( char ) ;
682+ }
689683
690684 if ( code === '<' ) {
691685 handlePageChange ( 'previous' ) ;
692686 } else if ( code === '>' ) {
693687 handlePageChange ( 'next' ) ;
694688 } else if ( code === 'backspace' ) {
695- deleteTextAtCursor ( textOutput ) ;
696- return ;
689+ processInput ( 'backspace' ) ;
697690 } else if ( code === 'enter' ) {
698- insertTextAtCursor ( textOutput , '\n' ) ;
699- return ;
691+ processInput ( 'enter' ) ;
700692 }
701-
693+ } ) ;
694+
695+ // --- 統一處理鍵盤輸入的核心函數 ---
696+ function processInput ( char ) {
702697 if ( isEnglishMode ) {
703- // Pass event.key to handleEnglishInput
704- const char = event . key ;
705- if ( char ) {
706- handleEnglishInput ( char ) ;
707- } else {
708- // Fallback for function keys without a single character
709- handleEnglishInput ( code ) ;
710- }
698+ handleEnglishInput ( char ) ;
711699 } else {
712- // Pass event.key to handleChineseInput
713- const char = event . key ;
714- if ( char ) {
715- handleChineseInput ( char ) ;
716- } else {
717- handleChineseInput ( code ) ;
718- }
700+ handleChineseInput ( char ) ;
719701 }
720- } ) ;
721-
702+ }
703+
704+ function isCodeKey ( char ) {
705+ return codeKeys . includes ( char . toLowerCase ( ) ) ;
706+ }
707+
722708 // --- 處理中文模式輸入的核心函數 ---
723709 function handleChineseInput ( char ) {
724- const isCodeKey = char . match ( / ^ [ a - z A - Z ; ' . / , ] $ / ) || char . match ( / ^ [ 0 - 9 ] $ / ) ;
725-
726- // 處理刪除、換行、清空等功能鍵
727- if ( char === 'Backspace' || char === 'backspace' ) {
710+ // 處理功能鍵
711+ if ( char === 'backspace' || char === 'Backspace' ) {
728712 if ( currentCode . length > 0 ) {
729713 currentCode = currentCode . slice ( 0 , - 1 ) ;
730714 updateStateAndDisplay ( ) ;
@@ -734,31 +718,31 @@ <h2>查碼練習</h2>
734718 }
735719 return ;
736720 }
737- if ( char === 'Enter ' || char === 'enter ' ) {
721+ if ( char === 'enter ' || char === 'Enter ' ) {
738722 insertTextAtCursor ( textOutput , '\n' ) ;
723+ resetInputState ( ) ;
739724 updatePhraseLookup ( ) ;
740725 return ;
741726 }
742- if ( char === 'Escape ' || char === 'escape ' ) {
727+ if ( char === 'escape ' || char === 'Escape ' ) {
743728 resetInputState ( ) ;
744729 updatePhraseLookup ( ) ;
745730 return ;
746731 }
747732
748- // 處理數字鍵選字
733+ // 處理數字鍵選字或直出
749734 if ( char . match ( / ^ [ 0 - 9 ] $ / ) ) {
750- if ( currentCode . length > 0 ) {
735+ if ( currentCandidates . length > 0 ) {
751736 const num = char === '0' ? 10 : parseInt ( char , 10 ) ;
752737 selectCandidate ( num - 1 ) ;
753738 } else {
754- // 如果沒有編碼輸入,直接插入數字
755739 insertTextAtCursor ( textOutput , char ) ;
756740 updatePhraseLookup ( ) ;
757741 }
758742 return ;
759743 }
760744
761- // 處理空白鍵選字
745+ // 處理空白鍵選字或直出
762746 if ( char === ' ' || char === 'Space' ) {
763747 if ( currentCandidates . length > 0 ) {
764748 selectCandidate ( 0 ) ;
@@ -770,45 +754,42 @@ <h2>查碼練習</h2>
770754 }
771755
772756 // 處理正常的編碼輸入
773- if ( isCodeKey ) {
774- const lowerChar = char . toLowerCase ( ) ;
757+ if ( isCodeKey ( char ) ) {
775758 if ( currentCode . length < MAX_CODE_LENGTH ) {
776- currentCode += lowerChar ;
759+ currentCode += char ;
777760 } else {
778761 // 如果已達最大長度,先選字再輸入新編碼
779762 if ( currentCandidates . length > 0 ) {
780763 selectCandidate ( 0 ) ;
781764 }
782- currentCode = lowerChar ;
765+ currentCode = char ;
783766 }
784767 updateStateAndDisplay ( ) ;
785768 } else {
786- // 處理所有其他非編碼字元(如標點符號、特殊符號等)
769+ // 如果輸入的不是編碼鍵,則直接輸出
787770 if ( currentCode . length > 0 ) {
788771 if ( currentCandidates . length > 0 ) {
789772 selectCandidate ( 0 ) ;
790773 }
791- resetInputState ( ) ;
792774 }
793775 insertTextAtCursor ( textOutput , char ) ;
794776 updatePhraseLookup ( ) ;
795777 }
796778 }
797779
798- // --- 處理英文模式輸入的新函數 ---
780+ // --- 處理英文模式輸入的函數 ---
799781 function handleEnglishInput ( char ) {
800- // 處理功能鍵
801- if ( char === 'Backspace' || char === 'backspace' ) {
782+ if ( char === 'backspace' || char === 'Backspace' ) {
802783 deleteTextAtCursor ( textOutput ) ;
803784 updatePhraseLookup ( ) ;
804785 return ;
805786 }
806- if ( char === 'Enter ' || char === 'enter ' ) {
787+ if ( char === 'enter ' || char === 'Enter ' ) {
807788 insertTextAtCursor ( textOutput , '\n' ) ;
808789 updatePhraseLookup ( ) ;
809790 return ;
810791 }
811- if ( char === 'Escape ' || char === 'escape ' ) {
792+ if ( char === 'escape ' || char === 'Escape ' ) {
812793 resetInputState ( ) ;
813794 updatePhraseLookup ( ) ;
814795 return ;
@@ -819,7 +800,6 @@ <h2>查碼練習</h2>
819800 return ;
820801 }
821802
822- // 處理英文字母和數字、符號
823803 if ( char . length === 1 ) {
824804 insertTextAtCursor ( textOutput , char ) ;
825805 updatePhraseLookup ( ) ;
@@ -852,7 +832,7 @@ <h2>查碼練習</h2>
852832 if ( currentCandidates . length === 1 ) {
853833 insertTextAtCursor ( textOutput , currentCandidates [ 0 ] ) ;
854834 resetInputState ( ) ;
855- updatePhraseLookup ( ) ; // 在自動選字後更新比對
835+ updatePhraseLookup ( ) ;
856836 return ;
857837 } else if ( currentCandidates . length === 0 ) {
858838 resetInputState ( ) ;
@@ -897,7 +877,7 @@ <h2>查碼練習</h2>
897877 if ( selectedCandidate ) {
898878 insertTextAtCursor ( textOutput , selectedCandidate ) ;
899879 resetInputState ( ) ;
900- updatePhraseLookup ( ) ; // 在選字後更新比對
880+ updatePhraseLookup ( ) ;
901881 }
902882 }
903883
@@ -940,7 +920,6 @@ <h2>查碼練習</h2>
940920 }
941921
942922 // --- 實體鍵盤事件處理 ---
943- // 取得按鍵代碼的輔助函數,使用 event.code 來確保物理鍵的一致性
944923 function getKeyCode ( event ) {
945924 const code = event . code ;
946925 if ( code . startsWith ( 'Key' ) ) {
@@ -965,9 +944,7 @@ <h2>查碼練習</h2>
965944 }
966945 }
967946
968- // keydown 事件處理
969947 document . addEventListener ( 'keydown' , ( event ) => {
970- // 允許 Ctrl/Meta 鍵組合使用
971948 if ( event . ctrlKey || event . metaKey ) {
972949 return ;
973950 }
@@ -980,19 +957,6 @@ <h2>查碼練習</h2>
980957 }
981958 }
982959
983- // 處理 Shift + < 或 Shift + > 的翻頁功能
984- if ( event . shiftKey && ( event . key === '<' || event . key === '>' ) ) {
985- if ( ! isEnglishMode && currentCandidates . length > candidatesPerPage ) {
986- event . preventDefault ( ) ;
987- if ( event . key === '<' ) {
988- handlePageChange ( 'previous' ) ;
989- } else if ( event . key === '>' ) {
990- handlePageChange ( 'next' ) ;
991- }
992- return ;
993- }
994- }
995-
996960 if ( event . key === 'Shift' ) {
997961 if ( ! isShiftDown ) {
998962 isShiftDown = true ;
@@ -1005,28 +969,35 @@ <h2>查碼練習</h2>
1005969 return ;
1006970 }
1007971
1008- // 在中文模式下,處理長按 Shift 後的符號鍵
1009- if ( ! isEnglishMode && event . shiftKey ) {
972+ if ( isLongPressActive && event . shiftKey ) {
1010973 const char = event . key ;
1011- const outputChar = keyname_map_chinese_shifted [ char ] ;
974+ const outputChar = isEnglishMode ? keyname_map_english_shifted [ char ] : keyname_map_chinese_shifted [ char ] ;
1012975 if ( outputChar ) {
1013976 event . preventDefault ( ) ;
1014977 insertTextAtCursor ( textOutput , outputChar ) ;
978+ resetInputState ( ) ; // 長按Shift後輸入應該清空編碼
979+ updatePhraseLookup ( ) ;
1015980 return ;
1016981 }
1017982 }
1018983
984+ const char = event . key ;
1019985 if ( isEnglishMode ) {
1020- // 英文模式直接處理 event.key
1021- handleEnglishInput ( event . key ) ;
986+ if ( ! event . altKey && ! event . ctrlKey ) {
987+ event . preventDefault ( ) ;
988+ handleEnglishInput ( char ) ;
989+ }
1022990 } else {
1023- // 中文模式直接處理 event.key
1024- handleChineseInput ( event . key ) ;
991+ if ( ! event . altKey && ! event . ctrlKey ) {
992+ const isInputKey = isCodeKey ( char ) || char . match ( / ^ [ 0 - 9 ] $ / ) || char === ' ' || char === 'Enter' || char === 'Backspace' || char === 'Escape' || char === '<' || char === '>' ;
993+ if ( isInputKey ) {
994+ event . preventDefault ( ) ;
995+ handleChineseInput ( char ) ;
996+ }
997+ }
1025998 }
1026-
1027999 } ) ;
10281000
1029- // keyup 事件處理
10301001 document . addEventListener ( 'keyup' , ( event ) => {
10311002 const virtualKeyCode = getKeyCode ( event ) ;
10321003 if ( virtualKeyCode ) {
@@ -1060,7 +1031,6 @@ <h2>查碼練習</h2>
10601031 const textToCompare = textOutput . value ;
10611032 encodingResults . innerHTML = '' ;
10621033
1063- // 計算連續正確字元的數量
10641034 let correctCharsCount = 0 ;
10651035 for ( let i = 0 ; i < textToCompare . length && i < textToSearch . length ; i ++ ) {
10661036 if ( textToCompare [ i ] === textToSearch [ i ] ) {
@@ -1070,19 +1040,16 @@ <h2>查碼練習</h2>
10701040 }
10711041 }
10721042
1073- // 根據正確字數計算查碼區塊的起始索引
10741043 const lookupStartIndex = Math . floor ( correctCharsCount / 10 ) * 10 ;
10751044 const characters = textToSearch . split ( '' ) . slice ( lookupStartIndex , lookupStartIndex + 10 ) ;
10761045
1077- // 固定顯示10個欄位
10781046 for ( let i = 0 ; i < 10 ; i ++ ) {
10791047 const column = document . createElement ( 'div' ) ;
10801048 column . className = 'char-encoding-column' ;
10811049
10821050 const charLabel = document . createElement ( 'span' ) ;
10831051 charLabel . className = 'char-label' ;
10841052
1085- // 判斷字元是否比對正確,並設定對應的顏色
10861053 if ( i < characters . length ) {
10871054 const char = characters [ i ] ;
10881055 charLabel . textContent = char ;
@@ -1095,7 +1062,6 @@ <h2>查碼練習</h2>
10951062 charLabel . classList . add ( 'incorrect-char' ) ;
10961063 }
10971064 } else {
1098- // 如果 text-output 比較短,則未輸入的字元顯示為紅色
10991065 charLabel . classList . add ( 'incorrect-char' ) ;
11001066 }
11011067 }
0 commit comments