mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-08 12:51:51 +09:00
chinese IME almost done
This commit is contained in:
@@ -13,12 +13,13 @@ data class TerrarumKeyLayout(
|
||||
|
||||
data class TerrarumInputMethod(
|
||||
val name: String,
|
||||
// (headkey, shiftin, altgrin)
|
||||
val acceptChar: (Int, Boolean, Boolean) -> Pair<IMECanditates, IMEOutput>,
|
||||
// (headkey, shiftin, altgrin, lowLayerKeysym)
|
||||
val acceptChar: (Int, Boolean, Boolean, String) -> Pair<IMECanditates, IMEOutput>,
|
||||
val backspace: () -> IMECanditates,
|
||||
val endCompose: () -> IMEOutput,
|
||||
val reset: () -> Unit,
|
||||
val composing: () -> Boolean
|
||||
val composing: () -> Boolean,
|
||||
val maxCandidates: () -> Int
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -46,12 +47,15 @@ object IME {
|
||||
private val highLayers = HashMap<String, TerrarumInputMethod>()
|
||||
|
||||
private val context = org.graalvm.polyglot.Context.newBuilder("js")
|
||||
.allowHostAccess(org.graalvm.polyglot.HostAccess.NONE)
|
||||
.allowHostAccess(org.graalvm.polyglot.HostAccess.ALL)
|
||||
// .allowHostClassLookup { it.equals("net.torvald.terrarum.gamecontroller.IMEProviderDelegate") }
|
||||
.allowHostClassLookup { false }
|
||||
.allowIO(false)
|
||||
.build()
|
||||
|
||||
init {
|
||||
context.getBindings("js").putMember("IMEProvider", IMEProviderDelegate(this))
|
||||
|
||||
File(KEYLAYOUT_DIR).listFiles { file, s -> s.endsWith(".$KEYLAYOUT_EXTENSION") }.forEach {
|
||||
printdbg(this, "Registering Low layer ${it.nameWithoutExtension.lowercase()}")
|
||||
lowLayers[it.nameWithoutExtension.lowercase()] = parseKeylayoutFile(it)
|
||||
@@ -115,8 +119,8 @@ object IME {
|
||||
val name = jsval.getMember("n").asString()
|
||||
|
||||
|
||||
return TerrarumInputMethod(name, { headkey, shifted, alted ->
|
||||
val a = jsval.invokeMember("accept", headkey, shifted, alted)
|
||||
return TerrarumInputMethod(name, { headkey, shifted, alted, lowLayerKeysym ->
|
||||
val a = jsval.invokeMember("accept", headkey, shifted, alted, lowLayerKeysym)
|
||||
a.getArrayElement(0).asString().toCanditates() to a.getArrayElement(1).asString()
|
||||
}, {
|
||||
jsval.invokeMember("backspace").asString().toCanditates()
|
||||
@@ -126,6 +130,8 @@ object IME {
|
||||
jsval.invokeMember("reset")
|
||||
}, {
|
||||
jsval.invokeMember("composing").asBoolean()
|
||||
}, {
|
||||
jsval.invokeMember("maxCandidates").asInt()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package net.torvald.terrarum.gamecontroller
|
||||
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
|
||||
class IMEProviderDelegate(val ime: IME) {
|
||||
|
||||
private val dictionaries = HashMap<String, IMEDictionary>()
|
||||
|
||||
fun requestDictionary(filename: String): IMEDictionary {
|
||||
return dictionaries.getOrPut(filename) { IMEDictionary(filename) }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class IMEDictionary(filename: String) {
|
||||
|
||||
private val candidates = HashMap<String, String>()
|
||||
|
||||
init {
|
||||
val reader = FileReader(File("assets/keylayout/", filename))
|
||||
reader.forEachLine {
|
||||
val (key, value) = it.split(',')
|
||||
if (candidates.containsKey(key)) {
|
||||
candidates[key] += ",$value"
|
||||
}
|
||||
else {
|
||||
candidates[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
operator fun get(key: String): String = candidates[key] ?: ""
|
||||
|
||||
}
|
||||
@@ -44,6 +44,9 @@ data class InputLenCap(val count: Int, val unit: CharLenUnit) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Protip: if there are multiple TextLineInputs on a same UI, draw bottom one first, otherwise the IME's
|
||||
* candidate window will be hidden by the bottom UIItem if they overlaps.
|
||||
*
|
||||
* @param width width of the text input where the text gets drawn, not the entire item
|
||||
* @param height height of the text input where the text gets drawn, not the entire item
|
||||
*
|
||||
@@ -230,7 +233,7 @@ class UIItemTextLineInput(
|
||||
val altgrin = keycodes.contains(Input.Keys.ALT_RIGHT)
|
||||
|
||||
val codepoints = if (ime != null) {
|
||||
val newStatus = ime.acceptChar(headkey, shiftin, altgrin)
|
||||
val newStatus = ime.acceptChar(headkey, shiftin, altgrin, char)
|
||||
candidates = newStatus.first.map { CodepointSequence(it.toCodePoints()) }
|
||||
|
||||
newStatus.second.toCodePoints()
|
||||
@@ -340,6 +343,8 @@ class UIItemTextLineInput(
|
||||
return textbuf.toJavaString()
|
||||
}
|
||||
|
||||
private val candidateNumberStrWidth = App.fontGame.getWidth("8. ")
|
||||
|
||||
override fun render(batch: SpriteBatch, camera: Camera) {
|
||||
|
||||
batch.end()
|
||||
@@ -436,21 +441,36 @@ class UIItemTextLineInput(
|
||||
// draw candidates view
|
||||
if (candidates.isNotEmpty()) {
|
||||
val textWidths = candidates.map { App.fontGame.getWidth(CodepointSequence(it)) }
|
||||
|
||||
val candidateWinW = (textWidths.maxOrNull() ?: 0).coerceAtLeast(20)
|
||||
val candidateWinH = App.fontGame.lineHeight.toInt() * candidates.size
|
||||
|
||||
// candidate view background
|
||||
batch.color = TEXTINPUT_COL_BACKGROUND
|
||||
Toolkit.fillArea(batch, cursorXOnScreen + 2, posY + 27, candidateWinW, candidateWinH)
|
||||
// candidate view border
|
||||
batch.color = Toolkit.Theme.COL_ACTIVE
|
||||
Toolkit.drawBoxBorder(batch, cursorXOnScreen + 1, posY + 26, candidateWinW + 2, candidateWinH + 2)
|
||||
|
||||
// candidate view text
|
||||
for (i in candidates.indices) {
|
||||
val previewTextWidth = textWidths[i]
|
||||
App.fontGame.draw(batch, candidates[i], cursorXOnScreen + 2 + (candidateWinW - previewTextWidth) / 2, posY + 27 + i * 20)
|
||||
if (getIME()!!.maxCandidates() > 1) {
|
||||
val candidateWinW = textWidths.maxOrNull()!!.coerceAtLeast(20) + candidateNumberStrWidth
|
||||
|
||||
// candidate view background
|
||||
batch.color = TEXTINPUT_COL_BACKGROUND
|
||||
Toolkit.fillArea(batch, cursorXOnScreen + 2, posY + 27, candidateWinW + 4, candidateWinH)
|
||||
// candidate view border
|
||||
batch.color = Toolkit.Theme.COL_ACTIVE
|
||||
Toolkit.drawBoxBorder(batch, cursorXOnScreen + 1, posY + 26, candidateWinW + 6, candidateWinH + 2)
|
||||
|
||||
for (i in 0..minOf(9, candidates.lastIndex)) {
|
||||
val candidateNum = listOf(i+48,46,32)
|
||||
App.fontGame.draw(batch, CodepointSequence(candidateNum + candidates[i]), cursorXOnScreen + 4, posY + 27 + i * 20)
|
||||
}
|
||||
}
|
||||
else {
|
||||
val candidateWinW = textWidths.maxOrNull()!!.coerceAtLeast(20)
|
||||
|
||||
// candidate view background
|
||||
batch.color = TEXTINPUT_COL_BACKGROUND
|
||||
Toolkit.fillArea(batch, cursorXOnScreen + 2, posY + 27, candidateWinW, candidateWinH)
|
||||
// candidate view border
|
||||
batch.color = Toolkit.Theme.COL_ACTIVE
|
||||
Toolkit.drawBoxBorder(batch, cursorXOnScreen + 1, posY + 26, candidateWinW + 2, candidateWinH + 2)
|
||||
|
||||
val previewTextWidth = textWidths[0]
|
||||
App.fontGame.draw(batch, candidates[0], cursorXOnScreen + 2 + (candidateWinW - previewTextWidth) / 2, posY + 27)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user