728x90
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hangul Keyboard IME</title>
<style>
body { font-family: sans-serif; padding: 20px; }
#output { border: 1px solid #ccc; padding: 10px; width: 100%; min-height: 150px; }
#composing { font-size: 1.5em; margin-top: 10px; padding: 5px; border: 1px solid #aaa; min-height: 30px; }
p { max-width: 600px; }
</style>
</head>
<body>
<h1>Hangul Keyboard IME</h1>
<p>Type on your English keyboard below. The text will be converted into Hangul syllables following the composition rules (initial consonant + medial vowel + optional final consonant).</p>
<p><strong>Output:</strong></p>
<div id="output"></div>
<p><strong>Current Composition:</strong></p>
<div id="composing"></div>
<script>
/***** Data Structures for Hangul Composition *****/
const initials = ['ㄱ','ㄲ','ㄴ','ㄷ','ㄸ','ㄹ','ㅁ','ㅂ','ㅃ','ㅅ','ㅆ','ㅇ','ㅈ','ㅉ','ㅊ','ㅋ','ㅌ','ㅍ','ㅎ'];
const medials = ['ㅏ','ㅐ','ㅑ','ㅒ','ㅓ','ㅔ','ㅕ','ㅖ','ㅗ','ㅘ','ㅙ','ㅚ','ㅛ','ㅜ','ㅝ','ㅞ','ㅟ','ㅠ','ㅡ','ㅢ','ㅣ'];
const finals = ['','ㄱ','ㄲ','ㄳ','ㄴ','ㄵ','ㄶ','ㄷ','ㄹ','ㄺ','ㄻ','ㄼ','ㄽ','ㄾ','ㄿ','ㅀ','ㅁ','ㅂ','ㅄ','ㅅ','ㅆ','ㅇ','ㅈ','ㅊ','ㅋ','ㅌ','ㅍ','ㅎ'];
// Map from English-key (Dubeolsik layout) to Hangul jamo.
const keyMap = {
// Consonants
'r': { type: 'consonant', jamo: 'ㄱ' },
'R': { type: 'consonant', jamo: 'ㄲ' },
's': { type: 'consonant', jamo: 'ㄴ' },
'e': { type: 'consonant', jamo: 'ㄷ' },
'E': { type: 'consonant', jamo: 'ㄸ' },
'f': { type: 'consonant', jamo: 'ㄹ' },
'a': { type: 'consonant', jamo: 'ㅁ' },
'q': { type: 'consonant', jamo: 'ㅂ' },
'Q': { type: 'consonant', jamo: 'ㅃ' },
't': { type: 'consonant', jamo: 'ㅅ' },
'T': { type: 'consonant', jamo: 'ㅆ' },
'd': { type: 'consonant', jamo: 'ㅇ' },
'w': { type: 'consonant', jamo: 'ㅈ' },
'W': { type: 'consonant', jamo: 'ㅉ' },
'c': { type: 'consonant', jamo: 'ㅊ' },
'z': { type: 'consonant', jamo: 'ㅋ' },
'x': { type: 'consonant', jamo: 'ㅌ' },
'v': { type: 'consonant', jamo: 'ㅍ' },
'g': { type: 'consonant', jamo: 'ㅎ' },
// Vowels
'k': { type: 'vowel', jamo: 'ㅏ' },
'o': { type: 'vowel', jamo: 'ㅐ' },
'i': { type: 'vowel', jamo: 'ㅑ' },
// (Skipping shift variant for ㅒ)
'j': { type: 'vowel', jamo: 'ㅓ' },
'p': { type: 'vowel', jamo: 'ㅔ' },
'u': { type: 'vowel', jamo: 'ㅕ' },
'P': { type: 'vowel', jamo: 'ㅖ' },
'h': { type: 'vowel', jamo: 'ㅗ' },
'y': { type: 'vowel', jamo: 'ㅛ' },
'n': { type: 'vowel', jamo: 'ㅜ' },
'b': { type: 'vowel', jamo: 'ㅠ' },
'm': { type: 'vowel', jamo: 'ㅡ' },
'l': { type: 'vowel', jamo: 'ㅣ' }
};
// Compound vowels: if a vowel is already present, check if the new vowel can combine.
const compoundVowels = {
'ㅗ': { 'ㅏ': 'ㅘ', 'ㅐ': 'ㅙ', 'ㅣ': 'ㅚ' },
'ㅜ': { 'ㅓ': 'ㅝ', 'ㅔ': 'ㅞ', 'ㅣ': 'ㅟ' },
'ㅡ': { 'ㅣ': 'ㅢ' }
};
// Compound final consonants (for when adding a second consonant after a final)
const compoundFinals = {
'ㄱ': { 'ㅅ': 'ㄳ' },
'ㄴ': { 'ㅈ': 'ㄵ', 'ㅎ': 'ㄶ' },
'ㄹ': { 'ㄱ': 'ㄺ', 'ㅁ': 'ㄻ', 'ㅂ': 'ㄼ', 'ㅅ': 'ㄽ', 'ㅌ': 'ㄾ', 'ㅍ': 'ㄿ', 'ㅎ': 'ㅀ' },
'ㅂ': { 'ㅅ': 'ㅄ' }
};
// For backspace handling when a compound final is present:
const decomposeFinal = {
'ㄳ': ['ㄱ', 'ㅅ'],
'ㄵ': ['ㄴ', 'ㅈ'],
'ㄶ': ['ㄴ', 'ㅎ'],
'ㄺ': ['ㄹ', 'ㄱ'],
'ㄻ': ['ㄹ', 'ㅁ'],
'ㄼ': ['ㄹ', 'ㅂ'],
'ㄽ': ['ㄹ', 'ㅅ'],
'ㄾ': ['ㄹ', 'ㅌ'],
'ㄿ': ['ㄹ', 'ㅍ'],
'ㅀ': ['ㄹ', 'ㅎ'],
'ㅄ': ['ㅂ', 'ㅅ']
};
/***** State Variables *****/
let currentSyllable = { initial: "", medial: "", final: "" };
let composedText = "";
// Display elements
const outputDiv = document.getElementById("output");
const composingDiv = document.getElementById("composing");
function updateDisplay() {
outputDiv.textContent = composedText;
composingDiv.textContent = composeSyllable(currentSyllable);
}
// Compose a Hangul syllable using the Unicode composition formula.
function composeSyllable(syllable) {
if (syllable.initial && syllable.medial) {
let initIndex = initials.indexOf(syllable.initial);
let medIndex = medials.indexOf(syllable.medial);
let finIndex = finals.indexOf(syllable.final);
if (initIndex === -1 || medIndex === -1 || finIndex === -1) {
return syllable.initial + syllable.medial + syllable.final;
}
return String.fromCharCode(0xAC00 + (initIndex * 588) + (medIndex * 28) + finIndex);
} else {
return syllable.initial + syllable.medial + syllable.final;
}
}
// Commit the current syllable and reset.
function commitSyllable() {
composedText += composeSyllable(currentSyllable);
currentSyllable = { initial: "", medial: "", final: "" };
}
/***** Key Event Handling *****/
document.addEventListener("keydown", function(e) {
// --- Ignore Pure Modifier Keys ---
if (["Shift", "Control", "Alt", "Meta"].includes(e.key)) {
return; // Do nothing if the pressed key is just a modifier.
}
// --- Backspace Handling ---
if (e.key === "Backspace") {
e.preventDefault();
if (currentSyllable.final) {
if (currentSyllable.final.length === 2 && decomposeFinal[currentSyllable.final]) {
currentSyllable.final = decomposeFinal[currentSyllable.final][0];
} else {
currentSyllable.final = "";
}
} else if (currentSyllable.medial) {
currentSyllable.medial = "";
} else if (currentSyllable.initial) {
currentSyllable.initial = "";
} else {
composedText = composedText.slice(0, -1);
}
updateDisplay();
return;
}
// --- Space Handling ---
if (e.key === " ") {
e.preventDefault();
commitSyllable();
composedText += " ";
updateDisplay();
return;
}
// Look up the mapping for the pressed key.
let mapping = keyMap[e.key];
if (!mapping) {
// If key not mapped, commit current syllable and output the key as-is.
commitSyllable();
composedText += e.key;
updateDisplay();
return;
}
e.preventDefault();
/***** Process Consonant and Vowel Input *****/
if (mapping.type === "consonant") {
if (!currentSyllable.initial) {
currentSyllable.initial = mapping.jamo;
}
else if (currentSyllable.initial && !currentSyllable.medial) {
currentSyllable.initial = mapping.jamo;
}
else if (currentSyllable.initial && currentSyllable.medial) {
if (!currentSyllable.final) {
currentSyllable.final = mapping.jamo;
} else {
let currFinal = currentSyllable.final;
if (compoundFinals[currFinal] && compoundFinals[currFinal][mapping.jamo]) {
currentSyllable.final = compoundFinals[currFinal][mapping.jamo];
} else {
commitSyllable();
currentSyllable.initial = mapping.jamo;
}
}
}
}
else if (mapping.type === "vowel") {
if (!currentSyllable.initial) {
currentSyllable.initial = "ㅇ";
currentSyllable.medial = mapping.jamo;
}
else if (currentSyllable.initial && !currentSyllable.medial) {
currentSyllable.medial = mapping.jamo;
}
else if (currentSyllable.initial && currentSyllable.medial && !currentSyllable.final) {
let currMedial = currentSyllable.medial;
if (compoundVowels[currMedial] && compoundVowels[currMedial][mapping.jamo]) {
currentSyllable.medial = compoundVowels[currMedial][mapping.jamo];
} else {
commitSyllable();
currentSyllable.initial = "ㅇ";
currentSyllable.medial = mapping.jamo;
}
}
else if (currentSyllable.initial && currentSyllable.medial && currentSyllable.final) {
let movedConsonant = currentSyllable.final;
if (movedConsonant.length === 2 && decomposeFinal[movedConsonant]) {
let decomposed = decomposeFinal[movedConsonant];
currentSyllable.final = decomposed[0];
commitSyllable();
currentSyllable.initial = decomposed[1];
currentSyllable.medial = mapping.jamo;
} else {
currentSyllable.final = "";
commitSyllable();
currentSyllable.initial = movedConsonant;
currentSyllable.medial = mapping.jamo;
}
}
}
updateDisplay();
});
</script>
</body>
</html>
//판도리카 !
728x90
'호그와트' 카테고리의 다른 글
피아노 게임 (0) | 2025.02.25 |
---|---|
mini go-lf game (0) | 2025.02.07 |
자~ 골라요 골라 (0) | 2025.01.21 |
수학을 한다는 거 (0) | 2024.11.26 |
crazy attack !!!!!!!!!!! (0) | 2024.11.22 |