forked from extern/Unexpected-Keyboard
Hangul support (#595)
* Hangul support This works with two new kinds of keys (Hangul_initial and Hangul_medial) that carry a precomposed hangul syllable and act as modifiers. The hangul syllables are composed algorithmically. * Add shift layer to Dubeolsik layout
This commit is contained in:
parent
d96414c6c6
commit
69ab869079
@ -52,6 +52,12 @@ public final class KeyModifier
|
|||||||
return modify(k, mod.getModifier());
|
return modify(k, mod.getModifier());
|
||||||
case Compose_pending:
|
case Compose_pending:
|
||||||
return ComposeKey.apply(mod.getPendingCompose(), k);
|
return ComposeKey.apply(mod.getPendingCompose(), k);
|
||||||
|
case Hangul_initial:
|
||||||
|
if (k.equals(mod)) // Allow typing the initial in letter form
|
||||||
|
return KeyValue.makeStringKey(k.getString(), KeyValue.FLAG_GREYED);
|
||||||
|
return combine_hangul_initial(k, mod.getHangulPrecomposed());
|
||||||
|
case Hangul_medial:
|
||||||
|
return combine_hangul_medial(k, mod.getHangulPrecomposed());
|
||||||
}
|
}
|
||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
@ -1234,4 +1240,108 @@ public final class KeyModifier
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Compose the precomposed initial with the medial [kv]. */
|
||||||
|
private static KeyValue combine_hangul_initial(KeyValue kv, int precomposed)
|
||||||
|
{
|
||||||
|
switch (kv.getKind())
|
||||||
|
{
|
||||||
|
case Char:
|
||||||
|
return combine_hangul_initial(kv, kv.getChar(), precomposed);
|
||||||
|
case Hangul_initial:
|
||||||
|
// No initials are expected to compose, grey out
|
||||||
|
return kv.withFlags(kv.getFlags() | KeyValue.FLAG_GREYED);
|
||||||
|
default:
|
||||||
|
return kv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static KeyValue combine_hangul_initial(KeyValue kv, char medial,
|
||||||
|
int precomposed)
|
||||||
|
{
|
||||||
|
int medial_idx;
|
||||||
|
switch (medial)
|
||||||
|
{
|
||||||
|
// Vowels
|
||||||
|
case 'ㅏ': medial_idx = 0; break;
|
||||||
|
case 'ㅐ': medial_idx = 1; break;
|
||||||
|
case 'ㅑ': medial_idx = 2; break;
|
||||||
|
case 'ㅒ': medial_idx = 3; break;
|
||||||
|
case 'ㅓ': medial_idx = 4; break;
|
||||||
|
case 'ㅔ': medial_idx = 5; break;
|
||||||
|
case 'ㅕ': medial_idx = 6; break;
|
||||||
|
case 'ㅖ': medial_idx = 7; break;
|
||||||
|
case 'ㅗ': medial_idx = 8; break;
|
||||||
|
case 'ㅘ': medial_idx = 9; break;
|
||||||
|
case 'ㅙ': medial_idx = 10; break;
|
||||||
|
case 'ㅚ': medial_idx = 11; break;
|
||||||
|
case 'ㅛ': medial_idx = 12; break;
|
||||||
|
case 'ㅜ': medial_idx = 13; break;
|
||||||
|
case 'ㅝ': medial_idx = 14; break;
|
||||||
|
case 'ㅞ': medial_idx = 15; break;
|
||||||
|
case 'ㅟ': medial_idx = 16; break;
|
||||||
|
case 'ㅠ': medial_idx = 17; break;
|
||||||
|
case 'ㅡ': medial_idx = 18; break;
|
||||||
|
case 'ㅢ': medial_idx = 19; break;
|
||||||
|
case 'ㅣ': medial_idx = 20; break;
|
||||||
|
// Grey-out uncomposable characters
|
||||||
|
default: return kv.withFlags(kv.getFlags() | KeyValue.FLAG_GREYED);
|
||||||
|
}
|
||||||
|
return KeyValue.makeHangulMedial(precomposed, medial_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Combine the precomposed medial with the final [kv]. */
|
||||||
|
private static KeyValue combine_hangul_medial(KeyValue kv, int precomposed)
|
||||||
|
{
|
||||||
|
switch (kv.getKind())
|
||||||
|
{
|
||||||
|
case Char:
|
||||||
|
return combine_hangul_medial(kv, kv.getChar(), precomposed);
|
||||||
|
case Hangul_initial:
|
||||||
|
// Finals that can also be initials have this kind.
|
||||||
|
return combine_hangul_medial(kv, kv.getString().charAt(0), precomposed);
|
||||||
|
default:
|
||||||
|
return kv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static KeyValue combine_hangul_medial(KeyValue kv, char c,
|
||||||
|
int precomposed)
|
||||||
|
{
|
||||||
|
int final_idx;
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case ' ': final_idx = 0; break;
|
||||||
|
case 'ㄱ': final_idx = 1; break;
|
||||||
|
case 'ㄲ': final_idx = 2; break;
|
||||||
|
case 'ㄳ': final_idx = 3; break;
|
||||||
|
case 'ㄴ': final_idx = 4; break;
|
||||||
|
case 'ㄵ': final_idx = 5; break;
|
||||||
|
case 'ㄶ': final_idx = 6; break;
|
||||||
|
case 'ㄷ': final_idx = 7; break;
|
||||||
|
case 'ㄹ': final_idx = 8; break;
|
||||||
|
case 'ㄺ': final_idx = 9; break;
|
||||||
|
case 'ㄻ': final_idx = 10; break;
|
||||||
|
case 'ㄼ': final_idx = 11; break;
|
||||||
|
case 'ㄽ': final_idx = 12; break;
|
||||||
|
case 'ㄾ': final_idx = 13; break;
|
||||||
|
case 'ㄿ': final_idx = 14; break;
|
||||||
|
case 'ㅀ': final_idx = 15; break;
|
||||||
|
case 'ㅁ': final_idx = 16; break;
|
||||||
|
case 'ㅂ': final_idx = 17; break;
|
||||||
|
case 'ㅄ': final_idx = 18; break;
|
||||||
|
case 'ㅅ': final_idx = 19; break;
|
||||||
|
case 'ㅆ': final_idx = 20; break;
|
||||||
|
case 'ㅇ': final_idx = 21; break;
|
||||||
|
case 'ㅈ': final_idx = 22; break;
|
||||||
|
case 'ㅊ': final_idx = 23; break;
|
||||||
|
case 'ㅋ': final_idx = 24; break;
|
||||||
|
case 'ㅌ': final_idx = 25; break;
|
||||||
|
case 'ㅍ': final_idx = 26; break;
|
||||||
|
case 'ㅎ': final_idx = 27; break;
|
||||||
|
// Grey-out uncomposable characters
|
||||||
|
default: return kv.withFlags(kv.getFlags() | KeyValue.FLAG_GREYED);
|
||||||
|
}
|
||||||
|
return KeyValue.makeHangulFinal(precomposed, final_idx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,8 +86,8 @@ public final class KeyValue implements Comparable<KeyValue>
|
|||||||
|
|
||||||
public static enum Kind
|
public static enum Kind
|
||||||
{
|
{
|
||||||
Char, String, Keyevent, Event, Compose_pending, Modifier, Editing,
|
Char, String, Keyevent, Event, Compose_pending, Hangul_initial,
|
||||||
Placeholder,
|
Hangul_medial, Modifier, Editing, Placeholder,
|
||||||
Cursor_move // Value is encoded as a 16-bit integer
|
Cursor_move // Value is encoded as a 16-bit integer
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,6 +195,13 @@ public final class KeyValue implements Comparable<KeyValue>
|
|||||||
return (_code & VALUE_BITS);
|
return (_code & VALUE_BITS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Defined only when [getKind()] is [Kind.Hangul_initial] or
|
||||||
|
[Kind.Hangul_medial]. */
|
||||||
|
public int getHangulPrecomposed()
|
||||||
|
{
|
||||||
|
return (_code & VALUE_BITS);
|
||||||
|
}
|
||||||
|
|
||||||
/** Defined only when [getKind() == Kind.Cursor_move]. */
|
/** Defined only when [getKind() == Kind.Cursor_move]. */
|
||||||
public short getCursorMove()
|
public short getCursorMove()
|
||||||
{
|
{
|
||||||
@ -368,6 +375,25 @@ public final class KeyValue implements Comparable<KeyValue>
|
|||||||
flags | FLAG_KEY_FONT);
|
flags | FLAG_KEY_FONT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static KeyValue makeHangulInitial(String symbol, int initial_idx)
|
||||||
|
{
|
||||||
|
return new KeyValue(symbol, Kind.Hangul_initial, initial_idx * 588 + 44032,
|
||||||
|
FLAG_LATCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyValue makeHangulMedial(int precomposed, int medial_idx)
|
||||||
|
{
|
||||||
|
precomposed += medial_idx * 28;
|
||||||
|
return new KeyValue(String.valueOf((char)precomposed), Kind.Hangul_medial,
|
||||||
|
precomposed, FLAG_LATCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyValue makeHangulFinal(int precomposed, int final_idx)
|
||||||
|
{
|
||||||
|
precomposed += final_idx;
|
||||||
|
return KeyValue.makeCharKey((char)precomposed);
|
||||||
|
}
|
||||||
|
|
||||||
/** Make a key that types a string. A char key is returned for a string of
|
/** Make a key that types a string. A char key is returned for a string of
|
||||||
length 1. */
|
length 1. */
|
||||||
public static KeyValue makeStringKey(String str, int flags)
|
public static KeyValue makeStringKey(String str, int flags)
|
||||||
@ -538,6 +564,27 @@ public final class KeyValue implements Comparable<KeyValue>
|
|||||||
case "f11_placeholder": return placeholderKey(Placeholder.F11);
|
case "f11_placeholder": return placeholderKey(Placeholder.F11);
|
||||||
case "f12_placeholder": return placeholderKey(Placeholder.F12);
|
case "f12_placeholder": return placeholderKey(Placeholder.F12);
|
||||||
|
|
||||||
|
// Korean Hangul
|
||||||
|
case "ㄱ": return makeHangulInitial("ㄱ", 0);
|
||||||
|
case "ㄲ": return makeHangulInitial("ㄲ", 1);
|
||||||
|
case "ㄴ": return makeHangulInitial("ㄴ", 2);
|
||||||
|
case "ㄷ": return makeHangulInitial("ㄷ", 3);
|
||||||
|
case "ㄸ": return makeHangulInitial("ㄸ", 4);
|
||||||
|
case "ㄹ": return makeHangulInitial("ㄹ", 5);
|
||||||
|
case "ㅁ": return makeHangulInitial("ㅁ", 6);
|
||||||
|
case "ㅂ": return makeHangulInitial("ㅂ", 7);
|
||||||
|
case "ㅃ": return makeHangulInitial("ㅃ", 8);
|
||||||
|
case "ㅅ": return makeHangulInitial("ㅅ", 9);
|
||||||
|
case "ㅆ": return makeHangulInitial("ㅆ", 10);
|
||||||
|
case "ㅇ": return makeHangulInitial("ㅇ", 11);
|
||||||
|
case "ㅈ": return makeHangulInitial("ㅈ", 12);
|
||||||
|
case "ㅉ": return makeHangulInitial("ㅉ", 13);
|
||||||
|
case "ㅊ": return makeHangulInitial("ㅊ", 14);
|
||||||
|
case "ㅋ": return makeHangulInitial("ㅋ", 15);
|
||||||
|
case "ㅌ": return makeHangulInitial("ㅌ", 16);
|
||||||
|
case "ㅍ": return makeHangulInitial("ㅍ", 17);
|
||||||
|
case "ㅎ": return makeHangulInitial("ㅎ", 18);
|
||||||
|
|
||||||
/* Fallback to a string key that types its name */
|
/* Fallback to a string key that types its name */
|
||||||
default: return makeStringKey(name);
|
default: return makeStringKey(name);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,16 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<keyboard name="두벌식 (Korean)" script="hangul">
|
<keyboard name="두벌식 (Korean)" script="hangul">
|
||||||
|
<modmap>
|
||||||
|
<!-- The hangul character don't have shifted variants, this is specific to
|
||||||
|
the layout. -->
|
||||||
|
<shift a="ㅂ" b="ㅃ"/>
|
||||||
|
<shift a="ㅈ" b="ㅉ"/>
|
||||||
|
<shift a="ㄷ" b="ㄸ"/>
|
||||||
|
<shift a="ㄱ" b="ㄲ"/>
|
||||||
|
<shift a="ㅅ" b="ㅆ"/>
|
||||||
|
<shift a="ㅐ" b="ㅒ"/>
|
||||||
|
<shift a="ㅔ" b="ㅖ"/>
|
||||||
|
</modmap>
|
||||||
<row>
|
<row>
|
||||||
<key key0="ㅂ" key2="1" key4="esc"/>
|
<key key0="ㅂ" key2="1" key4="esc"/>
|
||||||
<key key0="ㅈ" key1="~" key2="2" key3="\@"/>
|
<key key0="ㅈ" key1="~" key2="2" key3="\@"/>
|
||||||
|
Loading…
Reference in New Issue
Block a user