From 23f5133a075437cdeccad98b0dfc08648b0c5ebc Mon Sep 17 00:00:00 2001 From: guoqingshan Date: Sun, 2 Aug 2026 20:53:12 +0800 Subject: [PATCH] =?UTF-8?q?style:=20=E6=89=93=E5=AD=97=E7=BB=83=E4=B9=A0?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E6=A0=87=E5=87=86=E9=94=AE=E7=9B=98=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=E5=B9=B6=E5=A2=9E=E5=8A=A0=E7=89=B9=E6=AE=8A=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E8=BE=93=E5=85=A5=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- typing.css | 27 ++++++++++++--- typing.html | 1 + typing.js | 96 ++++++++++++++++++++++++++++++++++++++--------------- 3 files changed, 93 insertions(+), 31 deletions(-) diff --git a/typing.css b/typing.css index a1307ea..17debf2 100644 --- a/typing.css +++ b/typing.css @@ -170,6 +170,7 @@ gap: 0.35rem; } .kb-key { + flex: 0 0 auto; min-width: 34px; height: 40px; padding: 0 0.4rem; @@ -179,8 +180,14 @@ color: var(--text); font-size: 0.9rem; font-family: var(--font-mono); - cursor: pointer; + cursor: default; + user-select: none; + display: inline-flex; + align-items: center; + justify-content: center; } +.kb-key.wide { min-width: 64px; } +.kb-key.altgr { min-width: 64px; } .kb-key.space { flex: 1; max-width: 220px; } .kb-key.hint { border-color: var(--accent); @@ -188,6 +195,13 @@ color: #fff; font-weight: 700; } +#special-hint { + min-height: 1.6rem; + margin-top: 0.75rem; + font-size: 0.85rem; + color: var(--text-muted); + line-height: 1.5; +} .finish-box { text-align: center; padding: 2rem 0; @@ -205,10 +219,13 @@ } @media (max-width: 640px) { .kb-key { - min-width: 28px; - height: 38px; - font-size: 0.8rem; - padding: 0 0.25rem; + min-width: 20px; + height: 34px; + font-size: 0.65rem; + padding: 0 0.1rem; + } + .kb-key.wide, .kb-key.altgr { + min-width: 44px; } .kb-row { gap: 0.25rem; } } diff --git a/typing.html b/typing.html index 0d6e2ca..cc3909c 100644 --- a/typing.html +++ b/typing.html @@ -53,6 +53,7 @@
+
diff --git a/typing.js b/typing.js index 77fe0b9..fe16ed0 100644 --- a/typing.js +++ b/typing.js @@ -5,13 +5,62 @@ var typingStats = { correct: 0, errors: 0 }; var typed = ''; var KEY_ROWS = [ - ['1','2','3','4','5','6','7','8','9','0'], - ['q','w','e','r','t','y','u','i','o','p'], - ['a','s','d','f','g','h','j','k','l','ñ'], - ['z','x','c','v','b','n','m',',','.',';'], - ['á','é','í','ó','ú','ü','¿','¡',':','?','!',' '] + ['1','2','3','4','5','6','7','8','9','0','-','='], + ['q','w','e','r','t','y','u','i','o','p','[',']','\\'], + ['a','s','d','f','g','h','j','k','l',';','\''], + ['Shift','z','x','c','v','b','n','m',',','.','/','Shift'], + ['Ctrl','Alt','Space','AltGr','Ctrl'] ]; +var SPECIAL_HINTS = { + 'á': 'Windows 美式国际:先按 \' 再按 a;macOS:Option + e 再按 a;手机长按 a', + 'é': 'Windows 美式国际:先按 \' 再按 e;macOS:Option + e 再按 e;手机长按 e', + 'í': 'Windows 美式国际:先按 \' 再按 i;macOS:Option + e 再按 i;手机长按 i', + 'ó': 'Windows 美式国际:先按 \' 再按 o;macOS:Option + e 再按 o;手机长按 o', + 'ú': 'Windows 美式国际:先按 \' 再按 u;macOS:Option + e 再按 u;手机长按 u', + 'ü': 'Windows 美式国际:先按 " 再按 u;macOS:Option + u 再按 u;手机长按 u', + 'ñ': 'Windows:AltGr + n 或先按 ~ 再按 n;macOS:Option + n 再按 n;手机长按 n', + '¿': 'Windows:AltGr + ?;macOS:Option + Shift + ?;Linux:Compose ? ?', + '¡': 'Windows:AltGr + 1;macOS:Option + 1;Linux:Compose ! !', + '?': 'Shift + /', + '!': 'Shift + 1', + ':': 'Shift + ;' +}; + +function standardKeyForChar(ch) { + if (ch === ' ') return 'Space'; + var lower = ch.toLowerCase(); + if (/[a-z0-9]/.test(lower)) return lower; + var map = { + 'á':'a','é':'e','í':'i','ó':'o','ú':'u','ü':'u','ñ':'n', + '?':'/','¿':'/','!':'1','¡':'1', + ',':',','.':'.',';':';',':':';','-':'-','=':'=', + '[':'[',']':']','\\':'\\',"'":"'",'\"':"'" + }; + return map[ch] || ''; +} + +function renderSpecialHint(ch) { + var el = document.getElementById('special-hint'); + if (!ch) { + el.textContent = ''; + return; + } + if (SPECIAL_HINTS[ch]) { + el.textContent = '输入提示:' + SPECIAL_HINTS[ch]; + return; + } + if (ch === ' ') { + el.textContent = '输入提示:按空格键'; + return; + } + if (ch !== ch.toLowerCase() && ch === ch.toUpperCase() && /[a-z]/i.test(ch)) { + el.textContent = '输入提示:先按 Shift,再按 ' + ch.toLowerCase(); + return; + } + el.textContent = '输入提示:直接按标准键盘上的 ' + (standardKeyForChar(ch) || ch) + ' 键'; +} + function escTyping(s) { var div = document.createElement('div'); div.textContent = s == null ? '' : String(s); @@ -95,9 +144,10 @@ function renderPractice() { function renderNextKey(target) { var next = target[typed.length]; + var label = next === ' ' ? '空格' : next; document.getElementById('next-key').innerHTML = typed.length >= target.length ? '已完成' - : '下一键:' + escTyping(next) + ''; + : '下一键:' + escTyping(label) + ''; } function renderTypingAccuracy() { @@ -109,18 +159,25 @@ function renderTypingAccuracy() { function renderKeyboard(target) { var next = target[typed.length] || ''; + var base = standardKeyForChar(next); + var shiftNeeded = next && next !== next.toLowerCase() && next === next.toUpperCase() && /[a-z]/i.test(next); + var specialNeeded = next && /[áéíóúüñ¿¡]/.test(next); + var shiftPunctuation = next === '?' || next === '!' || next === ':'; var container = document.getElementById('keyboard'); container.innerHTML = KEY_ROWS.map(function(row) { return '
' + row.map(function(key) { - var label = key === ' ' ? '␣' : key; - var isHint = next && ( - key === next || - key.toLowerCase() === next.toLowerCase() || - (next === ' ' && key === ' ') - ); - return ''; + var isHint = key.toLowerCase() === String(base || '').toLowerCase() || + (key === 'Shift' && (shiftNeeded || shiftPunctuation)) || + (key === 'AltGr' && specialNeeded); + var cls = ['kb-key']; + if (isHint) cls.push('hint'); + if (key === 'Shift' || key === 'Ctrl' || key === 'Alt') cls.push('wide'); + if (key === 'AltGr') cls.push('altgr'); + if (key === 'Space') cls.push('space'); + return '
' + escTyping(key) + '
'; }).join('') + '
'; }).join(''); + renderSpecialHint(next); } function handleTypingInput() { @@ -200,18 +257,5 @@ document.querySelectorAll('.mode-select button').forEach(function(btn) { document.getElementById('btn-start').addEventListener('click', startTyping); document.getElementById('btn-restart').addEventListener('click', startTyping); document.getElementById('typing-input').addEventListener('input', handleTypingInput); -document.getElementById('keyboard').addEventListener('click', function(e) { - var btn = e.target.closest('.kb-key'); - if (!btn) return; - var input = document.getElementById('typing-input'); - var key = btn.dataset.key; - var next = typingItems[typingIndex] && typingItems[typingIndex].es[typed.length]; - if (next && key.toLowerCase() === next.toLowerCase() && key !== next) { - key = next; - } - input.value += key; - handleTypingInput(); - input.focus(); -}); renderCategories();