fix: 打字键盘改为西语键位并修复按键高亮

This commit is contained in:
guoqingshan
2026-08-02 22:09:05 +08:00
parent 7391007b74
commit ea33642f79
3 changed files with 172 additions and 38 deletions
+39 -4
View File
@@ -185,7 +185,16 @@
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex-direction: column;
line-height: 1.05;
} }
.kb-key .kb-main { font-size: 1em; }
.kb-key .kb-sub {
font-size: 0.62em;
opacity: 0.6;
margin-top: 1px;
}
.kb-key.hint .kb-sub { opacity: 0.9; }
.kb-key.wide { min-width: 64px; } .kb-key.wide { min-width: 64px; }
.kb-key.altgr { min-width: 64px; } .kb-key.altgr { min-width: 64px; }
.kb-key.space { flex: 1; max-width: 220px; } .kb-key.space { flex: 1; max-width: 220px; }
@@ -202,6 +211,26 @@
color: var(--text-muted); color: var(--text-muted);
line-height: 1.5; line-height: 1.5;
} }
.keyboard-guide {
margin-top: 1rem;
padding: 0.9rem 1rem;
background: var(--highlight);
border: 1px solid var(--border);
border-radius: var(--radius);
font-size: 0.86rem;
line-height: 1.7;
color: var(--text-muted);
}
.keyboard-guide h2 {
margin: 0 0 0.5rem;
font-size: 0.95rem;
color: var(--text);
}
.keyboard-guide ol {
margin: 0;
padding-left: 1.25rem;
}
.keyboard-guide li { margin-bottom: 0.25rem; }
.finish-box { .finish-box {
text-align: center; text-align: center;
padding: 2rem 0; padding: 2rem 0;
@@ -219,13 +248,19 @@
} }
@media (max-width: 640px) { @media (max-width: 640px) {
.kb-key { .kb-key {
min-width: 20px; flex: 1 1 0;
min-width: 0;
height: 34px; height: 34px;
font-size: 0.65rem; font-size: 0.62rem;
padding: 0 0.1rem; padding: 0 0.05rem;
} }
.kb-key.wide, .kb-key.altgr { .kb-key.wide, .kb-key.altgr {
min-width: 44px; min-width: 40px;
} }
.kb-key.space { min-width: 56px; max-width: 140px; }
.kb-row { gap: 0.25rem; } .kb-row { gap: 0.25rem; }
.keyboard-guide {
font-size: 0.8rem;
padding: 0.75rem;
}
} }
+19
View File
@@ -54,6 +54,25 @@
<div id="next-key"></div> <div id="next-key"></div>
<div id="keyboard"></div> <div id="keyboard"></div>
<div id="special-hint"></div> <div id="special-hint"></div>
<div id="keyboard-guide" class="keyboard-guide">
<h2>西语键盘按键说明</h2>
<ol>
<li>字母 ñ:点击“;”键,即字母 L 右边第一个键。</li>
<li>字母 á é í ó ú:引号键 + a e i o u,引号键是字母 L 右边第二个键。</li>
<li>倒问号 ¿:Shift + 加号键。</li>
<li>问号 ?:Shift + 减号键。</li>
<li>倒感叹号 ¡:直接按加号键。</li>
<li>感叹号 !:Shift + 数字 1。</li>
<li>快速切换键盘:Shift + Alt。</li>
<li>横线 ——:原键盘上的问号键,单击即可。</li>
<li>括号 ():Shift + 数字 8、9。</li>
<li>引号 “”:Shift + 数字 2。</li>
<li>斜线 /:Shift + 数字 7。</li>
<li>分号 ;:Shift + 逗号键。</li>
<li>冒号 ::Shift + 句号键。</li>
<li>ü:Shift + 引号键,松开后输入 u。</li>
</ol>
</div>
</div> </div>
</div> </div>
+114 -34
View File
@@ -5,39 +5,105 @@ var typingStats = { correct: 0, errors: 0 };
var typed = ''; var typed = '';
var KEY_ROWS = [ var KEY_ROWS = [
['1','2','3','4','5','6','7','8','9','0','-','='], [
['q','w','e','r','t','y','u','i','o','p','[',']','\\'], { key: 'º', sub: '`' },
['a','s','d','f','g','h','j','k','l',';','\''], { key: '1' }, { key: '2' }, { key: '3' }, { key: '4' }, { key: '5' },
['Shift','z','x','c','v','b','n','m',',','.','/','Shift'], { key: '6' }, { key: '7' }, { key: '8' }, { key: '9' }, { key: '0' },
['Ctrl','Alt','Space','AltGr','Ctrl'] { key: "'", sub: '-' }, { key: '¡', sub: '=' }
],
[
{ key: 'q' }, { key: 'w' }, { key: 'e' }, { key: 'r' }, { key: 't' },
{ key: 'y' }, { key: 'u' }, { key: 'i' }, { key: 'o' }, { key: 'p' },
{ key: '`', sub: '[' }, { key: '+', sub: ']' }, { key: 'ç', sub: '\\' }
],
[
{ key: 'a' }, { key: 's' }, { key: 'd' }, { key: 'f' }, { key: 'g' },
{ key: 'h' }, { key: 'j' }, { key: 'k' }, { key: 'l' },
{ key: 'ñ', sub: ';' }, { key: '´', sub: "'" }
],
[
{ key: 'Shift' }, { key: '<' }, { key: 'z' }, { key: 'x' }, { key: 'c' },
{ key: 'v' }, { key: 'b' }, { key: 'n' }, { key: 'm' }, { key: ',' },
{ key: '.' }, { key: '-', sub: '/' }, { key: 'Shift' }
],
[
{ key: 'Ctrl' }, { key: 'Win' }, { key: 'Alt' }, { key: 'Space' },
{ key: 'AltGr' }, { key: 'Ctrl' }
]
]; ];
var SPECIAL_HINTS = { var SPECIAL_HINTS = {
'á': 'Windows 美式国际:先按 \' 再按 a;macOS:Option + e 再按 a;手机长按 a', 'á': '先按 L 右边的 ´ 键,再按 a',
'é': 'Windows 美式国际:先按 \' 再按 e;macOS:Option + e 再按 e;手机长按 e', 'é': '先按 L 右边的 ´ 键,再按 e',
'í': 'Windows 美式国际:先按 \' 再按 i;macOS:Option + e 再按 i;手机长按 i', 'í': '先按 L 右边的 ´ 键,再按 i',
'ó': 'Windows 美式国际:先按 \' 再按 o;macOS:Option + e 再按 o;手机长按 o', 'ó': '先按 L 右边的 ´ 键,再按 o',
'ú': 'Windows 美式国际:先按 \' 再按 u;macOS:Option + e 再按 u;手机长按 u', 'ú': '先按 L 右边的 ´ 键,再按 u',
'ü': 'Windows 美式国际:先按 " 再按 u;macOS:Option + u 再按 u;手机长按 u', 'Á': '先按 L 右边的 ´ 键,再按 Shift + A',
'ñ': 'Windows:AltGr + n 或先按 ~ 再按 n;macOS:Option + n 再按 n;手机长按 n', 'É': '先按 L 右边的 ´ 键,再按 Shift + E',
'¿': '西班牙语键盘:Shift + 加号键;美式国际键盘:AltGr + ?;macOS:Option + Shift + ?;数字键盘:Alt + 0191', 'Í': '先按 L 右边的 ´ 键,再按 Shift + I',
'¡': '西班牙语键盘:直接按加号键;美式国际键盘:AltGr + 1;macOS:Option + 1;数字键盘:Alt + 0161', 'Ó': '先按 L 右边的 ´ 键,再按 Shift + O',
'?': '西班牙语键盘:Shift + 减号键;美式国际键盘:Shift + /', 'Ú': '先按 L 右边的 ´ 键,再按 Shift + U',
'ü': 'Shift + L 右边的 ´ 键,松开后按 u',
'Ü': 'Shift + L 右边的 ´ 键,松开后按 Shift + U',
'ñ': '直接按 L 右边的 ñ 键',
'Ñ': 'Shift + L 右边的 ñ 键',
'¿': 'Shift + ¡ 键(标准键盘上是 Shift + 加号键)',
'¡': '直接按 ¡ 键(标准键盘上是加号键)',
'?': 'Shift + \' 键(标准键盘上是 Shift + 减号键)',
'!': 'Shift + 数字 1', '!': 'Shift + 数字 1',
':': 'Shift + ;' ':': 'Shift + 句号键',
';': 'Shift + 逗号键'
}; };
function standardKeyForChar(ch) { function keyPressForChar(ch) {
if (ch === ' ') return 'Space'; if (!ch) return null;
if (ch === ' ') return { keys: ['Space'], shift: false };
var lower = ch.toLowerCase(); var lower = ch.toLowerCase();
if (/[a-z0-9]/.test(lower)) return lower; if (/[a-z0-9]/.test(lower)) {
return { keys: [lower], shift: ch !== lower };
}
var map = { var map = {
'á':'a','é':'e','í':'i','ó':'o','ú':'u','ü':'u','ñ':'n', 'á': { keys: ['´'], shift: false },
'?':'/','¿':'/','!':'1','¡':'1', 'é': { keys: ['´'], shift: false },
',':',','.':'.',';':';',':':';','-':'-','=':'=', 'í': { keys: ['´'], shift: false },
'[':'[',']':']','\\':'\\',"'":"'",'\"':"'" 'ó': { keys: ['´'], shift: false },
'ú': { keys: ['´'], shift: false },
'Á': { keys: ['´'], shift: false },
'É': { keys: ['´'], shift: false },
'Í': { keys: ['´'], shift: false },
'Ó': { keys: ['´'], shift: false },
'Ú': { keys: ['´'], shift: false },
'ü': { keys: ['´'], shift: true },
'Ü': { keys: ['´'], shift: true },
'ñ': { keys: ['ñ'], shift: false },
'Ñ': { keys: ['ñ'], shift: true },
'¿': { keys: ['¡'], shift: true },
'¡': { keys: ['¡'], shift: false },
'?': { keys: ["'"], shift: true },
'!': { keys: ['1'], shift: true },
':': { keys: ['.'], shift: true },
';': { keys: [','], shift: true },
'/': { keys: ['7'], shift: true },
'"': { keys: ['2'], shift: true },
'(': { keys: ['8'], shift: true },
')': { keys: ['9'], shift: true },
'_': { keys: ['-'], shift: true },
'-': { keys: ['-'], shift: false },
"'": { keys: ["'"], shift: false },
',': { keys: [','], shift: false },
'.': { keys: ['.'], shift: false },
'<': { keys: ['<'], shift: false },
'>': { keys: ['<'], shift: true },
'`': { keys: ['`'], shift: false },
'^': { keys: ['`'], shift: true },
'+': { keys: ['+'], shift: false },
'*': { keys: ['+'], shift: true },
'º': { keys: ['º'], shift: false },
'ª': { keys: ['º'], shift: true },
'ç': { keys: ['ç'], shift: false },
'Ç': { keys: ['ç'], shift: true }
}; };
return map[ch] || ''; return map[ch] || null;
} }
function renderSpecialHint(ch) { function renderSpecialHint(ch) {
@@ -54,11 +120,16 @@ function renderSpecialHint(ch) {
el.textContent = '输入提示:按空格键'; el.textContent = '输入提示:按空格键';
return; return;
} }
var press = keyPressForChar(ch);
if (press && press.shift) {
el.textContent = '输入提示:先按 Shift,再按 ' + press.keys.join(' + ') + ' 键';
return;
}
if (ch !== ch.toLowerCase() && ch === ch.toUpperCase() && /[a-z]/i.test(ch)) { if (ch !== ch.toLowerCase() && ch === ch.toUpperCase() && /[a-z]/i.test(ch)) {
el.textContent = '输入提示:先按 Shift,再按 ' + ch.toLowerCase(); el.textContent = '输入提示:先按 Shift,再按 ' + ch.toLowerCase();
return; return;
} }
el.textContent = '输入提示:直接按标准键盘上的 ' + (standardKeyForChar(ch) || ch) + ' 键'; el.textContent = '输入提示:直接按 ' + (press ? press.keys.join(' + ') : ch) + ' 键';
} }
function escTyping(s) { function escTyping(s) {
@@ -159,22 +230,31 @@ function renderTypingAccuracy() {
function renderKeyboard(target) { function renderKeyboard(target) {
var next = target[typed.length] || ''; var next = target[typed.length] || '';
var base = standardKeyForChar(next); var press = keyPressForChar(next);
var shiftNeeded = next && next !== next.toLowerCase() && next === next.toUpperCase() && /[a-z]/i.test(next); var highlightKeys = {};
var specialNeeded = next && /[áéíóúüñ¿¡]/.test(next); var highlightShift = false;
var shiftPunctuation = next === '?' || next === '!' || next === ':'; if (press) {
press.keys.forEach(function(key) {
highlightKeys[key.toLowerCase()] = true;
});
highlightShift = press.shift;
}
var container = document.getElementById('keyboard'); var container = document.getElementById('keyboard');
container.innerHTML = KEY_ROWS.map(function(row) { container.innerHTML = KEY_ROWS.map(function(row) {
return '<div class="kb-row">' + row.map(function(key) { return '<div class="kb-row">' + row.map(function(item) {
var isHint = key.toLowerCase() === String(base || '').toLowerCase() || var key = item.key;
(key === 'Shift' && (shiftNeeded || shiftPunctuation)) || var sub = item.sub || '';
(key === 'AltGr' && specialNeeded); var isHint = highlightKeys[key.toLowerCase()] ||
(key === 'Shift' && highlightShift);
var cls = ['kb-key']; var cls = ['kb-key'];
if (isHint) cls.push('hint'); if (isHint) cls.push('hint');
if (key === 'Shift' || key === 'Ctrl' || key === 'Alt') cls.push('wide'); if (key === 'Shift' || key === 'Ctrl' || key === 'Alt') cls.push('wide');
if (key === 'AltGr') cls.push('altgr'); if (key === 'AltGr') cls.push('altgr');
if (key === 'Space') cls.push('space'); if (key === 'Space') cls.push('space');
return '<div class="' + cls.join(' ') + '">' + escTyping(key) + '</div>'; var face = sub
? '<span class="kb-main">' + escTyping(key) + '</span><span class="kb-sub">' + escTyping(sub) + '</span>'
: escTyping(key);
return '<div class="' + cls.join(' ') + '">' + face + '</div>';
}).join('') + '</div>'; }).join('') + '</div>';
}).join(''); }).join('');
renderSpecialHint(next); renderSpecialHint(next);