forked from extern/Unexpected-Keyboard
Normalization of Korean characters
This changes how some characters are sent to the editor. Characters specified in 'should_normalize_char' are not committed immediately to the editor but instead added to the composing text. The composing text is NFCKC-normalized. Resulting characters that are not in 'should_normalize_char' committed, the rest is the composing text. Typing a character not specified here do not change: commitText is used immediately.
This commit is contained in:
parent
1cbaa7106c
commit
3cb92fce84
104
srcs/juloo.keyboard2/Autonormalization.java
Normal file
104
srcs/juloo.keyboard2/Autonormalization.java
Normal file
@ -0,0 +1,104 @@
|
||||
package juloo.keyboard2;
|
||||
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.icu.text.Normalizer2;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
|
||||
/** Compose the characters specified in [should_normalize_char()] using unicode
|
||||
normalization. The composing region is used to mark text where
|
||||
normalization could happen if more characters are typed. */
|
||||
public final class Autonormalization
|
||||
{
|
||||
/** Composing text waiting for more combinations. */
|
||||
StringBuilder _c = new StringBuilder();
|
||||
InputConnection _ic = null;
|
||||
Normalizer2 _normalizer_cached = null;
|
||||
|
||||
public Autonormalization() {}
|
||||
|
||||
public void started(EditorInfo info, InputConnection ic)
|
||||
{
|
||||
_ic = ic;
|
||||
_c.setLength(0);
|
||||
}
|
||||
|
||||
/** If the characters could combine with a following character, update the
|
||||
composing text and return [true]. If the typed chars can't combine, flush
|
||||
the composing text and return [false], without committing the text. */
|
||||
public boolean typed(CharSequence s)
|
||||
{
|
||||
if (_ic == null || s.length() == 0)
|
||||
return false;
|
||||
if (should_normalize_char(s.charAt(0)))
|
||||
{
|
||||
type_normalized(s);
|
||||
return true;
|
||||
}
|
||||
flush();
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Handle key events, might flush the composing text. Do not call [typed]. */
|
||||
public void key_up(KeyValue kv)
|
||||
{
|
||||
switch (kv.getKind())
|
||||
{
|
||||
// [typed] will be called later
|
||||
case Char:
|
||||
case String: break;
|
||||
// Do not change the composing text for these keys
|
||||
case Modifier:
|
||||
case Compose_pending: break;
|
||||
// The other keys flush the composing text
|
||||
case Event:
|
||||
case Keyevent:
|
||||
case Editing:
|
||||
flush();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** If [typed()] has been called before, [flush()] must be called before
|
||||
sending any other command to the [InputConnection]. */
|
||||
void flush()
|
||||
{
|
||||
if (_ic == null)
|
||||
return;
|
||||
_c.setLength(0);
|
||||
_ic.finishComposingText();
|
||||
}
|
||||
|
||||
Normalizer2 normalizer()
|
||||
{
|
||||
if (_normalizer_cached == null)
|
||||
_normalizer_cached = Normalizer2.getNFKCInstance();
|
||||
return _normalizer_cached;
|
||||
}
|
||||
|
||||
void type_normalized(CharSequence s)
|
||||
{
|
||||
Normalizer2 norm = normalizer();
|
||||
norm.normalizeSecondAndAppend(_c, s);
|
||||
/* Only keep the string of normalizable character at the end of [_c].
|
||||
Commit the rest. */
|
||||
int i = _c.length() - 1;
|
||||
while (i > 0 && should_normalize_char(_c.charAt(i)))
|
||||
i--;
|
||||
if (i > 0)
|
||||
{
|
||||
_ic.commitText(_c.subSequence(0, i), 1);
|
||||
_c.delete(0, i);
|
||||
}
|
||||
_ic.setComposingText(_c, 1);
|
||||
}
|
||||
|
||||
/** Characters for which autonormalization will happen. */
|
||||
boolean should_normalize_char(char c)
|
||||
{
|
||||
return (c >= '\u1100' && c <= '\u11FF') // Hangul Jamo
|
||||
|| (c >= '\u3130' && c <= '\u318F') // Hangul Compatibility Jamo
|
||||
|| (c >= '\uA960' && c <= '\uA97F') // Hangul Jamo Extended-A
|
||||
|| (c >= '\uD7B0' && c <= '\uD7FF') // Hangul Jamo Extended-B
|
||||
;
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ public final class KeyEventHandler implements Config.IKeyEventHandler
|
||||
{
|
||||
IReceiver _recv;
|
||||
Autocapitalisation _autocap;
|
||||
Autonormalization _autonorm;
|
||||
/** State of the system modifiers. It is updated whether a modifier is down
|
||||
or up and a corresponding key event is sent. */
|
||||
Pointers.Modifiers _mods;
|
||||
@ -30,13 +31,16 @@ public final class KeyEventHandler implements Config.IKeyEventHandler
|
||||
_recv = recv;
|
||||
_autocap = new Autocapitalisation(looper,
|
||||
this.new Autocapitalisation_callback());
|
||||
_autonorm = new Autonormalization();
|
||||
_mods = Pointers.Modifiers.EMPTY;
|
||||
}
|
||||
|
||||
/** Editing just started. */
|
||||
public void started(EditorInfo info)
|
||||
{
|
||||
_autocap.started(info, _recv.getCurrentInputConnection());
|
||||
InputConnection ic = _recv.getCurrentInputConnection();
|
||||
_autocap.started(info, ic);
|
||||
_autonorm.started(info, ic);
|
||||
// Workaround a bug in Acode, which answers to [getExtractedText] but do
|
||||
// not react to [setSelection] while returning [true].
|
||||
// Note: Using & to workaround a bug in Acode, which sets several
|
||||
@ -86,6 +90,8 @@ public final class KeyEventHandler implements Config.IKeyEventHandler
|
||||
return;
|
||||
Pointers.Modifiers old_mods = _mods;
|
||||
update_meta_state(mods);
|
||||
// Handles sending text
|
||||
_autonorm.key_up(key);
|
||||
switch (key.getKind())
|
||||
{
|
||||
case Char: send_text(String.valueOf(key.getChar())); break;
|
||||
@ -192,6 +198,7 @@ public final class KeyEventHandler implements Config.IKeyEventHandler
|
||||
InputConnection conn = _recv.getCurrentInputConnection();
|
||||
if (conn == null)
|
||||
return;
|
||||
if (!_autonorm.typed(text))
|
||||
conn.commitText(text, 1);
|
||||
_autocap.typed(text);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user