|
274 | 274 | } |
275 | 275 |
|
276 | 276 | .keyboard-key.highlighted { |
| 277 | + /* 用於 touchstart/mousedown 設置的高亮狀態 */ |
277 | 278 | background-color: var(--key-active-bg) !important; |
278 | 279 | color: white; |
279 | 280 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); |
|
313 | 314 | } |
314 | 315 |
|
315 | 316 | .keyboard-key:active { |
| 317 | + /* 作為降級/輔助的點擊視覺效果,但在 touchstart 設置 highlighted 後會被覆蓋 */ |
316 | 318 | background-color: var(--key-active-bg); |
317 | 319 | color: white; |
318 | 320 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); |
|
381 | 383 | // --- 長按相關狀態 --- |
382 | 384 | let longPressTimer = null; |
383 | 385 | let longPressCommitted = false; |
384 | | - const LONG_PRESS_TIMEOUT = 500; |
| 386 | + // *** 修正點 2:延長長按時限,更容易觸發 *** |
| 387 | + const LONG_PRESS_TIMEOUT = 750; // 500ms -> 750ms |
385 | 388 |
|
386 | 389 | // --- 游標 HTML 定義 --- |
387 | 390 | const CURSOR_HTML = '<span id="main-cursor" class="cursor">\u200c</span>'; |
|
414 | 417 | const KEYCODE_ENTER=0x0d; |
415 | 418 | const KEYCODE_SPACE=0x20; |
416 | 419 |
|
417 | | - // --- 鍵盤配置 --- |
| 420 | + // --- 鍵盤配置 (略) --- |
418 | 421 | var Keyboards = { |
419 | 422 | english: { |
420 | 423 | shifted : false, |
|
510 | 513 | } |
511 | 514 |
|
512 | 515 | /** |
513 | | - * 鍵盤渲染函數 |
| 516 | + * 鍵盤渲染函數 (略) |
514 | 517 | */ |
515 | 518 | function drawKeyboard() { |
516 | 519 | const layout = currentLayout; |
|
673 | 676 | } |
674 | 677 |
|
675 | 678 | /** |
676 | | - * 浮層處理函數 (保持不變) |
| 679 | + * 浮層處理函數 (略) |
677 | 680 | */ |
678 | 681 | function emoji(subIndex) { |
679 | 682 | const emojis=[[ |
|
736 | 739 | } |
737 | 740 |
|
738 | 741 | /** |
739 | | - * 處理短按事件:執行編碼或普通字符輸入 |
| 742 | + * 處理短按事件:執行編碼或普通字符輸入 (略) |
740 | 743 | */ |
741 | 744 | function handleShortPress(keyElement) { |
742 | 745 | preferredOffset = -1; |
|
781 | 784 | } |
782 | 785 |
|
783 | 786 | /** |
784 | | - * 處理功能鍵邏輯 |
| 787 | + * 處理功能鍵邏輯 (略) |
785 | 788 | */ |
786 | 789 | function handleFunctionKey(code, keyChar) { |
787 | 790 | switch(code) { |
|
869 | 872 |
|
870 | 873 | /** |
871 | 874 | * 統一的事件綁定函數 (同時支援 Touch 和 Mouse) |
872 | | - * 【修正區域:優化反白邏輯,移除導致無法點擊的檢查】 |
873 | 875 | */ |
874 | 876 | function bindKeyEvents() { |
875 | 877 | document.querySelectorAll('.keyboard-key').forEach(keyElement => { |
|
879 | 881 | keyElement.removeEventListener('touchstart', keyElement.handlePressDown); |
880 | 882 | keyElement.removeEventListener('touchend', keyElement.handlePressUp); |
881 | 883 | keyElement.removeEventListener('touchmove', keyElement.handlePressCancel); |
882 | | - keyElement.removeEventListener('touchcancel', keyElement.handlePressCancel); // 新增:確保移除 touchcancel |
| 884 | + keyElement.removeEventListener('touchcancel', keyElement.handlePressCancel); |
883 | 885 | keyElement.removeEventListener('mousedown', keyElement.handlePressDown); |
884 | 886 | keyElement.removeEventListener('mouseup', keyElement.handlePressUp); |
885 | 887 | keyElement.removeEventListener('mouseleave', keyElement.handlePressCancel); |
886 | 888 | } |
887 | 889 |
|
888 | | - // 清空舊的 onxxx 屬性 |
| 890 | + // 清空舊的 onxxx 屬性 (略) |
889 | 891 | keyElement.onclick = null; |
890 | 892 | keyElement.oncontextmenu = (e) => e.preventDefault(); |
891 | 893 | keyElement.ontouchstart = null; |
|
918 | 920 |
|
919 | 921 | // 2. 處理抬起/點擊 (Press Up) |
920 | 922 | const handlePressUp = (event) => { |
921 | | - // 移除 touchend 上的 preventDefault |
922 | | - // if (event.type.startsWith('touch')) event.preventDefault(); |
923 | | - |
| 923 | + // if (event.type.startsWith('touch')) event.preventDefault(); // 移除 preventDefault |
| 924 | + |
924 | 925 | if (longPressTimer) { |
925 | 926 | clearTimeout(longPressTimer); |
926 | 927 | longPressTimer = null; |
927 | 928 | } |
928 | 929 |
|
929 | | - // *** 修正:只要不是長按提交的,就視為短按並觸發輸入。*** |
930 | | - // 以前的邏輯會檢查 'highlighted' 類別,但 touchmove 會移除它,導致輕微移動就無法輸入。 |
| 930 | + // 只要不是長按提交的,就視為短按並觸發輸入 |
931 | 931 | if (!longPressCommitted) { |
932 | 932 | handleShortPress(keyElement); |
933 | 933 | } |
|
938 | 938 | }; |
939 | 939 |
|
940 | 940 | // 3. 處理取消 (Move/Leave/Cancel) |
941 | | - const handlePressCancel = () => { |
| 941 | + const handlePressCancel = (event) => { // 接受 event |
942 | 942 | if (longPressTimer) { |
943 | 943 | clearTimeout(longPressTimer); |
944 | 944 | longPressTimer = null; |
945 | 945 | } |
946 | | - // 移動、離開或觸摸中斷時立即移除高亮 |
947 | | - keyElement.classList.remove('highlighted'); |
948 | | - // 讓 longPressCommitted 保持原狀 (true 或 false),它在 handlePressUp 中決定是否執行 short press |
| 946 | + // *** 修正點 1:輕微的 touchmove 不再移除高亮,避免瞬間反白消失。*** |
| 947 | + // 只有在滑鼠離開 (mouseleave) 或系統明確取消 (touchcancel) 時,才移除高亮。 |
| 948 | + // 正常的 touchend/mouseup 會在 handlePressUp 中移除高亮。 |
| 949 | + if (event.type === 'mouseleave' || event.type === 'touchcancel') { |
| 950 | + keyElement.classList.remove('highlighted'); |
| 951 | + } |
949 | 952 | }; |
950 | 953 |
|
951 | 954 | // 將函數儲存在 DOM 元素上以便移除 |
|
957 | 960 | keyElement.addEventListener('touchstart', handlePressDown); |
958 | 961 | keyElement.addEventListener('touchend', handlePressUp); |
959 | 962 | keyElement.addEventListener('touchcancel', handlePressCancel); // 處理觸摸中斷 |
960 | | - keyElement.addEventListener('touchmove', handlePressCancel); // 處理手指移動取消 (主要用於取消長按,但也會導致輕微移動無法反白,這是我們接受的視覺取捨) |
961 | | - |
| 963 | + keyElement.addEventListener('touchmove', handlePressCancel); // 處理手指移動取消長按計時器 |
| 964 | + |
962 | 965 | // Mouse Events (用於桌面測試) |
963 | 966 | keyElement.addEventListener('mousedown', handlePressDown); |
964 | 967 | keyElement.addEventListener('mouseup', handlePressUp); |
|
967 | 970 | } |
968 | 971 |
|
969 | 972 | /** |
970 | | - * 處理單字符輸入 (用於英文/符號模式或 Shift+字母) |
| 973 | + * 處理單字符輸入 (用於英文/符號模式或 Shift+字母) (略) |
971 | 974 | */ |
972 | 975 | function handleCharInput(char) { |
973 | 976 | if (currentLayout.shifted) { |
|
982 | 985 | } |
983 | 986 | } |
984 | 987 |
|
985 | | - // --- 核心輸入法邏輯 (其餘部分保持不變) --- |
| 988 | + // --- 核心輸入法邏輯 (其餘部分略) --- |
986 | 989 |
|
987 | 990 | var currentCode = ''; |
988 | 991 | var currentCandidates = []; |
|
1244 | 1247 | updateOutputDisplay(); |
1245 | 1248 | } |
1246 | 1249 |
|
1247 | | - // --- 工具列與查碼功能 (其餘部分保持不變) --- |
| 1250 | + // --- 工具列與查碼功能 (其餘部分略) --- |
1248 | 1251 |
|
1249 | 1252 | function copyTextToClipboard() { |
1250 | 1253 | const textToCopy = committedText; |
|
0 commit comments