Skip to content

Commit d6bf316

Browse files
authored
Add files via upload
1 parent f4e371e commit d6bf316

1 file changed

Lines changed: 65 additions & 76 deletions

File tree

3code_mobile.html

Lines changed: 65 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<head>
44
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
55
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
6-
<title>三碼中文輸入法 - 手機版</title>
6+
<title>三碼中文輸入法 - 手機滑動選字版</title>
77
<link rel="preconnect" href="https://fonts.googleapis.com/">
88
<link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin>
99
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+TC:wght@400;700&display=swap" rel="stylesheet">
@@ -28,7 +28,7 @@
2828
margin: 0;
2929
padding: 0;
3030
box-sizing: border-box;
31-
-webkit-tap-highlight-color: transparent; /* 移除點擊高亮 */
31+
-webkit-tap-highlight-color: transparent;
3232
outline: none;
3333
}
3434

@@ -99,7 +99,7 @@
9999
cursor: text;
100100
}
101101

102-
/* 候選字與輸入區 */
102+
/* 候選字與輸入區容器 */
103103
#input-area {
104104
width: 100%;
105105
background-color: var(--container-bg);
@@ -110,6 +110,7 @@
110110
border: 1px solid var(--border-color);
111111
}
112112

113+
/* 編碼輸入顯示 */
113114
#main-input {
114115
width: 100%;
115116
padding: 8px;
@@ -120,28 +121,35 @@
120121
border-bottom: 1px solid var(--border-color);
121122
background-color: #fafafa;
122123
color: #757575;
124+
white-space: nowrap;
125+
overflow-x: auto;
123126
}
124127

128+
/* 候選字橫向滾動容器 */
125129
#candidate-display {
126130
display: flex;
127-
flex-wrap: wrap;
128131
align-items: center;
129132
padding: 8px;
130-
gap: 8px;
131-
white-space: normal;
133+
gap: 12px;
134+
white-space: nowrap; /* 確保所有候選字在一行 */
135+
overflow-x: scroll; /* 允許橫向滾動 */
136+
-webkit-overflow-scrolling: touch; /* 提升 iOS 上的滾動體驗 */
132137
min-height: 40px;
133138
}
134139

140+
#candidate-display::-webkit-scrollbar {
141+
display: none; /* 隱藏滾動條 */
142+
}
143+
135144
#candidate-display span {
136145
cursor: pointer;
137146
padding: 5px 8px;
138147
border-radius: 4px;
139148
transition: all 0.2s;
140149
user-select: none;
141150
white-space: nowrap;
142-
font-size: 1.1rem;
143-
flex-shrink: 0;
144-
text-align: center;
151+
font-size: 1.2rem; /* 略微放大字體 */
152+
flex-shrink: 0; /* 防止候選字被壓縮 */
145153
}
146154

147155
#candidate-display span:active, #candidate-display span:hover {
@@ -182,7 +190,7 @@
182190

183191
.key {
184192
flex-grow: 1;
185-
flex-basis: 0; /* 確保平均分配寬度 */
193+
flex-basis: 0;
186194
padding: 0;
187195
border-radius: 6px;
188196
background-color: var(--key-bg);
@@ -191,7 +199,7 @@
191199
user-select: none;
192200
transition: background-color 0.1s;
193201
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.2);
194-
line-height: 50px; /* 設定行高以垂直置中文字 */
202+
line-height: 50px;
195203
min-height: 50px;
196204
font-size: 1.2rem;
197205
font-weight: bold;
@@ -227,8 +235,8 @@
227235
<div id="text-output"></div>
228236

229237
<div id="input-area">
230-
<div id="main-input"></div>
231-
<div id="candidate-display"></div>
238+
<div id="main-input">編碼顯示在此</div>
239+
<div id="candidate-display">候選字顯示在此...</div>
232240
</div>
233241

234242
<div id="mode-display">模式:三碼次常</div>
@@ -240,22 +248,22 @@
240248
<script>
241249
// --- 資料處理與解析 (從 index-0.html 擷取核心部分) ---
242250
let currentCodemap = {};
243-
let currentReverseCodemap = {};
244251

245252
const keyname_map_upper = {
246-
'a': '', 'b': '', 'c': '', 'd': '', 'e': '', 'f': '', 'g': '',
247-
'h': '', 'i': '', 'j': '', 'k': '', 'l': '', 'm': '', 'n': '',
248-
'o': '', 'p': '', 'q': '', 'r': '', 's': '', 't': '', 'u': '',
249-
'v': '', 'w': '', 'x': '', 'y': '', 'z': '',
250-
// 符號對應 index-0.html 的顯示
251-
"'": "〃", ';': ';', ',': ',', '.': '.', '/': '/', ' ': '空白鍵', 'enter': 'Enter', 'backspace': '刪除鍵', 'shift': '中/英',
253+
'a': '', 'b': '', 'c': '', 'd': '', 'e': '', 'f': '', 'g': '',
254+
'h': '', 'i': '', 'j': '', 'k': '', 'l': '', 'm': '', 'n': 'P',
255+
'o': '', 'p': '', 'q': '', 'r': '', 's': '', 't': '', 'u': '',
256+
'v': '', 'w': 'O', 'x': 'X', 'y': 'Y', 'z': 'Z',
257+
// 符號對應
258+
"'": "〃", ';': ';', ',': ',', '.': '.', '/': '/', ' ': '空白', 'enter': '換行', 'backspace': '刪除', 'shift': '中/英',
252259
};
253260
const keyname_map_lower = {
254261
'a': 'a', 'b': 'b', 'c': 'c', 'd': 'd', 'e': 'e', 'f': 'f', 'g': 'g',
255262
'h': 'h', 'i': 'i', 'j': 'j', 'k': 'k', 'l': 'l', 'm': 'm', 'n': 'n',
256263
'o': 'o', 'p': 'p', 'q': 'q', 'r': 'r', 's': 's', 't': 't', 'u': 'u',
257264
'v': 'v', 'w': 'w', 'x': 'x', 'y': 'y', 'z': 'z',
258-
"'": "'", ';': ';', ',': ',', '.': '.', '/': '/', ' ': ' ', 'enter': 'Enter', 'backspace': '刪除鍵', 'shift': '中/英',
265+
// 符號對應
266+
"'": "'", ';': ';', ',': ',', '.': '.', '/': '/', ' ': ' ', 'enter': 'Enter', 'backspace': 'Back', 'shift': 'Shift',
259267
};
260268

261269
// DOM 元素
@@ -270,64 +278,50 @@
270278
const MAX_CODE_LENGTH = 3;
271279
let currentCode = '';
272280
let currentCandidates = [];
273-
let currentPage = 0;
274-
const candidatesPerPage = 10;
275281
let isEnglishMode = false;
276282

277283
// 函式:格式化碼表資料為物件 (從 index-0.html 擷取)
278284
function parseCinData(data) {
279285
const newCodemap = {};
280-
const newReverseCodemap = {};
281286
const lines = data.trim().split('\n');
282287
lines.forEach(line => {
283288
const parts = line.split('\t');
284289
if (parts.length >= 2 && !line.startsWith('#')) {
285-
const code = parts[0].trim();
290+
const code = parts[0].trim().toLowerCase(); // 確保編碼小寫
286291
const char = parts[1].trim();
287292
if (code && char) {
288293
if (!newCodemap[code]) {
289294
newCodemap[code] = [];
290295
}
291296
newCodemap[code].push(char);
292-
293-
if (!newReverseCodemap[char]) {
294-
newReverseCodemap[char] = [];
295-
}
296-
newReverseCodemap[char].push(code);
297297
}
298298
}
299299
});
300-
return { newCodemap, newReverseCodemap };
300+
return newCodemap;
301301
}
302302

303303
// 函式:載入次常用字碼表 (僅載入 3codes2.txt)
304304
async function loadSecondaryCodemap() {
305305
const fileName = './3codes2.txt';
306306
try {
307-
// 這裡假設 3codes2.txt 位於與此 HTML 檔案相同的目錄下
308307
const response = await fetch(fileName);
309308
if (!response.ok) {
310309
throw new Error('Network response was not ok');
311310
}
312311
const text = await response.text();
313-
const { newCodemap, newReverseCodemap } = parseCinData(text);
314-
currentCodemap = newCodemap;
315-
currentReverseCodemap = newReverseCodemap;
312+
currentCodemap = parseCinData(text);
316313
updateModeDisplay();
314+
mainInput.textContent = '編碼表載入成功';
317315
} catch (error) {
318316
console.error(`載入 ${fileName} 時發生錯誤:`, error);
319-
textOutput.textContent = `錯誤:無法載入編碼檔 ${fileName}。請確認檔案存在且與此 HTML 位於相同目錄下。`;
317+
mainInput.textContent = `錯誤:無法載入編碼檔 ${fileName}。請確認檔案存在且與此 HTML 位於相同目錄下。`;
320318
}
321319
resetInputState();
322320
}
323321

324-
// --- 處理中文模式輸入的核心函數 (從 index-0.html 擷取) ---
322+
// --- 處理中文模式輸入的核心函數 ---
325323
function handleChineseInput(code) {
326-
// 統一處理數字鍵邏輯 (虛擬鍵盤沒有數字鍵,此處忽略)
327-
if (code.match(/^[1-90]$/)) {
328-
return;
329-
}
330-
324+
331325
if (code === 'backspace') {
332326
if (currentCode.length > 0) {
333327
currentCode = currentCode.slice(0, -1);
@@ -347,8 +341,6 @@
347341
return;
348342
}
349343

350-
// 獨立的翻頁處理函數 (虛擬鍵盤移除翻頁鍵,此處忽略)
351-
352344
if (code === ' ') {
353345
if (currentCandidates.length > 0) {
354346
selectCandidate(0);
@@ -359,11 +351,11 @@
359351
}
360352

361353
const inputChar = code.toLowerCase();
362-
// 接受所有 26 字母和 5 符號的輸入
354+
// 接受所有 26 字母和 5 符號的輸入: a-z, ; ' , . /
363355
if (inputChar.match(/^[a-z;'./,<>]$/)) {
364356
if (currentCode.length === MAX_CODE_LENGTH) {
365357
if (currentCandidates.length > 0) {
366-
selectCandidate(0); // 超過三碼,自動上字
358+
selectCandidate(0); // 超過三碼,自動選第一個上字
367359
}
368360
currentCode = inputChar;
369361
} else {
@@ -373,7 +365,7 @@
373365
}
374366
}
375367

376-
// --- 處理英文模式輸入的新函數 (從 index-0.html 擷取) ---
368+
// --- 處理英文模式輸入 ---
377369
function handleEnglishInput(char) {
378370
// 處理功能鍵
379371
if (char === 'backspace') {
@@ -397,10 +389,9 @@
397389
}
398390
}
399391

400-
// --- 核心狀態更新與顯示函數 (中文模式專用) (從 index-0.html 擷取) ---
392+
// --- 核心狀態更新與顯示函數 (中文模式專用) ---
401393
function updateStateAndDisplay() {
402-
mainInput.textContent = formatCode(currentCode);
403-
currentPage = 0;
394+
mainInput.textContent = `輸入編碼: ${formatCode(currentCode)}`;
404395
currentCandidates = currentCodemap[currentCode] || [];
405396

406397
if (currentCode.length === MAX_CODE_LENGTH) {
@@ -409,7 +400,7 @@
409400
resetInputState();
410401
return;
411402
} else if (currentCandidates.length === 0) {
412-
// 如果沒有候選字,清空輸入,不做任何輸出
403+
// 沒有候選字,清空輸入
413404
resetInputState();
414405
return;
415406
}
@@ -418,70 +409,68 @@
418409
showCandidates();
419410
}
420411

421-
// --- 顯示候選字為列表 (從 index-0.html 擷取) ---
412+
// --- 顯示候選字為可滑動列表 (更新) ---
422413
function showCandidates() {
423414
candidateDisplay.innerHTML = '';
424415

425-
const start = currentPage * candidatesPerPage;
426-
const end = start + candidatesPerPage;
427-
const displayedCandidates = currentCandidates.slice(start, end);
428-
429-
displayedCandidates.forEach((candidate, index) => {
430-
const span = document.createElement('span');
431-
const displayIndex = (index === 9) ? '0' : (index + 1).toString();
432-
span.textContent = `${displayIndex}. ${candidate}`;
433-
span.onclick = () => selectCandidate(index);
434-
candidateDisplay.appendChild(span);
435-
});
436-
437416
if (currentCandidates.length === 0 && currentCode.length > 0) {
438417
candidateDisplay.textContent = '無候選字';
418+
return;
439419
} else if (currentCandidates.length === 0) {
440420
candidateDisplay.textContent = '候選字顯示在此...';
421+
return;
441422
}
423+
424+
// 顯示所有候選字並支援點擊
425+
currentCandidates.forEach((candidate, index) => {
426+
const span = document.createElement('span');
427+
// 移除數字標記,直接顯示漢字
428+
span.textContent = candidate;
429+
span.onclick = () => selectCandidate(index);
430+
candidateDisplay.appendChild(span);
431+
});
442432
}
443433

444-
// --- 選擇候選字並清空輸入 (從 index-0.html 擷取) ---
434+
// --- 選擇候選字並清空輸入 ---
445435
function selectCandidate(index) {
446-
const selectedCandidate = currentCandidates[currentPage * candidatesPerPage + index];
436+
const selectedCandidate = currentCandidates[index];
447437
if (selectedCandidate) {
448438
textOutput.textContent += selectedCandidate;
449439
resetInputState();
450440
}
451441
}
452442

453-
// --- 清空所有輸入狀態 (從 index-0.html 擷取) ---
443+
// --- 清空所有輸入狀態 ---
454444
function resetInputState() {
455445
currentCode = '';
456446
currentCandidates = [];
457-
currentPage = 0;
458-
mainInput.textContent = '編碼顯示在此';
447+
mainInput.textContent = isEnglishMode ? '英文模式' : '編碼顯示在此';
459448
showCandidates();
460449
}
461450

462-
// --- 格式化編碼顯示 (從 index-0.html 擷取) ---
451+
// --- 格式化編碼顯示 ---
463452
function formatCode(code) {
464453
let displayString = '';
465454
for (const char of code) {
466-
// 使用大寫字母顯示編碼
455+
// 顯示基礎字根/符號
467456
displayString += keyname_map_upper[char] || char.toUpperCase();
468457
}
469458
return displayString;
470459
}
471460

472-
// --- 更新鍵盤按鍵顯示 (從 index-0.html 擷取並修改) ---
461+
// --- 更新鍵盤按鍵顯示 ---
473462
function updateKeyboardDisplay() {
474463
const map = isEnglishMode ? keyname_map_lower : keyname_map_upper;
475464
document.querySelectorAll('.key[data-code]').forEach(keyElement => {
476465
const code = keyElement.dataset.code;
477466
if (map[code]) {
478-
// 功能鍵使用原始標籤,字符鍵使用大小寫
467+
// 功能鍵使用原始標籤,字符鍵使用大小寫/字根
479468
keyElement.textContent = map[code];
480469
}
481470
});
482471
}
483472

484-
// --- 更新模式顯示 (從 index-0.html 擷取並修改) ---
473+
// --- 更新模式顯示 ---
485474
function updateModeDisplay() {
486475
modeDisplay.textContent = isEnglishMode ? '模式:英文' : '模式:三碼次常';
487476
}
@@ -492,8 +481,8 @@
492481
const layout_mobile = [
493482
['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'],
494483
['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';'],
495-
['Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/', "'"],
496-
['Shift', 'Space', 'Back', 'Enter']
484+
['Shift', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/', "'"],
485+
['Space', 'Back', 'Enter'] // 移除 123
497486
];
498487

499488
keyboardContainer.innerHTML = '';

0 commit comments

Comments
 (0)