some formatting

This commit is contained in:
Helium314 2023-09-15 16:36:25 +02:00
parent eee94f2924
commit a7a3465e9b
4 changed files with 168 additions and 168 deletions

View file

@ -17,12 +17,29 @@ import java.util.*
* feedback on the composing state and will typically be shown with different styling such as
* a colored background.
*/
class CombinerChain(initialText: String?) {
class CombinerChain(initialText: String) {
// 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
private val mStateFeedback: SpannableStringBuilder
private val mCombiners: ArrayList<Combiner>
private val mStateFeedback = SpannableStringBuilder()
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() {
mCombinedText.setLength(0)
mStateFeedback.clear()
@ -45,14 +62,15 @@ class CombinerChain(initialText: String?) {
* @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.
*/
fun processEvent(previousEvents: ArrayList<Event>?,
newEvent: Event): Event {
fun processEvent(previousEvents: ArrayList<Event>?, newEvent: Event): Event {
val modifiablePreviousEvents = ArrayList(previousEvents!!)
var event = newEvent
for (combiner in mCombiners) { // A combiner can never return more than one event; it can return several
for (combiner in mCombiners) {
// 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)
if (event.isConsumed) { // If the event is consumed, then we don't pass it to subsequent combiners:
if (event.isConsumed) {
// If the event is consumed, then we don't pass it to subsequent combiners:
// they should not see it at all.
break
}
@ -93,22 +111,4 @@ class CombinerChain(initialText: String?) {
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()
}
}

View file

@ -17,14 +17,18 @@ import org.dslul.openboard.inputmethod.latin.common.StringUtils
* for example.
* The combiner should figure out what to do with this.
*/
class Event private constructor(// The type of event - one of the constants above
private val mEventType: Int, // If applicable, this contains the string that should be input.
val mText: CharSequence?, // The code point associated with the event, if relevant. This is a unicode code point, and
class Event private constructor(
// The type of event - one of the constants above
private val mEventType: Int,
// If applicable, this contains the string that should be input.
val mText: CharSequence?,
// The code point associated with the event, if relevant. This is a unicode code point, and
// has nothing to do with other representations of the key. It is only relevant if this event
// is of KEYPRESS type, but for a mode key like hankaku/zenkaku or ctrl, there is no code point
// associated so this should be NOT_A_CODE_POINT to avoid unintentional use of its value when
// it's not relevant.
val mCodePoint: Int, // The key code associated with the event, if relevant. This is relevant whenever this event
val mCodePoint: Int,
// 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
@ -41,38 +45,31 @@ class Event private constructor(// The type of event - one of the constants abov
// Some flags that can't go into the key code. It's a bit field of FLAG_*
private val mFlags: Int,
// 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
// that result in input like letters or space.
val isFunctionalKeyEvent: Boolean
get() =// This logic may need to be refined in the future
NOT_A_CODE_POINT == mCodePoint
get() = NOT_A_CODE_POINT == mCodePoint // This logic may need to be refined in the future
// Returns whether this event is for a dead character. @see {@link #FLAG_DEAD}
val isDead: Boolean
get() = 0 != FLAG_DEAD and mFlags
val isDead: Boolean get() = 0 != FLAG_DEAD and mFlags
val isKeyRepeat: Boolean
get() = 0 != FLAG_REPEAT and mFlags
val isKeyRepeat: Boolean get() = 0 != FLAG_REPEAT and mFlags
val isConsumed: Boolean
get() = 0 != FLAG_CONSUMED and mFlags
val isConsumed: Boolean get() = 0 != FLAG_CONSUMED and mFlags
val isCombining: Boolean
get() = 0 != FLAG_COMBINING and mFlags
val isCombining: Boolean get() = 0 != FLAG_COMBINING and mFlags
val isGesture: Boolean
get() = EVENT_TYPE_GESTURE == mEventType
val isGesture: Boolean get() = EVENT_TYPE_GESTURE == mEventType
// Returns whether this is a fake key press from the suggestion strip. This happens with
// punctuation signs selected from the suggestion strip.
val isSuggestionStripPress: Boolean
get() = EVENT_TYPE_SUGGESTION_PICKED == mEventType
val isSuggestionStripPress: Boolean get() = EVENT_TYPE_SUGGESTION_PICKED == mEventType
val isHandled: Boolean
get() = EVENT_TYPE_NOT_HANDLED != mEventType
val isHandled: Boolean get() = EVENT_TYPE_NOT_HANDLED != mEventType
// A consumed event should input no text.
val textToCommit: CharSequence?
@ -197,22 +194,20 @@ class Event private constructor(// The type of event - one of the constants abov
* or combination that outputs a string.
* @param text the CharSequence associated with this event.
* @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.
*/
@JvmStatic
fun createSoftwareTextEvent(text: CharSequence?, keyCode: Int): 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 {
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, next)
}
@JvmStatic
fun createSoftwareTextEvent(text: CharSequence?, keyCode: Int) =
createSoftwareTextEvent(text, keyCode, null)
/**
* Creates an input event representing the manual pick of a punctuation suggestion.
* @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
fun createPunctuationSuggestionPickedEvent(
suggestedWordInfo: SuggestedWordInfo): Event {
val primaryCode = suggestedWordInfo.mWord[0].toInt()
val primaryCode = suggestedWordInfo.mWord[0].code
return Event(EVENT_TYPE_SUGGESTION_PICKED, suggestedWordInfo.mWord, primaryCode,
NOT_A_KEY_CODE, Constants.SUGGESTION_STRIP_COORDINATE,
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.
* @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.
return Event(source!!.mEventType, source.mText, source.mCodePoint, source.mKeyCode,
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,
source.mX, source.mY, source.mSuggestedWordInfo, source.mFlags or FLAG_CONSUMED,
source.mNextEvent)
}

View file

@ -6,10 +6,10 @@ import java.util.ArrayList
class HangulCombiner : Combiner {
val composingWord = StringBuilder()
private val composingWord = StringBuilder()
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 {
if (event.mKeyCode == Constants.CODE_SHIFT) return event
@ -20,8 +20,7 @@ class HangulCombiner : Combiner {
} else if (event.isFunctionalKeyEvent) {
if(event.mKeyCode == Constants.CODE_DELETE) {
return when {
history.size == 1 && composingWord.isEmpty() ||
history.isEmpty() && composingWord.length == 1 -> {
history.size == 1 && composingWord.isEmpty() || history.isEmpty() && composingWord.length == 1 -> {
reset()
Event.createHardwareKeypressEvent(0x20, Constants.CODE_SPACE, event, event.isKeyRepeat)
}
@ -54,25 +53,27 @@ class HangulCombiner : Combiner {
if (currentSyllable.initial != null && currentSyllable.medial != null) {
if (currentSyllable.final == null) {
val combination = COMBINATION_TABLE_DUBEOLSIK[currentSyllable.initial.codePoint to (initial?.codePoint ?: -1)]
history +=
if (combination != null) {
history += currentSyllable.copy(initial = HangulJamo.Initial(combination))
currentSyllable.copy(initial = HangulJamo.Initial(combination))
} else {
if (final != null) {
currentSyllable.copy(final = final)
} else {
if(final != null) history += currentSyllable.copy(final = final)
else {
composingWord.append(currentSyllable.string)
history.clear()
history += HangulSyllable(initial = initial)
HangulSyllable(initial = initial)
}
}
} else {
val pair = currentSyllable.final.codePoint to (final?.codePoint ?: -1)
val combination = COMBINATION_TABLE_DUBEOLSIK[pair]
if(combination != null) {
history += currentSyllable.copy(final = HangulJamo.Final(combination, combinationPair = pair))
history += if (combination != null) {
currentSyllable.copy(final = HangulJamo.Final(combination, combinationPair = pair))
} else {
composingWord.append(currentSyllable.string)
history.clear()
history += HangulSyllable(initial = initial)
HangulSyllable(initial = initial)
}
}
} else {
@ -84,17 +85,18 @@ class HangulCombiner : Combiner {
is HangulJamo.Vowel -> {
val medial = jamo.toMedial()
if (currentSyllable.final == null) {
history +=
if (currentSyllable.medial != null) {
val combination = COMBINATION_TABLE_DUBEOLSIK[currentSyllable.medial.codePoint to (medial?.codePoint ?: -1)]
if (combination != null) {
history += currentSyllable.copy(medial = HangulJamo.Medial(combination))
currentSyllable.copy(medial = HangulJamo.Medial(combination))
} else {
composingWord.append(currentSyllable.string)
history.clear()
history += HangulSyllable(medial = medial)
HangulSyllable(medial = medial)
}
} else {
history += currentSyllable.copy(medial = medial)
currentSyllable.copy(medial = medial)
}
} else if (currentSyllable.final.combinationPair != null) {
val pair = currentSyllable.final.combinationPair
@ -119,45 +121,48 @@ class HangulCombiner : Combiner {
}
}
is HangulJamo.Initial -> {
history +=
if (currentSyllable.initial != null) {
val combination = COMBINATION_TABLE_SEBEOLSIK[currentSyllable.initial.codePoint to jamo.codePoint]
if (combination != null && currentSyllable.medial == null && currentSyllable.final == null) {
history += currentSyllable.copy(initial = HangulJamo.Initial(combination))
currentSyllable.copy(initial = HangulJamo.Initial(combination))
} else {
composingWord.append(currentSyllable.string)
history.clear()
history += HangulSyllable(initial = jamo)
HangulSyllable(initial = jamo)
}
} else {
history += currentSyllable.copy(initial = jamo)
currentSyllable.copy(initial = jamo)
}
}
is HangulJamo.Medial -> {
history +=
if (currentSyllable.medial != null) {
val combination = COMBINATION_TABLE_SEBEOLSIK[currentSyllable.medial.codePoint to jamo.codePoint]
if (combination != null) {
history += currentSyllable.copy(medial = HangulJamo.Medial(combination))
currentSyllable.copy(medial = HangulJamo.Medial(combination))
} else {
composingWord.append(currentSyllable.string)
history.clear()
history += HangulSyllable(medial = jamo)
HangulSyllable(medial = jamo)
}
} else {
history += currentSyllable.copy(medial = jamo)
currentSyllable.copy(medial = jamo)
}
}
is HangulJamo.Final -> {
history +=
if (currentSyllable.final != null) {
val combination = COMBINATION_TABLE_SEBEOLSIK[currentSyllable.final.codePoint to jamo.codePoint]
if (combination != null) {
history += currentSyllable.copy(final = HangulJamo.Final(combination))
currentSyllable.copy(final = HangulJamo.Final(combination))
} else {
composingWord.append(currentSyllable.string)
history.clear()
history += HangulSyllable(final = jamo)
HangulSyllable(final = jamo)
}
} else {
history += currentSyllable.copy(final = jamo)
currentSyllable.copy(final = jamo)
}
}
// 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
fun toConsonant(): Consonant? {
val codePoint = COMPAT_CONSONANTS.getOrNull(CONVERT_INITIALS.indexOf(codePoint.toChar())) ?: return null
if(codePoint.toInt() == 0) return null
return Consonant(codePoint.toInt())
if(codePoint.code == 0) return null
return Consonant(codePoint.code)
}
}
data class Medial(override val codePoint: Int) : HangulJamo() {
@ -199,7 +204,7 @@ class HangulCombiner : Combiner {
val ordinal: Int get() = codePoint - 0x1161
fun toVowel(): Vowel? {
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() {
@ -207,8 +212,8 @@ class HangulCombiner : Combiner {
val ordinal: Int get() = codePoint - 0x11a7
fun toConsonant(): Consonant? {
val codePoint = COMPAT_CONSONANTS.getOrNull(CONVERT_FINALS.indexOf(codePoint.toChar())) ?: return null
if(codePoint.toInt() == 0) return null
return Consonant(codePoint.toInt())
if(codePoint.code == 0) return null
return Consonant(codePoint.code)
}
}
data class Consonant(override val codePoint: Int) : HangulJamo() {
@ -216,13 +221,13 @@ class HangulCombiner : Combiner {
val ordinal: Int get() = codePoint - 0x3131
fun toInitial(): Initial? {
val codePoint = CONVERT_INITIALS.getOrNull(COMPAT_CONSONANTS.indexOf(codePoint.toChar())) ?: return null
if(codePoint.toInt() == 0) return null
return Initial(codePoint.toInt())
if(codePoint.code == 0) return null
return Initial(codePoint.code)
}
fun toFinal(): Final? {
val codePoint = CONVERT_FINALS.getOrNull(COMPAT_CONSONANTS.indexOf(codePoint.toChar())) ?: return null
if(codePoint.toInt() == 0) return null
return Final(codePoint.toInt())
if(codePoint.code == 0) return null
return Final(codePoint.code)
}
}
data class Vowel(override val codePoint: Int) : HangulJamo() {
@ -230,8 +235,8 @@ class HangulCombiner : Combiner {
val ordinal: Int get() = codePoint - 0x314f1
fun toMedial(): Medial? {
val codePoint = CONVERT_MEDIALS.getOrNull(COMPAT_VOWELS.indexOf(codePoint.toChar())) ?: return null
if(codePoint.toInt() == 0) return null
return Medial(codePoint.toInt())
if(codePoint.code == 0) return null
return Medial(codePoint.code)
}
}
companion object {
@ -320,7 +325,7 @@ class HangulCombiner : Combiner {
0x11ba to 0x11ba to 0x11bb // ㅆ
)
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)
}
}

View file

@ -22,7 +22,7 @@ object HangulEventDecoder {
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),
51 to (0x3148 to 0x3149),
33 to (0x3137 to 0x3138),
@ -53,7 +53,7 @@ object HangulEventDecoder {
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),
9 to (0x11bb to 0x0040),
10 to (0x11b8 to 0x0023),
@ -100,7 +100,7 @@ object HangulEventDecoder {
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),
8 to (0x11c2 to 0x11a9),
@ -154,7 +154,7 @@ object HangulEventDecoder {
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_sebeolsik_390" to LAYOUT_SEBEOLSIK_390,
"korean_sebeolsik_final" to LAYOUT_SEBEOLSIK_FINAL