mirror of
https://github.com/Helium314/HeliBoard.git
synced 2025-05-02 21:04:28 +00:00
some formatting
This commit is contained in:
parent
eee94f2924
commit
a7a3465e9b
4 changed files with 168 additions and 168 deletions
|
@ -17,12 +17,29 @@ import java.util.*
|
||||||
* feedback on the composing state and will typically be shown with different styling such as
|
* feedback on the composing state and will typically be shown with different styling such as
|
||||||
* a colored background.
|
* a colored background.
|
||||||
*/
|
*/
|
||||||
class CombinerChain(initialText: String?) {
|
class CombinerChain(initialText: String) {
|
||||||
// The already combined text, as described above
|
// The already combined text, as described above
|
||||||
private val mCombinedText: StringBuilder
|
private val mCombinedText = StringBuilder(initialText)
|
||||||
// The feedback on the composing state, as described above
|
// The feedback on the composing state, as described above
|
||||||
private val mStateFeedback: SpannableStringBuilder
|
private val mStateFeedback = SpannableStringBuilder()
|
||||||
private val mCombiners: ArrayList<Combiner>
|
private val mCombiners = ArrayList<Combiner>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an combiner chain.
|
||||||
|
*
|
||||||
|
* The combiner chain takes events as inputs and outputs code points and combining state.
|
||||||
|
* For example, if the input language is Japanese, the combining chain will typically perform
|
||||||
|
* kana conversion. This takes a string for initial text, taken to be present before the
|
||||||
|
* cursor: we'll start after this.
|
||||||
|
*
|
||||||
|
* @param initialText The text that has already been combined so far.
|
||||||
|
*/
|
||||||
|
init {
|
||||||
|
// The dead key combiner is always active, and always first
|
||||||
|
mCombiners.add(DeadKeyCombiner())
|
||||||
|
mCombiners.add(HangulCombiner())
|
||||||
|
}
|
||||||
|
|
||||||
fun reset() {
|
fun reset() {
|
||||||
mCombinedText.setLength(0)
|
mCombinedText.setLength(0)
|
||||||
mStateFeedback.clear()
|
mStateFeedback.clear()
|
||||||
|
@ -45,15 +62,16 @@ class CombinerChain(initialText: String?) {
|
||||||
* @return the processed event. It may be the same event, or a consumed event, or a completely
|
* @return the processed event. It may be the same event, or a consumed event, or a completely
|
||||||
* new event. However it may never be null.
|
* new event. However it may never be null.
|
||||||
*/
|
*/
|
||||||
fun processEvent(previousEvents: ArrayList<Event>?,
|
fun processEvent(previousEvents: ArrayList<Event>?, newEvent: Event): Event {
|
||||||
newEvent: Event): Event {
|
|
||||||
val modifiablePreviousEvents = ArrayList(previousEvents!!)
|
val modifiablePreviousEvents = ArrayList(previousEvents!!)
|
||||||
var event = newEvent
|
var event = newEvent
|
||||||
for (combiner in mCombiners) { // A combiner can never return more than one event; it can return several
|
for (combiner in mCombiners) {
|
||||||
// code points, but they should be encapsulated within one event.
|
// A combiner can never return more than one event; it can return several
|
||||||
|
// code points, but they should be encapsulated within one event.
|
||||||
event = combiner.processEvent(modifiablePreviousEvents, event)
|
event = combiner.processEvent(modifiablePreviousEvents, event)
|
||||||
if (event.isConsumed) { // If the event is consumed, then we don't pass it to subsequent combiners:
|
if (event.isConsumed) {
|
||||||
// they should not see it at all.
|
// If the event is consumed, then we don't pass it to subsequent combiners:
|
||||||
|
// they should not see it at all.
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,22 +111,4 @@ class CombinerChain(initialText: String?) {
|
||||||
return s.append(mStateFeedback)
|
return s.append(mStateFeedback)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an combiner chain.
|
|
||||||
*
|
|
||||||
* The combiner chain takes events as inputs and outputs code points and combining state.
|
|
||||||
* For example, if the input language is Japanese, the combining chain will typically perform
|
|
||||||
* kana conversion. This takes a string for initial text, taken to be present before the
|
|
||||||
* cursor: we'll start after this.
|
|
||||||
*
|
|
||||||
* @param initialText The text that has already been combined so far.
|
|
||||||
*/
|
|
||||||
init {
|
|
||||||
mCombiners = ArrayList()
|
|
||||||
// The dead key combiner is always active, and always first
|
|
||||||
mCombiners.add(DeadKeyCombiner())
|
|
||||||
mCombiners.add(HangulCombiner())
|
|
||||||
mCombinedText = StringBuilder(initialText!!)
|
|
||||||
mStateFeedback = SpannableStringBuilder()
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -17,62 +17,59 @@ import org.dslul.openboard.inputmethod.latin.common.StringUtils
|
||||||
* for example.
|
* for example.
|
||||||
* The combiner should figure out what to do with this.
|
* The combiner should figure out what to do with this.
|
||||||
*/
|
*/
|
||||||
class Event private constructor(// The type of event - one of the constants above
|
class Event private constructor(
|
||||||
private val mEventType: Int, // If applicable, this contains the string that should be input.
|
// The type of event - one of the constants above
|
||||||
val mText: CharSequence?, // The code point associated with the event, if relevant. This is a unicode code point, and
|
private val mEventType: Int,
|
||||||
// has nothing to do with other representations of the key. It is only relevant if this event
|
// If applicable, this contains the string that should be input.
|
||||||
// is of KEYPRESS type, but for a mode key like hankaku/zenkaku or ctrl, there is no code point
|
val mText: CharSequence?,
|
||||||
// associated so this should be NOT_A_CODE_POINT to avoid unintentional use of its value when
|
// The code point associated with the event, if relevant. This is a unicode code point, and
|
||||||
// it's not relevant.
|
// has nothing to do with other representations of the key. It is only relevant if this event
|
||||||
val mCodePoint: Int, // The key code associated with the event, if relevant. This is relevant whenever this event
|
// is of KEYPRESS type, but for a mode key like hankaku/zenkaku or ctrl, there is no code point
|
||||||
// has been triggered by a key press, but not for a gesture for example. This has conceptually
|
// associated so this should be NOT_A_CODE_POINT to avoid unintentional use of its value when
|
||||||
// no link to the code point, although keys that enter a straight code point may often set
|
// it's not relevant.
|
||||||
// this to be equal to mCodePoint for convenience. If this is not a key, this must contain
|
val mCodePoint: Int,
|
||||||
// NOT_A_KEY_CODE.
|
// The key code associated with the event, if relevant. This is relevant whenever this event
|
||||||
|
// has been triggered by a key press, but not for a gesture for example. This has conceptually
|
||||||
|
// no link to the code point, although keys that enter a straight code point may often set
|
||||||
|
// this to be equal to mCodePoint for convenience. If this is not a key, this must contain
|
||||||
|
// NOT_A_KEY_CODE.
|
||||||
val mKeyCode: Int,
|
val mKeyCode: Int,
|
||||||
// Coordinates of the touch event, if relevant. If useful, we may want to replace this with
|
// Coordinates of the touch event, if relevant. If useful, we may want to replace this with
|
||||||
// a MotionEvent or something in the future. This is only relevant when the keypress is from
|
// a MotionEvent or something in the future. This is only relevant when the keypress is from
|
||||||
// a software keyboard obviously, unless there are touch-sensitive hardware keyboards in the
|
// a software keyboard obviously, unless there are touch-sensitive hardware keyboards in the
|
||||||
// future or some other awesome sauce.
|
// future or some other awesome sauce.
|
||||||
val mX: Int, val mY: Int,
|
val mX: Int, val mY: Int,
|
||||||
// If this is of type EVENT_TYPE_SUGGESTION_PICKED, this must not be null (and must be null in
|
// If this is of type EVENT_TYPE_SUGGESTION_PICKED, this must not be null (and must be null in
|
||||||
// other cases).
|
// other cases).
|
||||||
val mSuggestedWordInfo: SuggestedWordInfo?,
|
val mSuggestedWordInfo: SuggestedWordInfo?,
|
||||||
// Some flags that can't go into the key code. It's a bit field of FLAG_*
|
// Some flags that can't go into the key code. It's a bit field of FLAG_*
|
||||||
private val mFlags: Int,
|
private val mFlags: Int,
|
||||||
// The next event, if any. Null if there is no next event yet.
|
// The next event, if any. Null if there is no next event yet.
|
||||||
val mNextEvent: Event?// This logic may need to be refined in the future
|
val mNextEvent: Event?
|
||||||
|
// This logic may need to be refined in the future
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// Returns whether this is a function key like backspace, ctrl, settings... as opposed to keys
|
// Returns whether this is a function key like backspace, ctrl, settings... as opposed to keys
|
||||||
// that result in input like letters or space.
|
// that result in input like letters or space.
|
||||||
val isFunctionalKeyEvent: Boolean
|
val isFunctionalKeyEvent: Boolean
|
||||||
get() =// This logic may need to be refined in the future
|
get() = NOT_A_CODE_POINT == mCodePoint // This logic may need to be refined in the future
|
||||||
NOT_A_CODE_POINT == mCodePoint
|
|
||||||
|
|
||||||
// Returns whether this event is for a dead character. @see {@link #FLAG_DEAD}
|
// Returns whether this event is for a dead character. @see {@link #FLAG_DEAD}
|
||||||
val isDead: Boolean
|
val isDead: Boolean get() = 0 != FLAG_DEAD and mFlags
|
||||||
get() = 0 != FLAG_DEAD and mFlags
|
|
||||||
|
|
||||||
val isKeyRepeat: Boolean
|
val isKeyRepeat: Boolean get() = 0 != FLAG_REPEAT and mFlags
|
||||||
get() = 0 != FLAG_REPEAT and mFlags
|
|
||||||
|
|
||||||
val isConsumed: Boolean
|
val isConsumed: Boolean get() = 0 != FLAG_CONSUMED and mFlags
|
||||||
get() = 0 != FLAG_CONSUMED and mFlags
|
|
||||||
|
|
||||||
val isCombining: Boolean
|
val isCombining: Boolean get() = 0 != FLAG_COMBINING and mFlags
|
||||||
get() = 0 != FLAG_COMBINING and mFlags
|
|
||||||
|
|
||||||
val isGesture: Boolean
|
val isGesture: Boolean get() = EVENT_TYPE_GESTURE == mEventType
|
||||||
get() = EVENT_TYPE_GESTURE == mEventType
|
|
||||||
|
|
||||||
// Returns whether this is a fake key press from the suggestion strip. This happens with
|
// Returns whether this is a fake key press from the suggestion strip. This happens with
|
||||||
// punctuation signs selected from the suggestion strip.
|
// punctuation signs selected from the suggestion strip.
|
||||||
val isSuggestionStripPress: Boolean
|
val isSuggestionStripPress: Boolean get() = EVENT_TYPE_SUGGESTION_PICKED == mEventType
|
||||||
get() = EVENT_TYPE_SUGGESTION_PICKED == mEventType
|
|
||||||
|
|
||||||
val isHandled: Boolean
|
val isHandled: Boolean get() = EVENT_TYPE_NOT_HANDLED != mEventType
|
||||||
get() = EVENT_TYPE_NOT_HANDLED != mEventType
|
|
||||||
|
|
||||||
// A consumed event should input no text.
|
// A consumed event should input no text.
|
||||||
val textToCommit: CharSequence?
|
val textToCommit: CharSequence?
|
||||||
|
@ -90,20 +87,20 @@ class Event private constructor(// The type of event - one of the constants abov
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// Should the types below be represented by separate classes instead? It would be cleaner
|
// Should the types below be represented by separate classes instead? It would be cleaner
|
||||||
// but probably a bit too much
|
// but probably a bit too much
|
||||||
// An event we don't handle in Latin IME, for example pressing Ctrl on a hardware keyboard.
|
// An event we don't handle in Latin IME, for example pressing Ctrl on a hardware keyboard.
|
||||||
const val EVENT_TYPE_NOT_HANDLED = 0
|
const val EVENT_TYPE_NOT_HANDLED = 0
|
||||||
// A key press that is part of input, for example pressing an alphabetic character on a
|
// A key press that is part of input, for example pressing an alphabetic character on a
|
||||||
// hardware qwerty keyboard. It may be part of a sequence that will be re-interpreted later
|
// hardware qwerty keyboard. It may be part of a sequence that will be re-interpreted later
|
||||||
// through combination.
|
// through combination.
|
||||||
const val EVENT_TYPE_INPUT_KEYPRESS = 1
|
const val EVENT_TYPE_INPUT_KEYPRESS = 1
|
||||||
// A toggle event is triggered by a key that affects the previous character. An example would
|
// A toggle event is triggered by a key that affects the previous character. An example would
|
||||||
// be a numeric key on a 10-key keyboard, which would toggle between 1 - a - b - c with
|
// be a numeric key on a 10-key keyboard, which would toggle between 1 - a - b - c with
|
||||||
// repeated presses.
|
// repeated presses.
|
||||||
const val EVENT_TYPE_TOGGLE = 2
|
const val EVENT_TYPE_TOGGLE = 2
|
||||||
// A mode event instructs the combiner to change modes. The canonical example would be the
|
// A mode event instructs the combiner to change modes. The canonical example would be the
|
||||||
// hankaku/zenkaku key on a Japanese keyboard, or even the caps lock key on a qwerty keyboard
|
// hankaku/zenkaku key on a Japanese keyboard, or even the caps lock key on a qwerty keyboard
|
||||||
// if handled at the combiner level.
|
// if handled at the combiner level.
|
||||||
const val EVENT_TYPE_MODE_KEY = 3
|
const val EVENT_TYPE_MODE_KEY = 3
|
||||||
// An event corresponding to a gesture.
|
// An event corresponding to a gesture.
|
||||||
const val EVENT_TYPE_GESTURE = 4
|
const val EVENT_TYPE_GESTURE = 4
|
||||||
|
@ -119,7 +116,7 @@ class Event private constructor(// The type of event - one of the constants abov
|
||||||
const val NOT_A_KEY_CODE = 0
|
const val NOT_A_KEY_CODE = 0
|
||||||
private const val FLAG_NONE = 0
|
private const val FLAG_NONE = 0
|
||||||
// This event is a dead character, usually input by a dead key. Examples include dead-acute
|
// This event is a dead character, usually input by a dead key. Examples include dead-acute
|
||||||
// or dead-abovering.
|
// or dead-abovering.
|
||||||
private const val FLAG_DEAD = 0x1
|
private const val FLAG_DEAD = 0x1
|
||||||
// This event is coming from a key repeat, software or hardware.
|
// This event is coming from a key repeat, software or hardware.
|
||||||
private const val FLAG_REPEAT = 0x2
|
private const val FLAG_REPEAT = 0x2
|
||||||
|
@ -197,22 +194,20 @@ class Event private constructor(// The type of event - one of the constants abov
|
||||||
* or combination that outputs a string.
|
* or combination that outputs a string.
|
||||||
* @param text the CharSequence associated with this event.
|
* @param text the CharSequence associated with this event.
|
||||||
* @param keyCode the key code, or NOT_A_KEYCODE if not applicable.
|
* @param keyCode the key code, or NOT_A_KEYCODE if not applicable.
|
||||||
|
* @param next the next event, or null if not applicable.
|
||||||
* @return an event for this text.
|
* @return an event for this text.
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun createSoftwareTextEvent(text: CharSequence?, keyCode: Int): Event {
|
fun createSoftwareTextEvent(text: CharSequence?, keyCode: Int, next: Event?): Event {
|
||||||
return Event(EVENT_TYPE_SOFTWARE_GENERATED_STRING, text, NOT_A_CODE_POINT, keyCode,
|
|
||||||
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE,
|
|
||||||
null /* suggestedWordInfo */, FLAG_NONE, null /* next */)
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun createSoftwareTextEvent(text: CharSequence?, keyCode: Int, next: Event): Event {
|
|
||||||
return Event(EVENT_TYPE_SOFTWARE_GENERATED_STRING, text, NOT_A_CODE_POINT, keyCode,
|
return Event(EVENT_TYPE_SOFTWARE_GENERATED_STRING, text, NOT_A_CODE_POINT, keyCode,
|
||||||
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE,
|
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE,
|
||||||
null /* suggestedWordInfo */, FLAG_NONE, next)
|
null /* suggestedWordInfo */, FLAG_NONE, next)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun createSoftwareTextEvent(text: CharSequence?, keyCode: Int) =
|
||||||
|
createSoftwareTextEvent(text, keyCode, null)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an input event representing the manual pick of a punctuation suggestion.
|
* Creates an input event representing the manual pick of a punctuation suggestion.
|
||||||
* @return an event for this suggestion pick.
|
* @return an event for this suggestion pick.
|
||||||
|
@ -220,7 +215,7 @@ class Event private constructor(// The type of event - one of the constants abov
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun createPunctuationSuggestionPickedEvent(
|
fun createPunctuationSuggestionPickedEvent(
|
||||||
suggestedWordInfo: SuggestedWordInfo): Event {
|
suggestedWordInfo: SuggestedWordInfo): Event {
|
||||||
val primaryCode = suggestedWordInfo.mWord[0].toInt()
|
val primaryCode = suggestedWordInfo.mWord[0].code
|
||||||
return Event(EVENT_TYPE_SUGGESTION_PICKED, suggestedWordInfo.mWord, primaryCode,
|
return Event(EVENT_TYPE_SUGGESTION_PICKED, suggestedWordInfo.mWord, primaryCode,
|
||||||
NOT_A_KEY_CODE, Constants.SUGGESTION_STRIP_COORDINATE,
|
NOT_A_KEY_CODE, Constants.SUGGESTION_STRIP_COORDINATE,
|
||||||
Constants.SUGGESTION_STRIP_COORDINATE, suggestedWordInfo, FLAG_NONE,
|
Constants.SUGGESTION_STRIP_COORDINATE, suggestedWordInfo, FLAG_NONE,
|
||||||
|
@ -244,8 +239,8 @@ class Event private constructor(// The type of event - one of the constants abov
|
||||||
* @param source the event to copy the properties of.
|
* @param source the event to copy the properties of.
|
||||||
* @return an identical event marked as consumed.
|
* @return an identical event marked as consumed.
|
||||||
*/
|
*/
|
||||||
fun createConsumedEvent(source: Event?): Event { // A consumed event should not input any text at all, so we pass the empty string as text.
|
fun createConsumedEvent(source: Event): Event { // A consumed event should not input any text at all, so we pass the empty string as text.
|
||||||
return Event(source!!.mEventType, source.mText, source.mCodePoint, source.mKeyCode,
|
return Event(source.mEventType, source.mText, source.mCodePoint, source.mKeyCode,
|
||||||
source.mX, source.mY, source.mSuggestedWordInfo, source.mFlags or FLAG_CONSUMED,
|
source.mX, source.mY, source.mSuggestedWordInfo, source.mFlags or FLAG_CONSUMED,
|
||||||
source.mNextEvent)
|
source.mNextEvent)
|
||||||
}
|
}
|
||||||
|
@ -266,7 +261,7 @@ class Event private constructor(// The type of event - one of the constants abov
|
||||||
// This method is private - to create a new event, use one of the create* utility methods.
|
// This method is private - to create a new event, use one of the create* utility methods.
|
||||||
init {
|
init {
|
||||||
// Sanity checks
|
// Sanity checks
|
||||||
// mSuggestedWordInfo is non-null if and only if the type is SUGGESTION_PICKED
|
// mSuggestedWordInfo is non-null if and only if the type is SUGGESTION_PICKED
|
||||||
if (EVENT_TYPE_SUGGESTION_PICKED == mEventType) {
|
if (EVENT_TYPE_SUGGESTION_PICKED == mEventType) {
|
||||||
if (null == mSuggestedWordInfo) {
|
if (null == mSuggestedWordInfo) {
|
||||||
throw RuntimeException("Wrong event: SUGGESTION_PICKED event must have a "
|
throw RuntimeException("Wrong event: SUGGESTION_PICKED event must have a "
|
||||||
|
|
|
@ -6,22 +6,21 @@ import java.util.ArrayList
|
||||||
|
|
||||||
class HangulCombiner : Combiner {
|
class HangulCombiner : Combiner {
|
||||||
|
|
||||||
val composingWord = StringBuilder()
|
private val composingWord = StringBuilder()
|
||||||
|
|
||||||
val history: MutableList<HangulSyllable> = mutableListOf()
|
val history: MutableList<HangulSyllable> = mutableListOf()
|
||||||
val syllable: HangulSyllable? get() = history.lastOrNull()
|
private val syllable: HangulSyllable? get() = history.lastOrNull()
|
||||||
|
|
||||||
override fun processEvent(previousEvents: ArrayList<Event>?, event: Event): Event {
|
override fun processEvent(previousEvents: ArrayList<Event>?, event: Event): Event {
|
||||||
if(event.mKeyCode == Constants.CODE_SHIFT) return event
|
if (event.mKeyCode == Constants.CODE_SHIFT) return event
|
||||||
if(Character.isWhitespace(event.mCodePoint)) {
|
if (Character.isWhitespace(event.mCodePoint)) {
|
||||||
val text = combiningStateFeedback
|
val text = combiningStateFeedback
|
||||||
reset()
|
reset()
|
||||||
return createEventChainFromSequence(text, event)
|
return createEventChainFromSequence(text, event)
|
||||||
} else if(event.isFunctionalKeyEvent) {
|
} else if (event.isFunctionalKeyEvent) {
|
||||||
if(event.mKeyCode == Constants.CODE_DELETE) {
|
if(event.mKeyCode == Constants.CODE_DELETE) {
|
||||||
return when {
|
return when {
|
||||||
history.size == 1 && composingWord.isEmpty() ||
|
history.size == 1 && composingWord.isEmpty() || history.isEmpty() && composingWord.length == 1 -> {
|
||||||
history.isEmpty() && composingWord.length == 1 -> {
|
|
||||||
reset()
|
reset()
|
||||||
Event.createHardwareKeypressEvent(0x20, Constants.CODE_SPACE, event, event.isKeyRepeat)
|
Event.createHardwareKeypressEvent(0x20, Constants.CODE_SPACE, event, event.isKeyRepeat)
|
||||||
}
|
}
|
||||||
|
@ -42,37 +41,39 @@ class HangulCombiner : Combiner {
|
||||||
} else {
|
} else {
|
||||||
val currentSyllable = syllable ?: HangulSyllable()
|
val currentSyllable = syllable ?: HangulSyllable()
|
||||||
val jamo = HangulJamo.of(event.mCodePoint)
|
val jamo = HangulJamo.of(event.mCodePoint)
|
||||||
if(!event.isCombining || jamo is HangulJamo.NonHangul) {
|
if (!event.isCombining || jamo is HangulJamo.NonHangul) {
|
||||||
composingWord.append(currentSyllable.string)
|
composingWord.append(currentSyllable.string)
|
||||||
composingWord.append(jamo.string)
|
composingWord.append(jamo.string)
|
||||||
history.clear()
|
history.clear()
|
||||||
} else {
|
} else {
|
||||||
when(jamo) {
|
when (jamo) {
|
||||||
is HangulJamo.Consonant -> {
|
is HangulJamo.Consonant -> {
|
||||||
val initial = jamo.toInitial()
|
val initial = jamo.toInitial()
|
||||||
val final = jamo.toFinal()
|
val final = jamo.toFinal()
|
||||||
if(currentSyllable.initial != null && currentSyllable.medial != null) {
|
if (currentSyllable.initial != null && currentSyllable.medial != null) {
|
||||||
if(currentSyllable.final == null) {
|
if (currentSyllable.final == null) {
|
||||||
val combination = COMBINATION_TABLE_DUBEOLSIK[currentSyllable.initial.codePoint to (initial?.codePoint ?: -1)]
|
val combination = COMBINATION_TABLE_DUBEOLSIK[currentSyllable.initial.codePoint to (initial?.codePoint ?: -1)]
|
||||||
if(combination != null) {
|
history +=
|
||||||
history += currentSyllable.copy(initial = HangulJamo.Initial(combination))
|
if (combination != null) {
|
||||||
|
currentSyllable.copy(initial = HangulJamo.Initial(combination))
|
||||||
|
} else {
|
||||||
|
if (final != null) {
|
||||||
|
currentSyllable.copy(final = final)
|
||||||
} else {
|
} else {
|
||||||
if(final != null) history += currentSyllable.copy(final = final)
|
|
||||||
else {
|
|
||||||
composingWord.append(currentSyllable.string)
|
composingWord.append(currentSyllable.string)
|
||||||
history.clear()
|
history.clear()
|
||||||
history += HangulSyllable(initial = initial)
|
HangulSyllable(initial = initial)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val pair = currentSyllable.final.codePoint to (final?.codePoint ?: -1)
|
val pair = currentSyllable.final.codePoint to (final?.codePoint ?: -1)
|
||||||
val combination = COMBINATION_TABLE_DUBEOLSIK[pair]
|
val combination = COMBINATION_TABLE_DUBEOLSIK[pair]
|
||||||
if(combination != null) {
|
history += if (combination != null) {
|
||||||
history += currentSyllable.copy(final = HangulJamo.Final(combination, combinationPair = pair))
|
currentSyllable.copy(final = HangulJamo.Final(combination, combinationPair = pair))
|
||||||
} else {
|
} else {
|
||||||
composingWord.append(currentSyllable.string)
|
composingWord.append(currentSyllable.string)
|
||||||
history.clear()
|
history.clear()
|
||||||
history += HangulSyllable(initial = initial)
|
HangulSyllable(initial = initial)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -83,20 +84,21 @@ class HangulCombiner : Combiner {
|
||||||
}
|
}
|
||||||
is HangulJamo.Vowel -> {
|
is HangulJamo.Vowel -> {
|
||||||
val medial = jamo.toMedial()
|
val medial = jamo.toMedial()
|
||||||
if(currentSyllable.final == null) {
|
if (currentSyllable.final == null) {
|
||||||
if(currentSyllable.medial != null) {
|
history +=
|
||||||
|
if (currentSyllable.medial != null) {
|
||||||
val combination = COMBINATION_TABLE_DUBEOLSIK[currentSyllable.medial.codePoint to (medial?.codePoint ?: -1)]
|
val combination = COMBINATION_TABLE_DUBEOLSIK[currentSyllable.medial.codePoint to (medial?.codePoint ?: -1)]
|
||||||
if(combination != null) {
|
if (combination != null) {
|
||||||
history += currentSyllable.copy(medial = HangulJamo.Medial(combination))
|
currentSyllable.copy(medial = HangulJamo.Medial(combination))
|
||||||
} else {
|
} else {
|
||||||
composingWord.append(currentSyllable.string)
|
composingWord.append(currentSyllable.string)
|
||||||
history.clear()
|
history.clear()
|
||||||
history += HangulSyllable(medial = medial)
|
HangulSyllable(medial = medial)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
history += currentSyllable.copy(medial = medial)
|
currentSyllable.copy(medial = medial)
|
||||||
}
|
}
|
||||||
} else if(currentSyllable.final.combinationPair != null) {
|
} else if (currentSyllable.final.combinationPair != null) {
|
||||||
val pair = currentSyllable.final.combinationPair
|
val pair = currentSyllable.final.combinationPair
|
||||||
|
|
||||||
history.removeAt(history.lastIndex)
|
history.removeAt(history.lastIndex)
|
||||||
|
@ -119,45 +121,48 @@ class HangulCombiner : Combiner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is HangulJamo.Initial -> {
|
is HangulJamo.Initial -> {
|
||||||
if(currentSyllable.initial != null) {
|
history +=
|
||||||
|
if (currentSyllable.initial != null) {
|
||||||
val combination = COMBINATION_TABLE_SEBEOLSIK[currentSyllable.initial.codePoint to jamo.codePoint]
|
val combination = COMBINATION_TABLE_SEBEOLSIK[currentSyllable.initial.codePoint to jamo.codePoint]
|
||||||
if(combination != null && currentSyllable.medial == null && currentSyllable.final == null) {
|
if (combination != null && currentSyllable.medial == null && currentSyllable.final == null) {
|
||||||
history += currentSyllable.copy(initial = HangulJamo.Initial(combination))
|
currentSyllable.copy(initial = HangulJamo.Initial(combination))
|
||||||
} else {
|
} else {
|
||||||
composingWord.append(currentSyllable.string)
|
composingWord.append(currentSyllable.string)
|
||||||
history.clear()
|
history.clear()
|
||||||
history += HangulSyllable(initial = jamo)
|
HangulSyllable(initial = jamo)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
history += currentSyllable.copy(initial = jamo)
|
currentSyllable.copy(initial = jamo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is HangulJamo.Medial -> {
|
is HangulJamo.Medial -> {
|
||||||
if(currentSyllable.medial != null) {
|
history +=
|
||||||
|
if (currentSyllable.medial != null) {
|
||||||
val combination = COMBINATION_TABLE_SEBEOLSIK[currentSyllable.medial.codePoint to jamo.codePoint]
|
val combination = COMBINATION_TABLE_SEBEOLSIK[currentSyllable.medial.codePoint to jamo.codePoint]
|
||||||
if(combination != null) {
|
if (combination != null) {
|
||||||
history += currentSyllable.copy(medial = HangulJamo.Medial(combination))
|
currentSyllable.copy(medial = HangulJamo.Medial(combination))
|
||||||
} else {
|
} else {
|
||||||
composingWord.append(currentSyllable.string)
|
composingWord.append(currentSyllable.string)
|
||||||
history.clear()
|
history.clear()
|
||||||
history += HangulSyllable(medial = jamo)
|
HangulSyllable(medial = jamo)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
history += currentSyllable.copy(medial = jamo)
|
currentSyllable.copy(medial = jamo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is HangulJamo.Final -> {
|
is HangulJamo.Final -> {
|
||||||
if(currentSyllable.final != null) {
|
history +=
|
||||||
|
if (currentSyllable.final != null) {
|
||||||
val combination = COMBINATION_TABLE_SEBEOLSIK[currentSyllable.final.codePoint to jamo.codePoint]
|
val combination = COMBINATION_TABLE_SEBEOLSIK[currentSyllable.final.codePoint to jamo.codePoint]
|
||||||
if(combination != null) {
|
if (combination != null) {
|
||||||
history += currentSyllable.copy(final = HangulJamo.Final(combination))
|
currentSyllable.copy(final = HangulJamo.Final(combination))
|
||||||
} else {
|
} else {
|
||||||
composingWord.append(currentSyllable.string)
|
composingWord.append(currentSyllable.string)
|
||||||
history.clear()
|
history.clear()
|
||||||
history += HangulSyllable(final = jamo)
|
HangulSyllable(final = jamo)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
history += currentSyllable.copy(final = jamo)
|
currentSyllable.copy(final = jamo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// compiler bug? when it's not added, compiler complains that it's missing
|
// compiler bug? when it's not added, compiler complains that it's missing
|
||||||
|
@ -190,8 +195,8 @@ class HangulCombiner : Combiner {
|
||||||
val ordinal: Int get() = codePoint - 0x1100
|
val ordinal: Int get() = codePoint - 0x1100
|
||||||
fun toConsonant(): Consonant? {
|
fun toConsonant(): Consonant? {
|
||||||
val codePoint = COMPAT_CONSONANTS.getOrNull(CONVERT_INITIALS.indexOf(codePoint.toChar())) ?: return null
|
val codePoint = COMPAT_CONSONANTS.getOrNull(CONVERT_INITIALS.indexOf(codePoint.toChar())) ?: return null
|
||||||
if(codePoint.toInt() == 0) return null
|
if(codePoint.code == 0) return null
|
||||||
return Consonant(codePoint.toInt())
|
return Consonant(codePoint.code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data class Medial(override val codePoint: Int) : HangulJamo() {
|
data class Medial(override val codePoint: Int) : HangulJamo() {
|
||||||
|
@ -199,7 +204,7 @@ class HangulCombiner : Combiner {
|
||||||
val ordinal: Int get() = codePoint - 0x1161
|
val ordinal: Int get() = codePoint - 0x1161
|
||||||
fun toVowel(): Vowel? {
|
fun toVowel(): Vowel? {
|
||||||
val codePoint = COMPAT_VOWELS.getOrNull(CONVERT_MEDIALS.indexOf(codePoint.toChar())) ?: return null
|
val codePoint = COMPAT_VOWELS.getOrNull(CONVERT_MEDIALS.indexOf(codePoint.toChar())) ?: return null
|
||||||
return Vowel(codePoint.toInt())
|
return Vowel(codePoint.code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data class Final(override val codePoint: Int, val combinationPair: Pair<Int, Int>? = null) : HangulJamo() {
|
data class Final(override val codePoint: Int, val combinationPair: Pair<Int, Int>? = null) : HangulJamo() {
|
||||||
|
@ -207,8 +212,8 @@ class HangulCombiner : Combiner {
|
||||||
val ordinal: Int get() = codePoint - 0x11a7
|
val ordinal: Int get() = codePoint - 0x11a7
|
||||||
fun toConsonant(): Consonant? {
|
fun toConsonant(): Consonant? {
|
||||||
val codePoint = COMPAT_CONSONANTS.getOrNull(CONVERT_FINALS.indexOf(codePoint.toChar())) ?: return null
|
val codePoint = COMPAT_CONSONANTS.getOrNull(CONVERT_FINALS.indexOf(codePoint.toChar())) ?: return null
|
||||||
if(codePoint.toInt() == 0) return null
|
if(codePoint.code == 0) return null
|
||||||
return Consonant(codePoint.toInt())
|
return Consonant(codePoint.code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data class Consonant(override val codePoint: Int) : HangulJamo() {
|
data class Consonant(override val codePoint: Int) : HangulJamo() {
|
||||||
|
@ -216,13 +221,13 @@ class HangulCombiner : Combiner {
|
||||||
val ordinal: Int get() = codePoint - 0x3131
|
val ordinal: Int get() = codePoint - 0x3131
|
||||||
fun toInitial(): Initial? {
|
fun toInitial(): Initial? {
|
||||||
val codePoint = CONVERT_INITIALS.getOrNull(COMPAT_CONSONANTS.indexOf(codePoint.toChar())) ?: return null
|
val codePoint = CONVERT_INITIALS.getOrNull(COMPAT_CONSONANTS.indexOf(codePoint.toChar())) ?: return null
|
||||||
if(codePoint.toInt() == 0) return null
|
if(codePoint.code == 0) return null
|
||||||
return Initial(codePoint.toInt())
|
return Initial(codePoint.code)
|
||||||
}
|
}
|
||||||
fun toFinal(): Final? {
|
fun toFinal(): Final? {
|
||||||
val codePoint = CONVERT_FINALS.getOrNull(COMPAT_CONSONANTS.indexOf(codePoint.toChar())) ?: return null
|
val codePoint = CONVERT_FINALS.getOrNull(COMPAT_CONSONANTS.indexOf(codePoint.toChar())) ?: return null
|
||||||
if(codePoint.toInt() == 0) return null
|
if(codePoint.code == 0) return null
|
||||||
return Final(codePoint.toInt())
|
return Final(codePoint.code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data class Vowel(override val codePoint: Int) : HangulJamo() {
|
data class Vowel(override val codePoint: Int) : HangulJamo() {
|
||||||
|
@ -230,8 +235,8 @@ class HangulCombiner : Combiner {
|
||||||
val ordinal: Int get() = codePoint - 0x314f1
|
val ordinal: Int get() = codePoint - 0x314f1
|
||||||
fun toMedial(): Medial? {
|
fun toMedial(): Medial? {
|
||||||
val codePoint = CONVERT_MEDIALS.getOrNull(COMPAT_VOWELS.indexOf(codePoint.toChar())) ?: return null
|
val codePoint = CONVERT_MEDIALS.getOrNull(COMPAT_VOWELS.indexOf(codePoint.toChar())) ?: return null
|
||||||
if(codePoint.toInt() == 0) return null
|
if(codePoint.code == 0) return null
|
||||||
return Medial(codePoint.toInt())
|
return Medial(codePoint.code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -265,7 +270,7 @@ class HangulCombiner : Combiner {
|
||||||
val uncombined: String get() = (initial?.string ?: "") + (medial?.string ?: "") + (final?.string ?: "")
|
val uncombined: String get() = (initial?.string ?: "") + (medial?.string ?: "") + (final?.string ?: "")
|
||||||
val uncombinedCompat: String get() = (initial?.toConsonant()?.string ?: "") +
|
val uncombinedCompat: String get() = (initial?.toConsonant()?.string ?: "") +
|
||||||
(medial?.toVowel()?.string ?: "") + (final?.toConsonant()?.string ?: "")
|
(medial?.toVowel()?.string ?: "") + (final?.toConsonant()?.string ?: "")
|
||||||
val string: String get() = if(this.combinable) this.combined else this.uncombinedCompat
|
val string: String get() = if (this.combinable) this.combined else this.uncombinedCompat
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -320,7 +325,7 @@ class HangulCombiner : Combiner {
|
||||||
0x11ba to 0x11ba to 0x11bb // ㅆ
|
0x11ba to 0x11ba to 0x11bb // ㅆ
|
||||||
)
|
)
|
||||||
private fun createEventChainFromSequence(text: CharSequence, originalEvent: Event): Event {
|
private fun createEventChainFromSequence(text: CharSequence, originalEvent: Event): Event {
|
||||||
return Event.createSoftwareTextEvent(text, Constants.CODE_OUTPUT_TEXT, originalEvent);
|
return Event.createSoftwareTextEvent(text, Constants.CODE_OUTPUT_TEXT, originalEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ object HangulEventDecoder {
|
||||||
else Event.createCombiningEvent(event)
|
else Event.createCombiningEvent(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
val LAYOUT_DUBEOLSIK_STANDARD = mapOf<Int, Pair<Int, Int>>(
|
private val LAYOUT_DUBEOLSIK_STANDARD = mapOf<Int, Pair<Int, Int>>(
|
||||||
45 to (0x3142 to 0x3143),
|
45 to (0x3142 to 0x3143),
|
||||||
51 to (0x3148 to 0x3149),
|
51 to (0x3148 to 0x3149),
|
||||||
33 to (0x3137 to 0x3138),
|
33 to (0x3137 to 0x3138),
|
||||||
|
@ -53,7 +53,7 @@ object HangulEventDecoder {
|
||||||
41 to (0x3161 to 0x3161)
|
41 to (0x3161 to 0x3161)
|
||||||
)
|
)
|
||||||
|
|
||||||
val LAYOUT_SEBEOLSIK_390 = mapOf<Int, Pair<Int, Int>>(
|
private val LAYOUT_SEBEOLSIK_390 = mapOf<Int, Pair<Int, Int>>(
|
||||||
8 to (0x11c2 to 0x11bd),
|
8 to (0x11c2 to 0x11bd),
|
||||||
9 to (0x11bb to 0x0040),
|
9 to (0x11bb to 0x0040),
|
||||||
10 to (0x11b8 to 0x0023),
|
10 to (0x11b8 to 0x0023),
|
||||||
|
@ -100,7 +100,7 @@ object HangulEventDecoder {
|
||||||
76 to (0x1169 to 0x003f)
|
76 to (0x1169 to 0x003f)
|
||||||
)
|
)
|
||||||
|
|
||||||
val LAYOUT_SEBEOLSIK_FINAL = mapOf<Int, Pair<Int, Int>>(
|
private val LAYOUT_SEBEOLSIK_FINAL = mapOf<Int, Pair<Int, Int>>(
|
||||||
68 to (0x002a to 0x203b),
|
68 to (0x002a to 0x203b),
|
||||||
|
|
||||||
8 to (0x11c2 to 0x11a9),
|
8 to (0x11c2 to 0x11a9),
|
||||||
|
@ -154,7 +154,7 @@ object HangulEventDecoder {
|
||||||
76 to (0x1169 to 0x0021)
|
76 to (0x1169 to 0x0021)
|
||||||
)
|
)
|
||||||
|
|
||||||
val LAYOUTS = mapOf<String, Map<Int, Pair<Int, Int>>>(
|
private val LAYOUTS = mapOf<String, Map<Int, Pair<Int, Int>>>(
|
||||||
"korean" to LAYOUT_DUBEOLSIK_STANDARD,
|
"korean" to LAYOUT_DUBEOLSIK_STANDARD,
|
||||||
"korean_sebeolsik_390" to LAYOUT_SEBEOLSIK_390,
|
"korean_sebeolsik_390" to LAYOUT_SEBEOLSIK_390,
|
||||||
"korean_sebeolsik_final" to LAYOUT_SEBEOLSIK_FINAL
|
"korean_sebeolsik_final" to LAYOUT_SEBEOLSIK_FINAL
|
||||||
|
|
Loading…
Add table
Reference in a new issue