From 4b00440b8acf4bef4fe15ab07edee0a71a407bf6 Mon Sep 17 00:00:00 2001 From: Hugo Montenegro Date: Sat, 14 Mar 2026 19:22:06 +0000 Subject: [PATCH 1/5] fix: Korean keyboard unclickable due to Hangul Jamo Unicode mismatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Korean keyboard used Compatibility Jamo (U+3130 block) while the word list used Hangul Jamo (U+1100 block). These are visually identical but different Unicode codepoints, so keyboard input was silently rejected. Fix uses the existing diacritic_map system to normalize between the two encodings — the same universal mechanism used for accent normalization in European languages. Also adds compound jongseong and compound vowel keys to an extended keyboard layout so all Korean words are playable. Backend change (app.py) is universal: any language with a diacritic_map now automatically includes base characters in the accepted set, even when only variant forms appear in the word list. Fixes #153 --- tests/conftest.py | 25 +++++++++ tests/test_language_config.py | 11 ++-- tests/test_word_lists.py | 12 ++--- webapp/app.py | 14 +++-- webapp/data/languages/ko/ko_keyboard.json | 10 ++-- webapp/data/languages/ko/language_config.json | 51 +++++++++++++++++++ 6 files changed, 101 insertions(+), 22 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 71f1fc08..5728c19b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -156,5 +156,30 @@ def load_keyboard(lang_code: str) -> list | None: return data +def load_all_keyboard_chars(lang_code: str) -> set[str]: + """Load all keyboard characters across ALL layouts for a language. + + For coverage tests, a character is typeable if it appears on any layout. + """ + keyboard_file = LANGUAGES_DIR / lang_code / f"{lang_code}_keyboard.json" + if not keyboard_file.exists(): + return set() + with open(keyboard_file, encoding="utf-8") as f: + data = json.load(f) + + control_keys = {"⇨", "⟹", "⌫", "↵", "ENTER", "DEL"} + chars = set() + + if isinstance(data, dict) and "layouts" in data: + for layout in data["layouts"].values(): + for row in layout.get("rows", []): + chars.update(k for k in row if k not in control_keys) + elif isinstance(data, list): + for row in data: + chars.update(k for k in row if k not in control_keys) + + return chars + + # Make language codes available for parametrize ALL_LANGUAGES = get_all_language_codes() diff --git a/tests/test_language_config.py b/tests/test_language_config.py index 9312024d..662ab2ff 100644 --- a/tests/test_language_config.py +++ b/tests/test_language_config.py @@ -9,6 +9,7 @@ from tests.conftest import ( ALL_LANGUAGES, get_diacritic_base_chars, + load_all_keyboard_chars, load_keyboard, load_language_config, load_word_list, @@ -153,7 +154,7 @@ class TestKeyboardConfig: """Tests for keyboard configuration.""" # Languages with known keyboard coverage gaps (complex scripts, incomplete keyboards) - KEYBOARD_COVERAGE_XFAIL = {"ko", "de"} + KEYBOARD_COVERAGE_XFAIL = {"de"} @pytest.mark.parametrize("lang", ALL_LANGUAGES) def test_keyboard_covers_all_characters(self, lang): @@ -178,12 +179,8 @@ def test_keyboard_covers_all_characters(self, lang): for word in words: word_chars.update(word) - # Flatten keyboard to get all keys - keyboard_chars = set() - for row in keyboard: - for key in row: - if key not in ("⇨", "⟹", "⌫", "ENTER", "DEL"): - keyboard_chars.add(key) + # Check all layouts — a character is typeable if it appears on any layout + keyboard_chars = load_all_keyboard_chars(lang) # Get diacritic mapping - chars that can be typed via base char diacritic_map = get_diacritic_base_chars(lang) diff --git a/tests/test_word_lists.py b/tests/test_word_lists.py index 2f43a514..975e9807 100644 --- a/tests/test_word_lists.py +++ b/tests/test_word_lists.py @@ -14,6 +14,7 @@ from tests.conftest import ( ALL_LANGUAGES, get_diacritic_base_chars, + load_all_keyboard_chars, load_blocklist, load_characters, load_daily_words, @@ -124,7 +125,7 @@ class TestKeyboardCoverage: """Tests for keyboard coverage of word characters.""" # Languages with known keyboard coverage gaps (complex scripts) - KEYBOARD_COVERAGE_XFAIL: set[str] = {"ko", "de"} + KEYBOARD_COVERAGE_XFAIL: set[str] = {"de"} @pytest.mark.parametrize("lang", ALL_LANGUAGES) def test_keyboard_covers_all_word_characters(self, lang): @@ -146,13 +147,8 @@ def test_keyboard_covers_all_word_characters(self, lang): if not keyboard or all(len(row) == 0 for row in keyboard): pytest.skip(f"{lang}: Empty keyboard (app will auto-generate)") - # Extract all characters from keyboard (load_keyboard returns normalized rows) - keyboard_chars = set() - for row in keyboard: - for key in row: - # Skip control keys - if key not in ["⇨", "⟹", "⌫", "↵", "ENTER", "DEL"]: - keyboard_chars.add(key) + # Check all layouts — a character is typeable if it appears on any layout + keyboard_chars = load_all_keyboard_chars(lang) if not keyboard_chars: pytest.skip(f"{lang}: Empty keyboard layout") diff --git a/webapp/app.py b/webapp/app.py index 5a61a475..229fa2ae 100644 --- a/webapp/app.py +++ b/webapp/app.py @@ -672,12 +672,20 @@ def __init__(self, language_code, word_list, keyboard_layout=None): self.characters = language_characters[language_code] # remove chars that aren't used to reduce bloat a bit - characters_used = [] + characters_used = set() for word in self.word_list: - characters_used += list(word) - characters_used = list(set(characters_used)) + characters_used.update(word) self.characters = [char for char in self.characters if char in characters_used] + # Include diacritic base characters whose variants appear in the word list. + # This allows keyboards using base forms (e.g., Compatibility Jamo) to work + # with word lists using variant forms (e.g., Hangul Jamo). + diacritic_map = self.config.get("diacritic_map", {}) + chars_set = set(self.characters) + for base, variants in diacritic_map.items(): + if base not in chars_set and any(v in characters_used for v in variants): + self.characters.append(base) + keyboard_config = keyboards.get(language_code, {"default": None, "layouts": {}}) self.keyboard_layouts = self._build_keyboard_layouts(keyboard_config) self.keyboard_layout_name = self._select_keyboard_layout( diff --git a/webapp/data/languages/ko/ko_keyboard.json b/webapp/data/languages/ko/ko_keyboard.json index 05a951ec..8373cb48 100644 --- a/webapp/data/languages/ko/ko_keyboard.json +++ b/webapp/data/languages/ko/ko_keyboard.json @@ -9,12 +9,14 @@ ["⇨", "ㅋ", "ㅌ", "ㅊ", "ㅍ", "ㅠ", "ㅜ", "ㅡ", "⌫"] ] }, - "korean_double": { - "label": "With Double Consonants", + "korean_extended": { + "label": "Extended (겹자모)", "rows": [ - ["ㅂ", "ㅃ", "ㅈ", "ㅉ", "ㄷ", "ㄸ", "ㄱ", "ㄲ", "ㅅ", "ㅆ", "ㅛ", "ㅕ", "ㅑ", "ㅐ", "ㅒ", "ㅔ", "ㅖ"], + ["ㅂ", "ㅃ", "ㅈ", "ㅉ", "ㄷ", "ㄸ", "ㄱ", "ㄲ", "ㅅ", "ㅆ"], + ["ㅛ", "ㅕ", "ㅑ", "ㅐ", "ㅒ", "ㅔ", "ㅖ", "ㅘ", "ㅙ", "ㅚ"], ["ㅁ", "ㄴ", "ㅇ", "ㄹ", "ㅎ", "ㅗ", "ㅓ", "ㅏ", "ㅣ"], - ["⇨", "ㅋ", "ㅌ", "ㅊ", "ㅍ", "ㅠ", "ㅜ", "ㅡ", "⌫"] + ["ㅝ", "ㅞ", "ㅟ", "ㅢ", "ㅋ", "ㅌ", "ㅊ", "ㅍ", "ㅠ", "ㅜ", "ㅡ"], + ["⇨", "ㄵ", "ㄶ", "ㄺ", "ㄻ", "ㄼ", "ㄽ", "ㄾ", "ㄿ", "ㅀ", "ㅄ", "⌫"] ] } } diff --git a/webapp/data/languages/ko/language_config.json b/webapp/data/languages/ko/language_config.json index be1f3b3e..33c567ca 100644 --- a/webapp/data/languages/ko/language_config.json +++ b/webapp/data/languages/ko/language_config.json @@ -23,6 +23,57 @@ "language_code_3": "", "language_code_iso_639_3": "", "right_to_left": "false", + "diacritic_map": { + "ㄱ": ["ᄀ", "ᆨ"], + "ㄲ": ["ᄁ", "ᆩ"], + "ㄴ": ["ᄂ", "ᆫ"], + "ㄵ": ["ᆬ"], + "ㄶ": ["ᆭ"], + "ㄷ": ["ᄃ", "ᆮ"], + "ㄸ": ["ᄄ"], + "ㄹ": ["ᄅ", "ᆯ"], + "ㄺ": ["ᆰ"], + "ㄻ": ["ᆱ"], + "ㄼ": ["ᆲ"], + "ㄽ": ["ᆳ"], + "ㄾ": ["ᆴ"], + "ㄿ": ["ᆵ"], + "ㅀ": ["ᆶ"], + "ㅁ": ["ᄆ", "ᆷ"], + "ㅂ": ["ᄇ", "ᆸ"], + "ㅃ": ["ᄈ"], + "ㅄ": ["ᆹ"], + "ㅅ": ["ᄉ", "ᆺ"], + "ㅆ": ["ᄊ", "ᆻ"], + "ㅇ": ["ᄋ", "ᆼ"], + "ㅈ": ["ᄌ", "ᆽ"], + "ㅉ": ["ᄍ"], + "ㅊ": ["ᄎ", "ᆾ"], + "ㅋ": ["ᄏ", "ᆿ"], + "ㅌ": ["ᄐ", "ᇀ"], + "ㅍ": ["ᄑ", "ᇁ"], + "ㅎ": ["ᄒ", "ᇂ"], + "ㅏ": ["ᅡ"], + "ㅐ": ["ᅢ"], + "ㅑ": ["ᅣ"], + "ㅓ": ["ᅥ"], + "ㅔ": ["ᅦ"], + "ㅕ": ["ᅧ"], + "ㅖ": ["ᅨ"], + "ㅗ": ["ᅩ"], + "ㅘ": ["ᅪ"], + "ㅙ": ["ᅫ"], + "ㅚ": ["ᅬ"], + "ㅛ": ["ᅭ"], + "ㅜ": ["ᅮ"], + "ㅝ": ["ᅯ"], + "ㅞ": ["ᅰ"], + "ㅟ": ["ᅱ"], + "ㅠ": ["ᅲ"], + "ㅡ": ["ᅳ"], + "ㅢ": ["ᅴ"], + "ㅣ": ["ᅵ"] + }, "help": { "title": "게임 방법 ", "title_2": "예 ", From a26cb6b14260576369f29162bddc3fdd25cc6785 Mon Sep 17 00:00:00 2001 From: Hugo Montenegro Date: Sat, 14 Mar 2026 19:56:36 +0000 Subject: [PATCH 2/5] =?UTF-8?q?fix:=20expand=20Korean=20default=20keyboard?= =?UTF-8?q?=20+=20fix=20German=20=C3=9F=20diacritic=20mapping?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Korean default keyboard now 5 rows with double consonants + all compound vowels (98.6% word coverage, up from 77%) - Compound jongseong available on "Full" layout (remaining 1.4%) - German: fix broken multi-char diacritic "ss"→"ß" to single-char "s"→"ß" which the char-by-char normalizer can actually process - Remove all keyboard coverage xfails (both ko and de now pass) --- tests/test_language_config.py | 2 +- tests/test_word_lists.py | 2 +- webapp/data/languages/de/language_config.json | 2 +- webapp/data/languages/ko/ko_keyboard.json | 6 ++++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/test_language_config.py b/tests/test_language_config.py index 662ab2ff..c4dc0e5e 100644 --- a/tests/test_language_config.py +++ b/tests/test_language_config.py @@ -154,7 +154,7 @@ class TestKeyboardConfig: """Tests for keyboard configuration.""" # Languages with known keyboard coverage gaps (complex scripts, incomplete keyboards) - KEYBOARD_COVERAGE_XFAIL = {"de"} + KEYBOARD_COVERAGE_XFAIL: set[str] = set() @pytest.mark.parametrize("lang", ALL_LANGUAGES) def test_keyboard_covers_all_characters(self, lang): diff --git a/tests/test_word_lists.py b/tests/test_word_lists.py index 975e9807..44208191 100644 --- a/tests/test_word_lists.py +++ b/tests/test_word_lists.py @@ -125,7 +125,7 @@ class TestKeyboardCoverage: """Tests for keyboard coverage of word characters.""" # Languages with known keyboard coverage gaps (complex scripts) - KEYBOARD_COVERAGE_XFAIL: set[str] = {"de"} + KEYBOARD_COVERAGE_XFAIL: set[str] = set() @pytest.mark.parametrize("lang", ALL_LANGUAGES) def test_keyboard_covers_all_word_characters(self, lang): diff --git a/webapp/data/languages/de/language_config.json b/webapp/data/languages/de/language_config.json index 1ce2ff65..342bb8ff 100644 --- a/webapp/data/languages/de/language_config.json +++ b/webapp/data/languages/de/language_config.json @@ -13,7 +13,7 @@ "u": [ "ü" ], - "ss": [ + "s": [ "ß" ] }, diff --git a/webapp/data/languages/ko/ko_keyboard.json b/webapp/data/languages/ko/ko_keyboard.json index 8373cb48..014ed6b6 100644 --- a/webapp/data/languages/ko/ko_keyboard.json +++ b/webapp/data/languages/ko/ko_keyboard.json @@ -6,11 +6,13 @@ "rows": [ ["ㅂ", "ㅈ", "ㄷ", "ㄱ", "ㅅ", "ㅛ", "ㅕ", "ㅑ", "ㅐ", "ㅔ"], ["ㅁ", "ㄴ", "ㅇ", "ㄹ", "ㅎ", "ㅗ", "ㅓ", "ㅏ", "ㅣ"], + ["ㅃ", "ㅉ", "ㄸ", "ㄲ", "ㅆ", "ㅒ", "ㅖ"], + ["ㅘ", "ㅙ", "ㅚ", "ㅝ", "ㅞ", "ㅟ", "ㅢ"], ["⇨", "ㅋ", "ㅌ", "ㅊ", "ㅍ", "ㅠ", "ㅜ", "ㅡ", "⌫"] ] }, - "korean_extended": { - "label": "Extended (겹자모)", + "korean_full": { + "label": "Full (전체 자모)", "rows": [ ["ㅂ", "ㅃ", "ㅈ", "ㅉ", "ㄷ", "ㄸ", "ㄱ", "ㄲ", "ㅅ", "ㅆ"], ["ㅛ", "ㅕ", "ㅑ", "ㅐ", "ㅒ", "ㅔ", "ㅖ", "ㅘ", "ㅙ", "ㅚ"], From 4ddd907cd182d7a7e95325fdef99a901d68ec2c2 Mon Sep 17 00:00:00 2001 From: Hugo Montenegro Date: Sat, 14 Mar 2026 20:02:57 +0000 Subject: [PATCH 3/5] fix: blocklist 129 Korean compound jongseong words from daily selection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Words with compound final consonants (ㄺ, ㄻ, ㄼ, etc.) are not typeable on the default keyboard. They remain valid guesses (via the Full layout) but are excluded from daily word selection so every daily word is always solvable on the default keyboard. Also adds documentation for future Option C: decomposing compound jongseong into individual jamo with 6-cell grid (like kordle.kr), which would eliminate compound keys entirely. Notes other languages (Devanagari, Thai, Khmer) that may need similar treatment. --- webapp/app.py | 8 ++ webapp/data/languages/ko/ko_blocklist.txt | 139 ++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 webapp/data/languages/ko/ko_blocklist.txt diff --git a/webapp/app.py b/webapp/app.py index 229fa2ae..1ee1f430 100644 --- a/webapp/app.py +++ b/webapp/app.py @@ -680,6 +680,14 @@ def __init__(self, language_code, word_list, keyboard_layout=None): # Include diacritic base characters whose variants appear in the word list. # This allows keyboards using base forms (e.g., Compatibility Jamo) to work # with word lists using variant forms (e.g., Hangul Jamo). + # + # Languages using this mechanism: + # - Korean (ko): Compatibility Jamo ↔ Hangul Jamo (different Unicode blocks) + # - German (de): s ↔ ß (sharp S treated as variant of s) + # - European languages: base letters ↔ accented variants (a ↔ ä, o ↔ ö) + # + # Future: languages with composition-based scripts (e.g., Devanagari for Hindi, + # Thai, Khmer) may need similar keyboard↔wordlist normalization if added. diacritic_map = self.config.get("diacritic_map", {}) chars_set = set(self.characters) for base, variants in diacritic_map.items(): diff --git a/webapp/data/languages/ko/ko_blocklist.txt b/webapp/data/languages/ko/ko_blocklist.txt new file mode 100644 index 00000000..f203acf4 --- /dev/null +++ b/webapp/data/languages/ko/ko_blocklist.txt @@ -0,0 +1,139 @@ +# Korean compound jongseong blocklist +# These words contain compound final consonants (겹받침) like ㄺ, ㄻ, ㄼ, etc. +# that are not on the default keyboard layout. They remain valid guesses +# (playable via the Full keyboard layout) but are excluded from daily selection. +# +# Future improvement: decompose compound jongseong into individual jamo and +# use 6 cells per word (like 꼬들/kordle.kr does), which would eliminate the +# need for compound keys entirely. See ko_keyboard.json for details. +# Total: 129 words + +갉다 +갉아 +값싸 +값져 +값해 +곪다 +곪아 +곯다 +곯려 +곯아 +굵기 +굵다 +굵어 +굶겨 +굶다 +굶어 +긁다 +긁어 +긁혀 +기슭 +까닭 +꿇다 +꿇려 +꿇어 +끊겨 +끊다 +끊어 +끊여 +끓다 +끓어 +끓여 +낡다 +낡아 +넓다 +넓어 +넓이 +넓혀 +늙다 +늙어 +닭띠 +닮다 +닮아 +닳다 +닳아 +떫다 +떫어 +뚫다 +뚫려 +뚫어 +많다 +많아 +많이 +맑다 +맑아 +묽다 +묽어 +밝기 +밝다 +밝아 +밝혀 +밝히 +밟다 +밟아 +밟혀 +붉다 +붉어 +붉혀 +삶다 +삶아 +섧다 +섧어 +수탉 +싫다 +싫어 +앉다 +앉아 +앉혀 +않다 +않아 +앓다 +앓아 +얇다 +얇아 +얹다 +얹어 +얹혀 +얽다 +얽매 +얽어 +얽혀 +없다 +없애 +없어 +없이 +여덟 +엷다 +엷어 +옭다 +옭매 +옭아 +옮겨 +옮다 +옮아 +옳다 +옳소 +옳아 +외곬 +읊다 +읊어 +읽기 +읽다 +읽어 +읽혀 +잃다 +잃어 +젊다 +젊어 +제값 +짊다 +짊어 +짧다 +짧아 +칡차 +핥다 +핥아 +훑다 +훑어 +흙내 +흙비 From f8b93a958c922db313925aac83be404ad891acfa Mon Sep 17 00:00:00 2001 From: Hugo Montenegro Date: Sat, 14 Mar 2026 20:14:03 +0000 Subject: [PATCH 4/5] feat: physical keyboard support for Korean (bypass IME) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Maps physical key codes (event.code) to jamo characters, bypassing the OS IME which would otherwise compose syllable blocks. Uses the standard Korean 2-set (Dubeolsik) layout: Q→ㅂ, W→ㅈ, E→ㄷ, etc. with Shift for double consonants (Shift+Q→ㅃ, Shift+T→ㅆ, etc.). The physical_key_map config is universal — any language needing IME bypass can add one to their language_config.json. --- frontend/src/game.ts | 13 ++++++++++++- frontend/src/types/index.ts | 5 +++++ webapp/data/languages/ko/language_config.json | 11 +++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/frontend/src/game.ts b/frontend/src/game.ts index 07af99f1..d06c9c05 100644 --- a/frontend/src/game.ts +++ b/frontend/src/game.ts @@ -631,7 +631,18 @@ export const createGameApp = () => { keyDown(event: KeyboardEvent | { key: string }): void { if (this.animating) return; - const key = event.key; + + // Physical keyboard → character mapping (bypasses IME for Korean, etc.) + let key = event.key; + const physicalKeyMap = this.config?.physical_key_map; + if (physicalKeyMap && 'code' in event) { + const code = event.shiftKey ? `Shift${event.code}` : event.code; + const mapped = physicalKeyMap[code]; + if (mapped) { + event.preventDefault(); + key = mapped; + } + } if (key === 'Escape') { this.showHelpModal = false; diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index 8e3b596e..7f548ef5 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -61,6 +61,11 @@ export interface LanguageConfig { * Example for Greek: { "σ": "ς" } */ final_form_map?: Record; + /** Optional physical key → character map for bypassing IME composition. + * Maps KeyboardEvent.code values to characters. + * Example for Korean: { "KeyQ": "ㅂ", "ShiftKeyQ": "ㅃ", ... } + */ + physical_key_map?: Record; } // ============================================================================= diff --git a/webapp/data/languages/ko/language_config.json b/webapp/data/languages/ko/language_config.json index 33c567ca..47ea1393 100644 --- a/webapp/data/languages/ko/language_config.json +++ b/webapp/data/languages/ko/language_config.json @@ -74,6 +74,17 @@ "ㅢ": ["ᅴ"], "ㅣ": ["ᅵ"] }, + "physical_key_map": { + "KeyQ": "ㅂ", "KeyW": "ㅈ", "KeyE": "ㄷ", "KeyR": "ㄱ", "KeyT": "ㅅ", + "KeyY": "ㅛ", "KeyU": "ㅕ", "KeyI": "ㅑ", "KeyO": "ㅐ", "KeyP": "ㅔ", + "KeyA": "ㅁ", "KeyS": "ㄴ", "KeyD": "ㅇ", "KeyF": "ㄹ", "KeyG": "ㅎ", + "KeyH": "ㅗ", "KeyJ": "ㅓ", "KeyK": "ㅏ", "KeyL": "ㅣ", + "KeyZ": "ㅋ", "KeyX": "ㅌ", "KeyC": "ㅊ", "KeyV": "ㅍ", + "KeyB": "ㅠ", "KeyN": "ㅜ", "KeyM": "ㅡ", + "ShiftKeyQ": "ㅃ", "ShiftKeyW": "ㅉ", "ShiftKeyE": "ㄸ", + "ShiftKeyR": "ㄲ", "ShiftKeyT": "ㅆ", + "ShiftKeyO": "ㅒ", "ShiftKeyP": "ㅖ" + }, "help": { "title": "게임 방법 ", "title_2": "예 ", From 6f3f7aafd5a11c86f1420ff41378c6fe39e99049 Mon Sep 17 00:00:00 2001 From: Hugo Montenegro Date: Sat, 14 Mar 2026 20:54:32 +0000 Subject: [PATCH 5/5] fix: hide diacritic hints on Korean keyboard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Korean diacritic_map is for internal Unicode normalization (Compatibility Jamo ↔ Hangul Jamo), not player-visible accent variants. The sub-key hints (ᄇ/ᆸ) are meaningless to players and add visual noise. Adds hide_diacritic_hints config flag — keeps hints working for European languages (German ä/ö/ü/ß, etc.) where they're genuinely useful. --- webapp/app.py | 5 +++++ webapp/data/languages/ko/language_config.json | 1 + 2 files changed, 6 insertions(+) diff --git a/webapp/app.py b/webapp/app.py index 1ee1f430..6a755218 100644 --- a/webapp/app.py +++ b/webapp/app.py @@ -792,6 +792,11 @@ def _build_key_diacritic_hints(self): for key in row: keyboard_keys.add(key.lower()) + # Hide diacritic hints when the map is used for encoding normalization + # (e.g., Korean Jamo) rather than player-visible accent variants. + if self.config.get("hide_diacritic_hints"): + return {} + hints = {} for base_char, variants in diacritic_map.items(): if base_char.lower() in keyboard_keys: diff --git a/webapp/data/languages/ko/language_config.json b/webapp/data/languages/ko/language_config.json index 47ea1393..992dea63 100644 --- a/webapp/data/languages/ko/language_config.json +++ b/webapp/data/languages/ko/language_config.json @@ -23,6 +23,7 @@ "language_code_3": "", "language_code_iso_639_3": "", "right_to_left": "false", + "hide_diacritic_hints": true, "diacritic_map": { "ㄱ": ["ᄀ", "ᆨ"], "ㄲ": ["ᄁ", "ᆩ"],