@@ -13,6 +13,20 @@ @interface DKSTHangul () {
1313 NSMutableString *_buffer;
1414 NSMutableString *_completed;
1515}
16+
17+ // Old Hangul Choseongs
18+ #define CHOSEONG_YESIEUNG 0x114C // Yesieung (ㆁ)
19+ #define CHOSEONG_SSANGIEUNG 0x1147 // SsangIeung (ㆀ) - Shift+D
20+ #define CHOSEONG_PANSIOT 0x1140 // Bansiot (ㅿ)
21+ #define CHOSEONG_YEORINHIEUH 0x1159 // Yeorinhieuh (ㆆ)
22+ #define CHOSEONG_KAPYEOUNPHIEUP 0x1157 // KapyeounPhieup (ㆄ)
23+ #define CHOSEONG_SG 0x112D // Sios-Kiyeok (ㅺ)
24+ #define CHOSEONG_BS 0x112F // Sios-Tikeut (ㅼ)
25+ #define CHOSEONG_BJ 0x1132 // Sios-Pieup (ㅽ)
26+
27+ // Old Hangul Jungseongs
28+ #define JUNGSEONG_ARAEAE 0x11A1
29+
1630@end
1731
1832@implementation DKSTHangul
@@ -37,7 +51,31 @@ - (void)reset {
3751
3852- (NSString *)composedString {
3953 if (_cho == 0 && _jung == 0 && _jong == 0 ) return @" " ;
40- return [NSString stringWithFormat: @" %C " , [self currentSyllable ]];
54+ unichar s = [self currentSyllable ];
55+ if (s != 0 ) return [NSString stringWithFormat: @" %C " , s];
56+
57+ // Archaic / Non-combinable case: Use raw Jamo (0x11xx) instead of compatibility (0x31xx)
58+ // to allow OS rendering to form a cluster.
59+ NSMutableString *res = [NSMutableString string ];
60+ if (_cho) [res appendFormat: @" %C " , _cho];
61+ if (_jung) [res appendFormat: @" %C " , _jung];
62+ if (_jong) [res appendFormat: @" %C " , _jong];
63+ return res;
64+ }
65+
66+ - (void )flush {
67+ if (_cho == 0 && _jung == 0 && _jong == 0 ) return ;
68+
69+ unichar s = [self currentSyllable ];
70+ if (s != 0 ) {
71+ [_completed appendFormat: @" %C " , s];
72+ } else {
73+ // Archaic / Non-combinable case
74+ if (_cho) [_completed appendFormat: @" %C " , _cho];
75+ if (_jung) [_completed appendFormat: @" %C " , _jung];
76+ if (_jong) [_completed appendFormat: @" %C " , _jong];
77+ }
78+ _cho = 0 ; _jung = 0 ; _jong = 0 ;
4179}
4280
4381- (NSString *)commitString {
@@ -47,11 +85,18 @@ - (NSString *)commitString {
4785}
4886
4987// Check types
50- - (BOOL )isCho : (unichar )c { return c >= 0x1100 && c <= 0x1112 ; }
51- - (BOOL )isJung : (unichar )c { return c >= 0x1161 && c <= 0x1175 ; }
52- - (BOOL )isJong : (unichar )c { return (c >= 0x11A8 && c <= 0x11C2 ); }
88+ // Updated ranges for Old Hangul
89+ - (BOOL )isCho : (unichar )c { return (c >= 0x1100 && c <= 0x115F ); } // Expanded
90+ - (BOOL )isJung : (unichar )c { return (c >= 0x1161 && c <= 0x11A7 ); } // Expanded
91+ - (BOOL )isJong : (unichar )c { return (c >= 0x11A8 && c <= 0x11FF ); } // Expanded
5392
5493- (unichar )mapFromChar : (unichar )c {
94+ // Old Hangul Overrides for Shift+D/Shift+G
95+ if (self.oldHangulEnabled ) {
96+ if (c == ' D' ) return CHOSEONG_SSANGIEUNG; // ㆀ
97+ if (c == ' G' ) return CHOSEONG_KAPYEOUNPHIEUP; // ㆄ
98+ }
99+
55100 switch (c) {
56101 case ' q' : return 0x1107 ; case ' Q' : return 0x1108 ; // ㅂ, ㅃ
57102 case ' w' : return 0x110c ; case ' W' : return 0x110d ; // ㅈ, ㅉ
@@ -86,6 +131,28 @@ - (unichar)mapFromChar:(unichar)c {
86131 return 0 ;
87132}
88133
134+ - (unichar )combineCho : (unichar )a second : (unichar )b {
135+ if (!self.oldHangulEnabled ) return 0 ;
136+
137+ // ㅇ + ㅇ = ㆁ (Yesieung)
138+ if (a == 0x110B && b == 0x110B ) return CHOSEONG_YESIEUNG;
139+ // ㅅ + ㅅ = ㅿ (Bansiot)
140+ if (a == 0x1109 && b == 0x1109 ) return CHOSEONG_PANSIOT;
141+ // ㅎ + ㅎ = ㆆ (Yeorinhieuh)
142+ if (a == 0x1112 && b == 0x1112 ) return CHOSEONG_YEORINHIEUH;
143+
144+ // ㄱ + ㅅ = ㅺ (Sg)
145+ if (a == 0x1100 && b == 0x1109 ) return CHOSEONG_SG;
146+ // ㅂ + ㅅ = ㅼ (Bs)
147+ if (a == 0x1107 && b == 0x1109 ) return CHOSEONG_BS;
148+ // ㅂ + ㅈ = ㅽ (Bj)
149+ if (a == 0x1107 && b == 0x110C ) return CHOSEONG_BJ;
150+
151+ return 0 ;
152+ }
153+
154+
155+
89156- (unichar )currentSyllable {
90157 if (_cho == 0 && _jung == 0 && _jong == 0 ) return 0 ;
91158
@@ -135,6 +202,8 @@ - (unichar)compatibilityJamo:(unichar)u {
135202 };
136203 return map[u - 0x1161 ];
137204 }
205+
206+ if (u == 0x119E ) return 0x318D ; // Araea
138207 return u;
139208}
140209
@@ -145,6 +214,8 @@ - (int)choIndex:(unichar)c {
145214
146215- (int )jungIndex : (unichar )c {
147216 if (c >= 0x1161 && c <= 0x1175 ) return c - 0x1161 ;
217+ // Araea is not part of modern syllable block (U+AC00-U+D7A3),
218+ // but we support it as an independent jamo for now.
148219 return -1 ;
149220}
150221
@@ -210,8 +281,7 @@ - (BOOL)processCode:(NSInteger)keyCode modifiers:(NSUInteger)flags
210281
211282 if (hangul == 0 ) {
212283 if (_cho || _jung || _jong) {
213- [_completed appendFormat: @" %C " , [self currentSyllable ]];
214- _cho = 0 ; _jung = 0 ; _jong = 0 ;
284+ [self flush ];
215285 }
216286 return NO ;
217287 }
@@ -221,9 +291,15 @@ - (BOOL)processCode:(NSInteger)keyCode modifiers:(NSUInteger)flags
221291 // State: Cho only or Empty
222292 if (_cho == 0 ) { _cho = hangul; }
223293 else {
224- // Flush prev Cho, start new
225- [_completed appendFormat: @" %C " , [self compatibilityJamo: _cho]];
226- _cho = hangul;
294+ // Try Combine Cho (Old Hangul)
295+ unichar compound = [self combineCho: _cho second: hangul];
296+ if (compound) {
297+ _cho = compound;
298+ } else {
299+ // Flush prev Cho, start new
300+ [_completed appendFormat: @" %C " , [self compatibilityJamo: _cho]];
301+ _cho = hangul;
302+ }
227303 }
228304 } else {
229305 // Already have Jung.
@@ -235,7 +311,7 @@ - (BOOL)processCode:(NSInteger)keyCode modifiers:(NSUInteger)flags
235311 return YES ;
236312 } else {
237313 // Moa-jjiki Disabled: Flush Jung, start new Cho
238- [_completed appendFormat: @" %C " , [ self currentSyllable ] ];
314+ [self flush ];
239315 _cho = hangul; _jung = 0 ; _jong = 0 ;
240316 return YES ;
241317 }
@@ -246,8 +322,11 @@ - (BOOL)processCode:(NSInteger)keyCode modifiers:(NSUInteger)flags
246322 if (asJong) {
247323 _jong = asJong;
248324 } else {
249- // Start new syllable
250- [_completed appendFormat: @" %C " , [self currentSyllable ]];
325+ // Not a valid Jongseong. Maybe combined Cho (Old Hangul)?
326+ // But we already have Jung, so it's a new Syllable unless Old Hangul allows Cho+Jung+Cho?
327+ // No, Cho+Jung+Cho structure isn't standard. It must be Jongseong or new Syllable.
328+ // If it's not a valid Jongseong, it's a new syllable.
329+ [self flush ];
251330 _cho = hangul; _jung = 0 ; _jong = 0 ;
252331 }
253332 } else { // Cho+Jung+Jong
@@ -257,7 +336,7 @@ - (BOOL)processCode:(NSInteger)keyCode modifiers:(NSUInteger)flags
257336 _jong = compound;
258337 } else {
259338 // Flush, start new
260- [_completed appendFormat: @" %C " , [ self currentSyllable ] ];
339+ [self flush ];
261340 _cho = hangul; _jung = 0 ; _jong = 0 ;
262341 }
263342 }
@@ -271,12 +350,12 @@ - (BOOL)processCode:(NSInteger)keyCode modifiers:(NSUInteger)flags
271350 if (j2) {
272351 _jong = j1;
273352 unichar nextCho = [self jongToCho: j2];
274- [_completed appendFormat: @" %C " , [ self currentSyllable ] ];
353+ [self flush ];
275354 _cho = nextCho; _jung = hangul; _jong = 0 ;
276355 } else {
277356 unichar nextCho = [self jongToCho: _jong];
278357 _jong = 0 ;
279- [_completed appendFormat: @" %C " , [ self currentSyllable ] ];
358+ [self flush ];
280359 _cho = nextCho; _jung = hangul; _jong = 0 ;
281360 }
282361 } else if (_jung) {
@@ -386,6 +465,12 @@ - (unichar)combineJung:(unichar)a second:(unichar)b {
386465 if (a == 0x116e && b == 0x1166 ) return 0x1170 ; // ㅞ
387466 if (a == 0x116e && b == 0x1175 ) return 0x1171 ; // ㅟ
388467 if (a == 0x1173 && b == 0x1175 ) return 0x1174 ; // ㅢ
468+
469+ // Araea (Optional)
470+ if (self.oldHangulEnabled ) {
471+ if (a == 0x1161 && b == 0x1161 ) return 0x119E ; // ㅏ + ㅏ = ᆞ (Araea)
472+ }
473+
389474 return 0 ;
390475}
391476
@@ -399,6 +484,7 @@ - (void)splitJung:(unichar)c first:(unichar*)j1 second:(unichar*)j2 {
399484 case 0x1170 : *j1 = 0x116e ; *j2 = 0x1166 ; break ; // ㅞ
400485 case 0x1171 : *j1 = 0x116e ; *j2 = 0x1175 ; break ; // ㅟ
401486 case 0x1174 : *j1 = 0x1173 ; *j2 = 0x1175 ; break ; // ㅢ
487+ case 0x119E : *j1 = 0x1161 ; *j2 = 0x1161 ; break ; // ᆞ -> ㅏ + ㅏ
402488 }
403489}
404490
0 commit comments