Compare commits

..

No commits in common. "cbaa339c376ff9d3a34e1f0a49de26857c08cc93" and "c89d4f02045f45df5d0156186d41e637fbdd6ecd" have entirely different histories.

11 changed files with 40 additions and 80 deletions

View File

@ -5,7 +5,6 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" <uses-permission android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" /> tools:ignore="ProtectedPermissions" />

View File

@ -1,7 +1,6 @@
package net.mezimmah.wkt9 package net.mezimmah.wkt9
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent import android.content.Intent
import android.inputmethodservice.InputMethodService import android.inputmethodservice.InputMethodService
import android.media.AudioManager import android.media.AudioManager
@ -18,8 +17,6 @@ import android.view.inputmethod.InputMethodManager
import android.view.textservice.SentenceSuggestionsInfo import android.view.textservice.SentenceSuggestionsInfo
import android.view.textservice.SpellCheckerSession import android.view.textservice.SpellCheckerSession
import android.view.textservice.SuggestionsInfo import android.view.textservice.SuggestionsInfo
import android.view.textservice.TextInfo
import android.view.textservice.TextServicesManager
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
@ -50,6 +47,11 @@ import okio.IOException
import java.io.File import java.io.File
import java.util.Locale import java.util.Locale
//val info = arrayOf(TextInfo("banan#", 0, 6, 0, 0))
//
//spellCheckerSession?.getSentenceSuggestions(info, 10)
class WKT9: InputMethodService(), SpellCheckerSession.SpellCheckerSessionListener { class WKT9: InputMethodService(), SpellCheckerSession.SpellCheckerSessionListener {
private val tag = "WKT9" private val tag = "WKT9"
@ -208,8 +210,10 @@ class WKT9: InputMethodService(), SpellCheckerSession.SpellCheckerSessionListene
val inputClass = inputType?.and(InputType.TYPE_MASK_CLASS) ?: 0 val inputClass = inputType?.and(InputType.TYPE_MASK_CLASS) ?: 0
val typeVariation = inputType?.and(InputType.TYPE_MASK_VARIATION) ?: 0 val typeVariation = inputType?.and(InputType.TYPE_MASK_VARIATION) ?: 0
val typeFlags = inputType?.and(InputType.TYPE_MASK_FLAGS) ?: 0 val typeFlags = inputType?.and(InputType.TYPE_MASK_FLAGS) ?: 0
// val textServiceManager = getSystemService(TEXT_SERVICES_MANAGER_SERVICE) as TextServicesManager
cursorPosition = attribute?.initialSelEnd ?: 0 cursorPosition = attribute?.initialSelEnd ?: 0
// spellCheckerSession = textServiceManager.newSpellCheckerSession(null, locale, this, false)
val forceNumeric = resources.getStringArray(R.array.input_mode_numeric) val forceNumeric = resources.getStringArray(R.array.input_mode_numeric)
@ -255,18 +259,14 @@ class WKT9: InputMethodService(), SpellCheckerSession.SpellCheckerSessionListene
} }
override fun onGetSentenceSuggestions(suggestionsInfo: Array<out SentenceSuggestionsInfo>?) { override fun onGetSentenceSuggestions(suggestionsInfo: Array<out SentenceSuggestionsInfo>?) {
clearCandidates()
suggestionsInfo?.map { suggestionsInfo?.map {
val suggestions = it.getSuggestionsInfoAt(0) val suggestions = it.getSuggestionsInfoAt(0)
for (index in 0 until suggestions.suggestionsCount) { for (index in 0 until suggestions.suggestionsCount) {
val suggestion = suggestions.getSuggestionAt(index) val suggestion = suggestions.getSuggestionAt(index)
candidates.add(suggestion) Log.d(tag, "Suggestion: $suggestion")
} }
if (candidates.isNotEmpty()) loadCandidates()
} }
} }
@ -344,41 +344,28 @@ class WKT9: InputMethodService(), SpellCheckerSession.SpellCheckerSessionListene
InputType.TYPE_TEXT_VARIATION_PERSON_NAME InputType.TYPE_TEXT_VARIATION_PERSON_NAME
) )
val mode: WKT9InputMode = if (letterVariations.contains(variation)) { if (letterVariations.contains(variation)) {
allowSuggestions = false allowSuggestions = false
WKT9InputMode.ALPHA enableInputMode(WKT9InputMode.ALPHA)
} else if (lastInputMode == WKT9InputMode.ALPHA) { } else if (lastInputMode == WKT9InputMode.ALPHA) {
allowSuggestions = flags != InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS allowSuggestions = flags != InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
WKT9InputMode.ALPHA enableInputMode(WKT9InputMode.ALPHA)
} else { } else enableInputMode(WKT9InputMode.WORD)
allowSuggestions = flags != InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
WKT9InputMode.WORD
}
spellCheckerSession = if (allowSuggestions) {
val textServiceManager = getSystemService(TEXT_SERVICES_MANAGER_SERVICE) as TextServicesManager
textServiceManager.newSpellCheckerSession(null, locale, this, false)
} else {
spellCheckerSession?.apply {
cancel()
close()
}
null
}
enableInputMode(mode)
} }
private fun finishComposingText(): Boolean { private fun finishComposingText(): Boolean {
return if (composing) { return if (composing) {
composing = false composing = false
if (allowSuggestions && inputMode is AlphaInputMode) handleSuggestions() lastComposedString?.let {
commitHistory.add(it)
lastComposedString = null
}
if (allowSuggestions) Log.d(tag, "History: $commitHistory")
updateInputStatus() updateInputStatus()
@ -386,28 +373,6 @@ class WKT9: InputMethodService(), SpellCheckerSession.SpellCheckerSessionListene
} else false } else false
} }
private fun handleSuggestions() {
val lastComposed = lastComposedString ?: return
val lastChar = lastComposed.lowercase().last()
val code = keypad.codeForLetter(lastChar)
if (lastComposed.length != 1 || code == null) {
commitHistory.clear()
return
}
commitHistory.add(lastComposed)
// loadSuggestions(commitHistory.joinToString(""))
}
private fun loadSuggestions(word: String) {
val info = arrayOf(TextInfo(word.plus("#"), 0, word.length + 1, 0, 0))
spellCheckerSession?.getSentenceSuggestions(info, 10)
}
@SuppressLint("DiscouragedApi") @SuppressLint("DiscouragedApi")
private fun getIconResource(): Int { private fun getIconResource(): Int {
val mode = inputMode?.mode ?: return resources.getIdentifier("wkt9", "drawable", packageName) val mode = inputMode?.mode ?: return resources.getIdentifier("wkt9", "drawable", packageName)
@ -422,20 +387,11 @@ class WKT9: InputMethodService(), SpellCheckerSession.SpellCheckerSessionListene
} }
private fun goHome() { private fun goHome() {
if (Settings.canDrawOverlays(this)) { with(Intent(Intent.ACTION_MAIN)) {
val startMain = Intent(Intent.ACTION_MAIN) this.addCategory(Intent.CATEGORY_HOME)
this.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startMain.addCategory(Intent.CATEGORY_HOME) startActivity(this)
startMain.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(startMain)
} else {
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)
intent.data = Uri.parse("package:$packageName")
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
} }
} }
@ -491,11 +447,11 @@ class WKT9: InputMethodService(), SpellCheckerSession.SpellCheckerSessionListene
return false return false
} }
private fun loadCandidates() { private fun loadCandidates(highLight: Int? = null) {
val candidatesView = inputView?.findViewById<LinearLayout>(R.id.suggestions) ?: return val candidatesView = inputView?.findViewById<LinearLayout>(R.id.suggestions) ?: return
candidates.forEachIndexed { index, candidate -> candidates.forEachIndexed { index, candidate ->
val layout = if (index == candidateIndex) R.layout.current_suggestion else R.layout.suggestion val layout = if (index == highLight) R.layout.current_suggestion else R.layout.suggestion
val candidateView = layoutInflater.inflate(layout, null) val candidateView = layoutInflater.inflate(layout, null)
val textView = candidateView.findViewById<TextView>(R.id.suggestion_text) val textView = candidateView.findViewById<TextView>(R.id.suggestion_text)
@ -530,7 +486,7 @@ class WKT9: InputMethodService(), SpellCheckerSession.SpellCheckerSessionListene
this.candidates.add(candidate) this.candidates.add(candidate)
} }
loadCandidates() loadCandidates(candidateIndex)
composeText(this.candidates[candidateIndex]) composeText(this.candidates[candidateIndex])
handleComposeTimeout(timeout) handleComposeTimeout(timeout)
} }
@ -544,7 +500,7 @@ class WKT9: InputMethodService(), SpellCheckerSession.SpellCheckerSessionListene
if (!hasCandidates) return@launch if (!hasCandidates) return@launch
loadCandidates() loadCandidates(candidateIndex)
composeText(candidates[candidateIndex], 1) composeText(candidates[candidateIndex], 1)
handleComposeTimeout(timeout) handleComposeTimeout(timeout)
} }
@ -626,7 +582,7 @@ class WKT9: InputMethodService(), SpellCheckerSession.SpellCheckerSessionListene
if (candidateIndex < 0) candidateIndex = candidates.count() - 1 if (candidateIndex < 0) candidateIndex = candidates.count() - 1
clearCandidateUI() clearCandidateUI()
loadCandidates() loadCandidates(candidateIndex)
composeText(candidates[candidateIndex]) composeText(candidates[candidateIndex])
handleComposeTimeout(this.timeout) handleComposeTimeout(this.timeout)
} }
@ -676,7 +632,7 @@ class WKT9: InputMethodService(), SpellCheckerSession.SpellCheckerSessionListene
if (candidateIndex >= candidates.count()) candidateIndex = 0 if (candidateIndex >= candidates.count()) candidateIndex = 0
clearCandidateUI() clearCandidateUI()
loadCandidates() loadCandidates(candidateIndex)
composeText(candidates[candidateIndex]) composeText(candidates[candidateIndex])
handleComposeTimeout(this.timeout) handleComposeTimeout(this.timeout)
} }
@ -745,7 +701,7 @@ class WKT9: InputMethodService(), SpellCheckerSession.SpellCheckerSessionListene
} }
showStatusIcon(getIconResource()) showStatusIcon(getIconResource())
loadCandidates() loadCandidates(candidateIndex)
composeText(candidates[candidateIndex]) composeText(candidates[candidateIndex])
} }

View File

@ -6,6 +6,8 @@ import net.mezimmah.wkt9.keypad.Key
import net.mezimmah.wkt9.keypad.KeyEventResult import net.mezimmah.wkt9.keypad.KeyEventResult
class AlphaInputMode: BaseInputMode() { class AlphaInputMode: BaseInputMode() {
private val tag = "WKT9"
init { init {
mode = "alpha" mode = "alpha"
status = Status.CAP status = Status.CAP

View File

@ -6,8 +6,6 @@ import net.mezimmah.wkt9.keypad.KeyEventResult
import net.mezimmah.wkt9.keypad.KeyLayout import net.mezimmah.wkt9.keypad.KeyLayout
open class BaseInputMode: InputMode { open class BaseInputMode: InputMode {
protected val tag = "WKT9"
protected var newKey = true protected var newKey = true
protected var keyIndex = 0 protected var keyIndex = 0
protected var lastKey: Key? = null protected var lastKey: Key? = null

View File

@ -7,6 +7,7 @@ import net.mezimmah.wkt9.keypad.KeyCommandResolver
import net.mezimmah.wkt9.keypad.KeyEventResult import net.mezimmah.wkt9.keypad.KeyEventResult
class FNInputMode: BaseInputMode() { class FNInputMode: BaseInputMode() {
private val tag = "WKT9"
override val keyCommandResolver: KeyCommandResolver = KeyCommandResolver( override val keyCommandResolver: KeyCommandResolver = KeyCommandResolver(
parent = super.keyCommandResolver, parent = super.keyCommandResolver,

View File

@ -6,6 +6,8 @@ import net.mezimmah.wkt9.keypad.Key
import net.mezimmah.wkt9.keypad.KeyEventResult import net.mezimmah.wkt9.keypad.KeyEventResult
class IdleInputMode : BaseInputMode() { class IdleInputMode : BaseInputMode() {
private val tag = "WKT9"
init { init {
mode = "idle" mode = "idle"
status = Status.NA status = Status.NA

View File

@ -7,6 +7,7 @@ import net.mezimmah.wkt9.keypad.KeyCommandResolver
import net.mezimmah.wkt9.keypad.KeyEventResult import net.mezimmah.wkt9.keypad.KeyEventResult
class NumericInputMode: BaseInputMode() { class NumericInputMode: BaseInputMode() {
private val tag = "WKT9"
override val keyCommandResolver: KeyCommandResolver = KeyCommandResolver( override val keyCommandResolver: KeyCommandResolver = KeyCommandResolver(
parent = super.keyCommandResolver, parent = super.keyCommandResolver,

View File

@ -8,6 +8,7 @@ import net.mezimmah.wkt9.keypad.KeyLayout
import java.lang.StringBuilder import java.lang.StringBuilder
class WordInputMode: BaseInputMode() { class WordInputMode: BaseInputMode() {
private val tag = "WKT9"
private val codeWord = StringBuilder() private val codeWord = StringBuilder()
init { init {

View File

@ -16,7 +16,7 @@ object KeyLayout {
) )
val en_US = mapOf( val en_US = mapOf(
Key.N1 to listOf('.','?','!',',','-','+','=','\'','"','@','$','/','%',':','(',')'), Key.N1 to listOf('.','?','!',',','-','\'','"','@','$','/','%',':','(',')'),
Key.N2 to listOf('a','b','c','ä','æ','å','à','á','â','ã','ç'), Key.N2 to listOf('a','b','c','ä','æ','å','à','á','â','ã','ç'),
Key.N3 to listOf('d','e','f','è','é','ê','ë','đ'), Key.N3 to listOf('d','e','f','è','é','ê','ë','đ'),
Key.N4 to listOf('g','h','i','ì','í','î','ï'), Key.N4 to listOf('g','h','i','ì','í','î','ï'),

View File

@ -44,7 +44,7 @@ class Keypad(
return builder.toString() return builder.toString()
} }
fun codeForLetter(letter: Char): Int? { private fun codeForLetter(letter: Char): Int? {
return letterCodeMap[letter] return letterCodeMap[letter]
} }
} }

View File

@ -1,6 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins { plugins {
id("com.android.application") version "8.1.1" apply false id("com.android.application") version "8.1.0" apply false
id("org.jetbrains.kotlin.android") version "1.8.0" apply false id("org.jetbrains.kotlin.android") version "1.8.0" apply false
id("com.google.devtools.ksp") version "1.8.10-1.0.9" apply false id("com.google.devtools.ksp") version "1.8.10-1.0.9" apply false
} }