Phonetic Korean Keyboard

Is it feasible to develop a Korean keyboard based on this layout?
hngl

Hi Mauro. I’m glad you are having fun looking at keyboard possibilities. I’m sure you could come up with a layout based on that. Remember that desktop keyboards will need to use a hardware keyboard to access keys and then a touch layout is much more flexible in what the layout can look like.

You might want to focus on one keyboard and follow it the whole way from developing the whole package in Keyman developer, then going through the Github process to get it published. Then you’ll understand the pitfalls you may encounter along the way. Once you’ve successfully done one, you can move on to other keyboards.

I cant make a korean keyboard from scratch with thousands jamos. I wanted just reorganize the keys positions from the current keyboard (its not a romaja keyboard like hnc and GongjinCheong), but theres no korean keyboard file i can work. i plan to use the desktop version. Does use hangul characters with unicode points makes it behave like a korean keyboard? I think not.

The difficult part of a Korean keyboard like this is combining jamo. One example of a Korean keyboard you could start with that supports this on Windows (and desktop web I think) is the korean_rr keyboard: keyboards/release/k/korean_rr/source at master · keymanapp/keyboards · GitHub

Hangul implementation:

  • Decomposed 256 jamos
  • Precomposed 11,172 syllables with 2350 used in modern hangul

Can i emulate the original layout and reorganize the keys? I dont need hanja or romanization. Only koreans letters.

My code dosnt work:

store(&VERSION) '10.0'
store(&NAME) 'Korean RR'
c 
c Keyboard follows the input conventions of Revised Romanization of Korean, as offically adopted by RoK (July 2000).
c To allow entry of all normally-used Hangul characters, the start of each syllable must be marked, by one of the following:
c (1) being the start of Korean characters in a run
c (2) being capitalized, or
c (c) following a space - the first space after a run of Korean will convert the pending jamo to Hangeul.
c 
c In each case, the IME will be visible until the last syallable has been converted to Hangeul.
c 
store(&mnemoniclayout)  '0'           
store(&capsalwaysoff)   '1'
store(&VISUALKEYBOARD) 'korean_rr.kvks'
store(&BITMAP) 'korean_rr.ico'
store(&KMW_EMBEDJS) 'korean_ime.js'

c store(HelpFile) 'welcome.htm'
store(&KMW_HELPTEXT) '<div><a href="http://help.keymanweb.com/go?keyboard=Keyboard_korean_rr" target="KeymanWebHelp">Help on this keyboard</a></div><div id=' U+0027 'Keyboard_Korean_IME' U+0027 '></div>'
store(&COPYRIGHT)    '© 2010-2023 SIL International'
c store(&LAYOUTFILE) 'korean_rr.keyman-touch-layout'
store(&KEYBOARDVERSION) '1.3'
store(&TARGETS) 'web'

begin Unicode > use(combineJamo)                                           

c Keys used for IME selection
store(numberKey)   '123456789' [K_NP1][K_NP2][K_NP3][K_NP4][K_NP5][K_NP6][K_NP7][K_NP8][K_NP9]                                                
store(digits)      '123456789123456789'

c Other number pad keys
store(numPadKey)   [K_NP0][K_NPPLUS][K_NPMINUS][K_NPSLASH][K_NPDOT][K_NPSTAR]
store(numPadChar)  '0+-/.*'

c Punctuation (and other) keys never used for romanized entry or selection
store(punctKey)    '0!@#$%^&*()-=_+`~[]{}\|;:",./<>?' "'"

store(ucLetter)    'ABCDEGHIJKLMNOPRSTUWY'     c upper-case letters used for starting a new Hangul
store(lcLetter)    'abcdeghijklmnoprstuwy'     c lower-case letters used for continuing a Hangul character
store(noJamo)      'fqvxzFQVXZ'                c keys that are not used for Korean romanization
                              
store(choseongK)   'cgndrmbsjktphlCGNDRMBSJKTPHL'
store(choseongS)   'ᄎᄀᄂᄃᄅᄆᄇᄉᄌᄏᄐᄑᄒᄅᄎᄀᄂᄃᄅᄆᄇᄉᄌᄏᄐᄑᄒᄅ'

store(choseong)    'ᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑᄒ' U+1113 U+1114 U+1115 U+1116 U+1117 U+1118 U+1119 U+111A U+111B \
                   U+111C U+111D U+111E U+111F U+1120 U+1121 U+1122 U+1123 U+1124 U+1125 U+1126 U+1127 U+1128 \ 
                   U+1129 U+112A U+112B U+112C U+112D U+112E U+112F U+1130 U+1131 U+1132 U+1133 U+1134 U+1135 \
                   U+1136 U+1137 U+1138 U+1139 U+113A U+113B U+113C U+113D U+113E U+113F U+1140 U+1141 U+1142 \
                   U+1143 U+1144 U+1145 U+1146 U+1147 U+1148 U+1149 U+114A U+114B U+114C U+114D U+114E U+114F \
                   U+1150 U+1151 U+1152 U+1153 U+1154 U+1155 U+1156 U+1157 U+1158 U+1159

store(jungseongK)  'auoieywAUOIEYW'
store(jungseongS)  'ᅡᅮᅩᅵᅦᅨᅰᅡᅮᅩᅵ

ᅦᅨᅰ'

store(jungseong)   'ᅡᅡᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵᅶᅷᅸᅹᅺᅻᅼᅽᅾᅿ' \
                   'ᆨᆩᆪᆫᆬᆭᆮᆯᆰᆱᆲᆳᆴᆵᆶᆷᆸᆹᆺᆻᆼᆽᆾᆿᇀᇁᇂᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑᄒ' \
                   'ᅡᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵᅶᅷᅸᅹᅺᅻᅼᅽᅾᅿᆨᆩᆪᆫᆬᆭᆮᆯᆰᆱᆲᆳᆴᆵᆶᆷᆸᆹᆺᆻᆼᆽᆾᆿᇀᇁᇂ'
                   
store(jongseongK)  'rqtwpsadfzxvkgQRTWPSADFZXVKG'
store(jongseongS)  'ᆨᆩᆪᆫᆬᆭᆮᆯᆰᆱᆲᆳᆴᆵᆶᆷᆸᆹᆺᆻᆼᆽᆾᆿᇀᇁᇂᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑᄒ' \
                   'ᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑᄒ' 'ᇂᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑᄒ'
                   
store(jongseong)   'ᆨᆩᆪᆫᆬᆭᆮᆯᆰᆱᆲᆳᆴᆵᆶᆷᆸᆹᆺᆻᆼᆽᆾᆿᇀᇁᇂᇇᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑᄒ' \
                   
'ᆨᆩᆪᆫᆬᆭᆮᆯᆰᆱᆲᆳᆴᆵᆶᆷᆸᆹᆺᆻᆼᆽᆾᆿᇀᇁᇂᇇᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑᄒ' \
                   'ᇂᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑᄒ'

store(consumeKey) [K_BKQUOTE] [K_F10] [K_F11] [K_F12] [K_F13] [K_F14] [K_F15] [K_F16] [K_F17] [K_F18] [K_F19] [K_F20] [K_F21] [K_F22] [K_F23] [K_F24] [K_TAB] [K_ESCAPE] [K_LWIN] [K_RWIN] [K_LCONTROL] [K_RCONTROL] [K_LMENU] [K_RMENU] [K_LSHIFT] [K_RSHIFT] [K_APPS] [K_CAPSLOCK] [K_NUMLOCK] [K_SCROLLLOCK] [K_PRINTSCREEN] [K_PAUSE] [K_INSERT] [K_HOME] [K_PGUP] [K_DEL] [K_END] [K_PGDN] [K_LEFT] [K_RIGHT] [K_UP] [K_DOWN] [K_SYSREQ] [K_MENU] [K_HELP] [K_BREAK]

group(main) using keys

c Dead keys
 dk(') + any(choseongK) > dk(choseong)
 dk(') + any(jungseongK) > dk(jungseong)
 dk(') + any(jongseongK) > dk(jongseong)
 dk(ᅠ) + any(choseongK) > dk(choseong)
 dk(ᅠ) + any(jungseongK) > dk(jungseong)
 dk(ᅠ) + any(jongseongK) > dk(jongseong)

 dk(ᅠ) + any(choseongS) > context
 dk(ᅠ) + any(jungseongS) > context
 dk(ᅠ) + any(jongseongS) > context

c Regular keys
 any(choseong) + any(jungseong)  > call(jamo_combine) call(show_ime)
 any(choseong) + any(jongseong)  > call(jamo_combine) call(show)

How do i remove the code for hanja? Whats de .dll included for?

  • The code you have shared doesn’t have any rules for the base keys – it relies on a previous character or deadkey already being present. So it will never match any of those rules.

  • The dk(') and dk( ) statements are not technically valid – the deadkeys need a name. I’m not sure what you are trying to do with those.

The DLL is used to convert the individual jamo characters into the combined Hangul syllables. (This could be done with thousands of Keyman rules but it’s not the best approach!) The only problem with the DLL is that it is Windows-only. We have a feature planned on our roadmap to make the call() statement more cross-platform, but we are some way off implementing it.

c Keyman keyboard generated by ImportKeyboard
c Imported: 2019-04-15 15:33:37
c
c Source Keyboard File: KBDUS.DLL
c Source KeyboardID: 00000409
c
c 

store(&VERSION) '10.0'
store(&NAME) 'Korean Phonetic'
store(&VISUALKEYBOARD) 'korean_phonetic.kvks'
store(&BITMAP) 'korean_phonetic.ico'
store(&LAYOUTFILE) 'korean_phonetic.keyman-touch-layout'
store(&COPYRIGHT) '© SIL International'
store(&KEYBOARDVERSION) '1.0'
store(&TARGETS) 'any'

begin Unicode > use(main)

store(cons) 'ᄀᄂᄃᄅᄆᄇᄉᄋᄌᄎᄏᄐᄑᄒ'
store(vowels) 'ᅡᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵ'
store(finals) 'ᆨᆩᆪᆫᆬᆭᆮᆯᆰᆱᆲᆳᆴᆵᆶᆷᆸᆹᆺᆻᆼᆽᆾᆿᇀᇁᇂ'

group(main) using keys

+ [K_SPACE] > use(finalize_hangul)

+ [K_0] > U+0030
+ [SHIFT K_0] > U+0029

+ [K_1] > U+0031
+ [SHIFT K_1] > U+0021

+ [K_2] > U+0032
+ [SHIFT K_2] > U+0040

+ [K_3] > U+0033
+ [SHIFT K_3] > U+0023

+ [K_4] > U+0034
+ [SHIFT K_4] > U+0024

+ [K_5] > U+0035
+ [SHIFT K_5] > U+0025

+ [K_6] > U+0036
+ [SHIFT K_6] > U+005e

+ [K_7] > U+0037
+ [SHIFT K_7] > U+0026

+ [K_8] > U+0038
+ [SHIFT K_8] > U+002a

+ [K_9] > U+0039
+ [SHIFT K_9] > U+0028

+ [NCAPS K_A] > U+314F
+ [CAPS K_A] > U+314F
+ [NCAPS SHIFT K_A] > U+314F
+ [CAPS SHIFT K_A] > U+314F

+ [NCAPS K_B] > U+3142
+ [CAPS K_B] > U+3143
+ [NCAPS SHIFT K_B] > U+3143
+ [CAPS SHIFT K_B] > U+3143

+ [NCAPS K_C] > U+314A
+ [CAPS K_C] > U+314A
+ [NCAPS SHIFT K_C] > U+314A
+ [CAPS SHIFT K_C] > U+314A

+ [NCAPS K_D] > U+3137
+ [CAPS K_D] > U+3138
+ [NCAPS SHIFT K_D] > U+3138
+ [CAPS SHIFT K_D] > U+3138

+ [NCAPS K_E] > U+3154
+ [CAPS K_E] > U+3156
+ [NCAPS SHIFT K_E] > U+3156
+ [CAPS SHIFT K_E] > U+3156

+ [NCAPS K_F] > U+3150
+ [CAPS K_F] > U+3152
+ [NCAPS SHIFT K_F] > U+3152
+ [CAPS SHIFT K_F] > U+3152

+ [NCAPS K_G] > U+3131
+ [CAPS K_G] > U+3132
+ [NCAPS SHIFT K_G] > U+3132
+ [CAPS SHIFT K_G] > U+3132

+ [NCAPS K_H] > U+314E
+ [CAPS K_H] > U+314E
+ [NCAPS SHIFT K_H] > U+314E
+ [CAPS SHIFT K_H] > U+314E

+ [NCAPS K_I] > U+3163
+ [CAPS K_I] > U+3163
+ [NCAPS SHIFT K_I] > U+3163
+ [CAPS SHIFT K_I] > U+3163

+ [NCAPS K_J] > U+3148
+ [CAPS K_J] > U+3149
+ [NCAPS SHIFT K_J] > U+3149
+ [CAPS SHIFT K_J] > U+3149

+ [NCAPS K_K] > U+314B
+ [CAPS K_K] > U+314B
+ [NCAPS SHIFT K_K] > U+314B
+ [CAPS SHIFT K_K] > U+314B

+ [NCAPS K_L] > U+3151
+ [CAPS K_L] > U+3151
+ [NCAPS SHIFT K_L] > U+3151
+ [CAPS SHIFT K_L] > U+3151

+ [NCAPS K_M] > U+3141
+ [CAPS K_M] > U+3141
+ [NCAPS SHIFT K_M] > U+3141
+ [CAPS SHIFT K_M] > U+3141

+ [NCAPS K_N] > U+3134
+ [CAPS K_N] > U+3134
+ [NCAPS SHIFT K_N] > U+3134
+ [CAPS SHIFT K_N] > U+3134

+ [NCAPS K_O] > U+3157
+ [CAPS K_O] > U+3157
+ [NCAPS SHIFT K_O] > U+3157
+ [CAPS SHIFT K_O] > U+3157

+ [NCAPS K_P] > U+314D
+ [CAPS K_P] > U+314D
+ [NCAPS SHIFT K_P] > U+314D
+ [CAPS SHIFT K_P] > U+314D

+ [NCAPS K_Q] > U+3147
+ [CAPS K_Q] > U+3147
+ [NCAPS SHIFT K_Q] > U+3147
+ [CAPS SHIFT K_Q] > U+3147

+ [NCAPS K_R] > U+3139
+ [CAPS K_R] > U+3139
+ [NCAPS SHIFT K_R] > U+3139
+ [CAPS SHIFT K_R] > U+3139

+ [NCAPS K_S] > U+3145
+ [CAPS K_S] > U+3146
+ [NCAPS SHIFT K_S] > U+3146
+ [CAPS SHIFT K_S] > U+3146

+ [NCAPS K_T] > U+314C
+ [CAPS K_T] > U+314C
+ [NCAPS SHIFT K_T] > U+314C
+ [CAPS SHIFT K_T] > U+314C

+ [NCAPS K_U] > U+315C
+ [CAPS K_U] > U+315C
+ [NCAPS SHIFT K_U] > U+315C
+ [CAPS SHIFT K_U] > U+315C

+ [NCAPS K_V] > U+3153
+ [CAPS K_V] > U+3153
+ [NCAPS SHIFT K_V] > U+3153
+ [CAPS SHIFT K_V] > U+3153

+ [NCAPS K_W] > U+315B
+ [CAPS K_W] > U+315B
+ [NCAPS SHIFT K_W] > U+315B
+ [CAPS SHIFT K_W] > U+315B

+ [NCAPS K_X] > U+3160
+ [CAPS K_X] > U+3160
+ [NCAPS SHIFT K_X] > U+3160
+ [CAPS SHIFT K_X] > U+3160

+ [NCAPS K_Y] > U+3161
+ [CAPS K_Y] > U+3161
+ [NCAPS SHIFT K_Y] > U+3161
+ [CAPS SHIFT K_Y] > U+3161

+ [NCAPS K_Z] > U+3155
+ [CAPS K_Z] > U+3155
+ [NCAPS SHIFT K_Z] > U+3155
+ [CAPS SHIFT K_Z] > U+3155

+ [K_COLON] > U+003b
+ [SHIFT K_COLON] > U+003a

+ [K_EQUAL] > U+003d
+ [SHIFT K_EQUAL] > U+002b

+ [K_COMMA] > U+002c
+ [SHIFT K_COMMA] > U+003c

+ [K_HYPHEN] > U+002d
+ [SHIFT K_HYPHEN] > U+005f

+ [K_PERIOD] > U+002e
+ [SHIFT K_PERIOD] > U+003e

+ [K_SLASH] > U+002f
+ [SHIFT K_SLASH] > U+003f

+ [K_BKQUOTE] > U+0060
+ [SHIFT K_BKQUOTE] > U+007e

+ [K_LBRKT] > U+005b
+ [SHIFT K_LBRKT] > U+007b

+ [K_BKSLASH] > U+005c
+ [SHIFT K_BKSLASH] > U+007c

+ [K_RBRKT] > U+005d
+ [SHIFT K_RBRKT] > U+007d

+ [K_QUOTE] > U+0027
+ [SHIFT K_QUOTE] > U+0022

+ [K_oE2] > U+005c
+ [SHIFT K_oE2] > U+007c

group(compose_hangul)
begin > compose_hangul
+ [cons] > use(set_init)
+ [vowels] > use(set_vowel)
+ [finals] > use(set_final)

group(set_init)
begin > context
+ any > store(init) + index(cons) > context

group(set_vowel)
begin > context
+ any(init) + [vowels] > store(vowel) + index(vowels) > context

group(set_final)
begin > context
+ any(vowel) + [finals] > U+AC00 + (index(cons) - 1) * 588 + (index(vowels) - 1) * 28 + index(finals) > context

group(finalize_hangul)
begin > context
+ any(init vowel finals) > context

I’ve found a solution. I’ll work with the korean morse keyboard file instead.


The Sylable-initial (Choseong) and final (Jongseong) works and shows on layout.
the vowels (Jungseong) are not showing and the jungseongPuO variable not working.
Is it because of the ‘u’ in?: any(jungseongPu) + ‘u’ > index(jungseongPuO, 1)

store(&Version) '10.0'
store(&NAME) 'Korean Morse (SIL)'
store(&TARGETS) 'desktop'
store(&VISUALKEYBOARD) 'sil_korean_morse.kvks'
store(&BITMAP) 'sil_korean_morse.ico'
store(&COPYRIGHT) '© 2006-2020 SIL International'
store(&KEYBOARDVERSION) '2.0'
store(&mnemoniclayout) '1'


begin Unicode > use(main)
                              
c Choseong (Sylable-initial consonants)
store(choseongSK) 'gndrmbsqjcktph'			 c keys
store(choseongS)  'ᄀᄂᄃᄅᄆᄇᄉᄋᄌᄎᄏᄐᄑᄒ'	 c output jamo
store(choseong)   'ᄀᄁᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎᄏᄐᄑᄒ' U+1113 U+1114 U+1115 U+1116 U+1117 U+1118 U+1119 U+111A U+111B \
                  U+111C U+111D U+111E U+111F U+1120 U+1121 U+1122 U+1123 U+1124 U+1125 U+1126 U+1127 U+1128 \ 
                  U+1129 U+112A U+112B U+112C U+112D U+112E U+112F U+1130 U+1131 U+1132 U+1133 U+1134 U+1135 \
                  U+1136 U+1137 U+1138 U+1139 U+113A U+113B U+113C U+113D U+113E U+113F U+1140 U+1141 U+1142 \
                  U+1143 U+1144 U+1145 U+1146 U+1147 U+1148 U+1149 U+114A U+114B U+114C U+114D U+114E U+114F \
                  U+1150 U+1151 U+1152 U+1153 U+1154 U+1155 U+1156 U+1157 U+1158 U+1159
                              
c Jungseong (Vowels)
store(jungseongSK) 'alvzowuxyi'			 c keys
store(jungseongS)  'ᅡᅣᅥᅧᅩᅭᅮᅲᅳᅵ'	 c output jamo
store(jungseongPu)  'ᅡᅣᅥᅧᅪᅩᅯᅮᅳ'
store(jungseongPuO) 'ᅢᅤᅦᅨᅫᅬᅰᅱᅴ'
store(jungseong)   U+1160 U+1161 U+1162 U+1163 U+1164 U+1165 U+1166 U+1167 U+1168 U+1169 U+116A U+116B U+116C U+116D U+116E U+116F \
                   U+1170 U+1171 U+1172 U+1173 U+1174 U+1175 U+1176 U+1177 U+1178 U+1179 U+117A U+117B U+117C U+117D U+117E U+117F \
                   U+1180 U+1181 U+1182 U+1183 U+1184 U+1185 U+1186 U+1187 U+1188 U+1189 U+118A U+118B U+118C U+118D U+118E U+118F \
                   U+1190 U+1191 U+1192 U+1193 U+1194 U+1195 U+1196 U+1197 U+1198 U+1199 U+119A U+119B U+119C U+119D U+119E U+119F \
                   U+11A0 U+11A1 U+11A2

c Jongseong (Sylable-final consonants)
store(jongseongSK) 'gndrmbsqjcktph'			 c keys
store(jongseongS)  'ᆨᆫᆮᆯᆷᆸᆺᆼᆽᆾᆿᇀᇁᇂ'	 c output jamo
store(jongseong)   U+11A8 U+11A9 U+11AA U+11AB U+11AC U+11AD U+11AE U+11AF \
                   U+11B0 U+11B1 U+11B2 U+11B3 U+11B4 U+11B5 U+11B6 U+11B7 U+11B8 U+11B9 U+11BA U+11BB U+11BC U+11BD U+11BE U+11BF \
                   U+11C0 U+11C1 U+11C2 U+11C3 U+11C4 U+11C5 U+11C6 U+11C7 U+11C8 U+11C9 U+11CA U+11CB U+11CC U+11CD U+11CE U+11CF \
                   U+11D0 U+11D1 U+11D2 U+11D3 U+11D4 U+11D5 U+11D6 U+11D7 U+11D8 U+11D9 U+11DA U+11DB U+11DC U+11DD U+11DE U+11DF \
                   U+11E0 U+11E1 U+11E2 U+11E3 U+11E4 U+11E5 U+11C6 U+11E7 U+11E8 U+11E9 U+11EA U+11EB U+11EC U+11ED U+11EE U+11EF \
                   U+11F0 U+11F1 U+11F2 U+11F3
                             
group(main) using keys

c Choseong - Sylable-initial consonants
+ any(choseongSK) > use(g_choseong)
any(choseong) + any(choseongSK) > context use(g_choseong)

c Jungseong - Vowels
any(choseong) + any(jungseongSK) > context use(g_jungseong)
any(choseong) any(jungseong) + any(jungseongSK) > context use(g_jungseong)

c Jongseong - Sylable-final consonants
any(choseong) any(jungseong) + any(jongseongSK) > context use(g_jongseong)
any(choseong) any(jungseong) any(jongseong) + any(jongseongSK) > context use(g_jongseong)

c Invalid sequences - prevent
any(jongseong) + any(jungseongSK) > context beep
any(jongseong) + any(choseongSK) > context beep
any(choseong) any(choseong) + any(choseongSK) > context beep

c Combining jamo
store(jamo_combine) 'jamo_combine.dll:jamo_combine'
+ ' ' > call(jamo_combine) dk(space)
dk(space)+' '>' '

c Other characters
store(punct_or_number) '1234567890!@#$%^&*()-=_+`~[]{}\|;:",./<>?' "'"
+ any(punct_or_number) > index(punct_or_number, 1)

nomatch > beep

c ==Choseong==
group(g_choseong) using keys

c Start a syllable
+ any(choseongSK) > index(choseongS, 1)
dk(space) + any(choseongSK) > index(choseongS, 2)

c second half of initial consonant - standard alphabet
'ᄀ' + 'g' > 'ᄁ'
'ᄃ' + 'd' > 'ᄄ'
'ᄇ' + 'b' > 'ᄈ'
'ᄉ' + 's' > 'ᄊ'
'ᄌ' + 'j' > 'ᄍ'

nomatch > beep

c ==Jungseong==
group(g_jungseong) using keys
         
any(choseong) + any(jungseongSK) > context index(jungseongS, 2)
any(jungseongPu) + 'u' > index(jungseongPuO, 1)
'ᅩ' + 'a' > 'ᅪ'
'ᅮ' + 'v' > 'ᅯ'

nomatch > beep

c ==Jongseong==
group(g_jongseong) using keys

any(jungseong) + any(jongseongSK) > context index(jongseongS, 2)

c combinations

'ᆨ' + 'g' > 'ᆩ'
'ᆺ' + 's' > 'ᆻ'

'ᆫ' + 'j' > 'ᆬ'
'ᆫ' + 'h' > 'ᆭ'
'ᆯ' + 'g' > 'ᆰ'
'ᆯ' + 'm' > 'ᆱ'
'ᆯ' + 'b' > 'ᆲ'
'ᆯ' + 's' > 'ᆳ'
'ᆯ' + 't' > 'ᆴ'
'ᆯ' + 'p' > 'ᆵ'
'ᆯ' + 'h' > 'ᆶ'
'ᆸ' + 's' > 'ᆹ'

nomatch > beep


I also ended up making it an autohotkey script that remaps the keys when using korean layout:
#SingleInstance force

q::d
w::y
e::p‎
E::P‎
r::f
t::x
y::m
u::n
i::l
o::h
p::v

a::k
s::t
S::T
d::e
D::E
f::o
F::O‎
g::r
G::R
h::g
j::w
J::W
k::z
l::i

z::u
x::b
c::c
v::j
b::q
B::Q
n::s
m::a

naratgul_keypad
Or used with a keypad.