@@ -408,6 +408,8 @@ <h2>輸入法模式:</h2>
408408 let currentCodemap = { } ;
409409 let currentReverseCodemap = { } ;
410410 let isEnglishMode = false ;
411+ let currentPage = 0 ;
412+ const candidatesPerPage = 10 ;
411413
412414 const output = document . getElementById ( 'text-output' ) ;
413415 const mainInput = document . getElementById ( 'main-input' ) ;
@@ -423,7 +425,7 @@ <h2>輸入法模式:</h2>
423425 ';' : ';' , "'" : '〃' , ',' : ',' , '.' : '.' , '/' : '/'
424426 } ;
425427
426- // --- 載入碼表檔案(已修復) ---
428+ // --- 載入碼表檔案 ---
427429 async function loadCodemap ( filePath ) {
428430 try {
429431 const response = await fetch ( filePath ) ;
@@ -439,7 +441,7 @@ <h2>輸入法模式:</h2>
439441 }
440442 }
441443
442- // --- 解析 Cin 格式檔案內容(已修復) ---
444+ // --- 解析 Cin 格式檔案內容 ---
443445 function parseCinLikeFile ( text ) {
444446 const lines = text . split ( '\n' ) ;
445447 const codemap = { } ;
@@ -484,23 +486,53 @@ <h2>輸入法模式:</h2>
484486 function updateCandidates ( ) {
485487 candidateArea . innerHTML = '' ;
486488 currentCandidates = currentCodemap [ currentCode ] || [ ] ;
489+
490+ if ( currentCandidates . length === 1 && currentCode . length === 3 ) {
491+ output . textContent += currentCandidates [ 0 ] ;
492+ resetInputState ( ) ;
493+ return ;
494+ }
495+
496+ const totalPages = Math . ceil ( currentCandidates . length / candidatesPerPage ) ;
497+ const startIndex = currentPage * candidatesPerPage ;
498+ const endIndex = startIndex + candidatesPerPage ;
499+ const displayedCandidates = currentCandidates . slice ( startIndex , endIndex ) ;
487500
488- if ( currentCandidates . length > 0 ) {
489- currentCandidates . forEach ( ( char , index ) => {
501+ if ( displayedCandidates . length > 0 ) {
502+ displayedCandidates . forEach ( ( char , index ) => {
490503 const candidateSpan = document . createElement ( 'span' ) ;
491- candidateSpan . textContent = `${ index + 1 } . ${ char } ` ;
504+ const displayIndex = ( index === 9 ) ? 0 : index + 1 ;
505+ candidateSpan . textContent = `${ displayIndex } . ${ char } ` ;
492506 candidateSpan . dataset . char = char ;
493507 candidateSpan . dataset . index = index ;
494508 candidateArea . appendChild ( candidateSpan ) ;
495509 } ) ;
496510 } else if ( currentCode . length === 3 ) {
497511 resetInputState ( ) ;
498512 }
513+
514+ if ( totalPages > 1 ) {
515+ if ( currentPage > 0 ) {
516+ const prevSpan = document . createElement ( 'span' ) ;
517+ prevSpan . textContent = '上一頁' ;
518+ prevSpan . className = 'page-nav' ;
519+ prevSpan . dataset . page = 'prev' ;
520+ candidateArea . prepend ( prevSpan ) ;
521+ }
522+ if ( currentPage < totalPages - 1 ) {
523+ const nextSpan = document . createElement ( 'span' ) ;
524+ nextSpan . textContent = '下一頁' ;
525+ nextSpan . className = 'page-nav' ;
526+ nextSpan . dataset . page = 'next' ;
527+ candidateArea . appendChild ( nextSpan ) ;
528+ }
529+ }
499530 }
500531
501532 function resetInputState ( ) {
502533 currentCode = '' ;
503534 mainInput . value = '' ;
535+ currentPage = 0 ;
504536 updateCandidates ( ) ;
505537 }
506538
@@ -540,10 +572,18 @@ <h2>輸入法模式:</h2>
540572
541573 candidateArea . addEventListener ( 'click' , ( event ) => {
542574 const candidate = event . target . closest ( 'span[data-char]' ) ;
575+ const pageNav = event . target . closest ( 'span[data-page]' ) ;
543576 if ( candidate ) {
544577 const char = candidate . dataset . char ;
545578 output . textContent += char ;
546579 resetInputState ( ) ;
580+ } else if ( pageNav ) {
581+ if ( pageNav . dataset . page === 'next' ) {
582+ currentPage ++ ;
583+ } else if ( pageNav . dataset . page === 'prev' ) {
584+ currentPage -- ;
585+ }
586+ updateCandidates ( ) ;
547587 }
548588 } ) ;
549589
@@ -555,42 +595,38 @@ <h2>輸入法模式:</h2>
555595 handleKey ( key ) ;
556596 } ) ;
557597
598+ const specialKeys = [ "backspace" , "enter" , " " ] ;
599+ const pageKeys = [ "<" , ">" ] ;
600+ const numKeys = "1234567890" ;
601+ const codeKeys = "abcdefghijklmnopqrstuvwxyz;',./" ;
602+
558603 // 監聽實體鍵盤事件
559604 document . addEventListener ( 'keydown' , ( event ) => {
560605 const key = event . key . toLowerCase ( ) ;
561- const keyMap = {
562- 'backspace' : 'backspace' ,
563- 'enter' : 'enter' ,
564- ' ' : ' ' ,
565- 'shift' : 'shift' ,
566- '~' : '~' ,
567- '1' : '1' , '2' : '2' , '3' : '3' , '4' : '4' , '5' : '5' , '6' : '6' , '7' : '7' , '8' : '8' , '9' : '9' , '0' : '0' ,
568- ';' : ';' , "'" : "'" , ',' : ',' , '.' : '.' , '/' : '/' ,
569- 'q' : 'q' , 'w' : 'w' , 'e' : 'e' , 'r' : 'r' , 't' : 't' , 'y' : 'y' , 'u' : 'u' , 'i' : 'i' , 'o' : 'o' , 'p' : 'p' ,
570- 'a' : 'a' , 's' : 's' , 'd' : 'd' , 'f' : 'f' , 'g' : 'g' , 'h' : 'h' , 'j' : 'j' , 'k' : 'K' , 'l' : 'l' ,
571- 'z' : 'z' , 'x' : 'x' , 'c' : 'c' , 'v' : 'v' , 'b' : 'b' , 'n' : 'n' , 'm' : 'm'
572- } ;
573- const inputKey = keyMap [ key ] || key ;
574606
575607 // 處理按鍵反白效果
576- const pressedKey = document . querySelector ( `.key[data-code='${ inputKey } ']` ) ;
577- if ( pressedKey ) {
578- pressedKey . classList . add ( 'active' ) ;
608+ let pressedKeyDiv ;
609+ if ( key === '<' ) {
610+ pressedKeyDiv = document . querySelector ( `.key[data-code='<']` ) ;
611+ } else if ( key === '>' ) {
612+ pressedKeyDiv = document . querySelector ( `.key[data-code='>']` ) ;
613+ } else {
614+ pressedKeyDiv = document . querySelector ( `.key[data-code='${ key } ']` ) ;
615+ }
616+ if ( pressedKeyDiv ) {
617+ pressedKeyDiv . classList . add ( 'active' ) ;
579618 }
580619
581- // 處理 Shift 鍵切換模式
582620 if ( event . key === "Shift" ) {
583- if ( event . repeat ) return ; // 避免長按時重複觸發
621+ if ( event . repeat ) return ;
584622 isEnglishMode = ! isEnglishMode ;
585623 updateModeDisplay ( ) ;
586624 resetInputState ( ) ;
587- event . preventDefault ( ) ; // 阻止瀏覽器默認行為
588- return ;
625+ return ;
589626 }
590627
591- // 在英數模式下處理所有輸入
592628 if ( isEnglishMode ) {
593- if ( event . key . length === 1 ) {
629+ if ( key . length === 1 && ! event . ctrlKey && ! event . altKey ) {
594630 output . textContent += event . key ;
595631 } else if ( event . key === 'Backspace' ) {
596632 output . textContent = output . textContent . slice ( 0 , - 1 ) ;
@@ -600,57 +636,41 @@ <h2>輸入法模式:</h2>
600636 return ;
601637 }
602638
603- // 在中文模式下處理
604- // 數字鍵處理邏輯:有候選字則選字,無候選字則上字
605- if ( event . key >= '1' && event . key <= '9' ) {
606- event . preventDefault ( ) ; // 阻止瀏覽器默認行為
607- const index = parseInt ( event . key , 10 ) - 1 ;
608- if ( currentCandidates . length > 0 && index >= 0 && index < currentCandidates . length ) {
609- output . textContent += currentCandidates [ index ] ;
610- resetInputState ( ) ;
611- } else {
612- output . textContent += event . key ;
613- resetInputState ( ) ;
614- }
615- } else if ( event . key === '0' ) {
616- event . preventDefault ( ) ;
617- output . textContent += event . key ;
618- resetInputState ( ) ;
619- } else if ( inputKey ) {
620- event . preventDefault ( ) ; // 阻止瀏覽器默認行為
621- handleKey ( inputKey ) ;
622- } else if ( event . key . length === 1 ) { // 處理未映射的單個字元
623- output . textContent += event . key ;
639+ if ( specialKeys . includes ( key ) ) {
640+ event . preventDefault ( ) ;
641+ handleKey ( key ) ;
642+ } else if ( pageKeys . includes ( key ) ) {
643+ event . preventDefault ( ) ;
644+ handlePageKey ( key ) ;
645+ } else if ( numKeys . includes ( key ) ) {
646+ event . preventDefault ( ) ;
647+ handleNumKey ( key ) ;
648+ } else if ( codeKeys . includes ( key ) ) {
649+ handleKey ( key ) ;
624650 }
625651 } ) ;
626652
627653 // 監聽實體鍵盤放開事件,移除按鍵反白
628654 document . addEventListener ( 'keyup' , ( event ) => {
629655 const key = event . key . toLowerCase ( ) ;
630- const keyMap = {
631- 'backspace' : 'backspace' ,
632- 'enter' : 'enter' ,
633- ' ' : ' ' ,
634- 'shift' : 'shift' ,
635- '~' : '~' ,
636- '1' : '1' , '2' : '2' , '3' : '3' , '4' : '4' , '5' : '5' , '6' : '6' , '7' : '7' , '8' : '8' , '9' : '9' , '0' : '0' ,
637- ';' : ';' , "'" : "'" , ',' : ',' , '.' : '.' , '/' : '/' ,
638- 'q' : 'q' , 'w' : 'w' , 'e' : 'e' , 'r' : 'r' , 't' : 't' , 'y' : 'y' , 'u' : 'u' , 'i' : 'i' , 'o' : 'o' , 'p' : 'p' ,
639- 'a' : 'a' , 's' : 's' , 'd' : 'd' , 'f' : 'f' , 'g' : 'g' , 'h' : 'h' , 'j' : 'j' , 'k' : 'K' , 'l' : 'l' ,
640- 'z' : 'z' , 'x' : 'x' , 'c' : 'c' , 'v' : 'v' , 'b' : 'b' , 'n' : 'n' , 'm' : 'm'
641- } ;
642- const releasedKey = keyMap [ key ] || key ;
643- const releasedKeyDiv = document . querySelector ( `.key[data-code='${ releasedKey } ']` ) ;
656+ let releasedKeyDiv ;
657+ if ( key === '<' ) {
658+ releasedKeyDiv = document . querySelector ( `.key[data-code='<']` ) ;
659+ } else if ( key === '>' ) {
660+ releasedKeyDiv = document . querySelector ( `.key[data-code='>']` ) ;
661+ } else {
662+ releasedKeyDiv = document . querySelector ( `.key[data-code='${ key } ']` ) ;
663+ }
644664 if ( releasedKeyDiv ) {
645665 releasedKeyDiv . classList . remove ( 'active' ) ;
646666 }
647667 } ) ;
648668
649669 // 處理鍵盤與物理鍵盤的共用邏輯
650670 function handleKey ( key ) {
651- const validCodeKeys = "1234567890abcdefghijklmnopqrstuvwxyz ;',./" ;
671+ const codeKeys = "abcdefghijklmnopqrstuvwxyz ;',./" ;
652672
653- if ( validCodeKeys . includes ( key ) && currentCode . length < 3 ) {
673+ if ( codeKeys . includes ( key ) && currentCode . length < 3 ) {
654674 currentCode += key ;
655675 const fullWidthCode = Array . from ( currentCode ) . map ( char => fullWidthMap [ char ] || char ) . join ( '' ) ;
656676 mainInput . value = fullWidthCode ;
@@ -676,6 +696,35 @@ <h2>輸入法模式:</h2>
676696 resetInputState ( ) ;
677697 }
678698 }
699+
700+ function handlePageKey ( key ) {
701+ if ( key === '<' ) {
702+ if ( currentPage > 0 ) {
703+ currentPage -- ;
704+ updateCandidates ( ) ;
705+ }
706+ } else if ( key === '>' ) {
707+ const totalPages = Math . ceil ( currentCandidates . length / candidatesPerPage ) ;
708+ if ( currentPage < totalPages - 1 ) {
709+ currentPage ++ ;
710+ updateCandidates ( ) ;
711+ }
712+ }
713+ }
714+
715+ function handleNumKey ( key ) {
716+ let index = parseInt ( key , 10 ) ;
717+ if ( index === 0 ) index = 10 ;
718+
719+ const candidateIndex = ( currentPage * candidatesPerPage ) + ( index - 1 ) ;
720+ if ( candidateIndex >= 0 && candidateIndex < currentCandidates . length ) {
721+ output . textContent += currentCandidates [ candidateIndex ] ;
722+ resetInputState ( ) ;
723+ } else {
724+ output . textContent += key ;
725+ resetInputState ( ) ;
726+ }
727+ }
679728
680729 // --- 反向查詢事件處理 ---
681730 searchInput . addEventListener ( 'input' , ( ) => {
0 commit comments