js cannot be accessed concurrently

This commit is contained in:
minjaesong
2021-11-09 14:38:47 +09:00
parent 16272e76f6
commit 3c43aeec9d
10 changed files with 236 additions and 174 deletions

View File

@@ -343,7 +343,7 @@ let bufAssemble = (isPreview) => {
}
//let bufDebugStringify = (buf) => [0,1,2].map(i => (buf[i] == undefined) ? "·" : `\\u${buf[i].codePointAt(0).toString(16).toUpperCase()}`).join(' ')
let bufDebugStringify = (buf) => [0,1,2].map(i => (buf[i] == undefined) ? "·" : `${buf[i]}`).join(' ')
return Object.freeze({"n":"두벌식 표준","states":states,"c":"CuriousTo\uA75Bvald",
return Object.freeze({"n":"두벌식 표준","v":"one","c":"CuriousTo\uA75Bvald",
// return: [displayed output, composed output]
"accept":(headkey,shiftin,altgrin)=>{
let layer = 1*shiftin// + 2*altgrin
@@ -472,6 +472,5 @@ return Object.freeze({"n":"두벌식 표준","states":states,"c":"CuriousTo\uA75
return ret
},
"reset":()=>{ reset() },
"composing":()=>(states.code!=0),
"maxCandidates":()=>1
"composing":()=>(states.code!=0)
})

View File

@@ -369,7 +369,7 @@ let bufAssemble = (isPreview) => {
return states.buf.join('')
}
let bufDebugStringify = (buf) => [0,1,2].map(i => (buf[i] == undefined) ? "·" : `\\u${buf[i].codePointAt(0).toString(16).toUpperCase()}`).join(' ')
return Object.freeze({"n":"세벌식 3-90","states":states,"c":"CuriousTo\uA75Bvald",
return Object.freeze({"n":"세벌식 3-90","v":"one","c":"CuriousTo\uA75Bvald",
// return: [displayed output, composed output]
"accept":(headkey,shiftin,altgrin)=>{
let layer = 1*shiftin// + 2*altgrin
@@ -474,6 +474,5 @@ return Object.freeze({"n":"세벌식 3-90","states":states,"c":"CuriousTo\uA75Bv
return ret
},
"reset":()=>{ reset() },
"composing":()=>(states.code!=0),
"maxCandidates":()=>1
"composing":()=>(states.code!=0)
})

View File

@@ -380,7 +380,7 @@ let bufAssemble = (isPreview) => {
return states.buf.join('')
}
let bufDebugStringify = (buf) => [0,1,2].map(i => (buf[i] == undefined) ? "·" : `\\u${buf[i].codePointAt(0).toString(16).toUpperCase()}`).join(' ')
return Object.freeze({"n":"신세벌식 P2","states":states,"c":"CuriousTo\uA75Bvald",
return Object.freeze({"n":"신세벌식 P2","v":"one","c":"CuriousTo\uA75Bvald",
// return: [displayed output, composed output]
"accept":(headkey,shiftin,altgrin)=>{
let layer = 1*shiftin// + 2*altgrin
@@ -509,6 +509,5 @@ return Object.freeze({"n":"신세벌식 P2","states":states,"c":"CuriousTo\uA75B
return ret
},
"reset":()=>{ reset() },
"composing":()=>(states.code!=0),
"maxCandidates":()=>1
"composing":()=>(states.code!=0)
})

View File

@@ -269,7 +269,7 @@ let getCandidatesUsingBuf = () => {
// console.log(`cangjie in, buf: ${states.buf}, candidates: ${states.candidates}`)
return `${states.buf},${states.candidates}`
}
return Object.freeze({"n":"五仓简体 Qwerty","states":states,"c":"CuriousTo\uA75Bvald, 倉頡之友 。馬來西亞 http://www.chinesecj.com",
return Object.freeze({"n":"五仓简体 Qwerty","v":"many","c":"CuriousTo\uA75Bvald, 倉頡之友 。馬來西亞 http://www.chinesecj.com",
// return: [displayed output, composed output]
"accept":(headkey,shiftin,altgrin)=>{
let layer = 1*shiftin// + 2*altgrin
@@ -313,6 +313,5 @@ return Object.freeze({"n":"五仓简体 Qwerty","states":states,"c":"CuriousTo\u
return ret
},
"reset":()=>{ reset() },
"composing":()=>(states.code!=0),
"maxCandidates":()=>10
"composing":()=>(states.code!=0)
})

View File

@@ -269,7 +269,7 @@ let getCandidatesUsingBuf = () => {
// console.log(`cangjie in, buf: ${states.buf}, candidates: ${states.candidates}`)
return `${states.buf},${states.candidates}`
}
return Object.freeze({"n":"五倉正體 Qwerty","states":states,"c":"CuriousTo\uA75Bvald, 倉頡之友 。馬來西亞 http://www.chinesecj.com",
return Object.freeze({"n":"五倉正體 Qwerty","v":"many","c":"CuriousTo\uA75Bvald, 倉頡之友 。馬來西亞 http://www.chinesecj.com",
// return: [displayed output, composed output]
"accept":(headkey,shiftin,altgrin)=>{
let layer = 1*shiftin// + 2*altgrin
@@ -313,6 +313,5 @@ return Object.freeze({"n":"五倉正體 Qwerty","states":states,"c":"CuriousTo\u
return ret
},
"reset":()=>{ reset() },
"composing":()=>(states.code!=0),
"maxCandidates":()=>10
"composing":()=>(states.code!=0)
})

View File

@@ -11,17 +11,33 @@ data class TerrarumKeyLayout(
val symbols: Array<Array<String?>>?
)
data class TerrarumInputMethod(
data class TerrarumIME(
val name: String,
val config: TerrarumIMEConf,
// (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 maxCandidates: () -> Int
val composing: () -> Boolean
)
data class TerrarumIMEConf(
val name: String,
val copying: String,
val candidates: TerrarumIMEViewCount
)
enum class TerrarumIMEViewCount {
NONE, ONE, MANY;
fun toInt() = when (this) {
NONE -> 0
ONE -> 1
MANY -> 10 // an hard-coded config
}
}
/**
* Key Layout File Structure for Low Layer:
* - n: Displayed name of the keyboard layout
@@ -44,7 +60,7 @@ object IME {
const val IME_EXTENSION = "ime"
private val lowLayers = HashMap<String, TerrarumKeyLayout>()
private val highLayers = HashMap<String, TerrarumInputMethod>()
private val highLayers = HashMap<String, TerrarumIME>()
private val context = org.graalvm.polyglot.Context.newBuilder("js")
.allowHostAccess(org.graalvm.polyglot.HostAccess.EXPLICIT)
@@ -73,7 +89,7 @@ object IME {
return lowLayers[name.lowercase()]!!
}
fun getHighLayerByName(name: String): TerrarumInputMethod {
fun getHighLayerByName(name: String): TerrarumIME {
return highLayers[name.lowercase()]!!
}
@@ -85,12 +101,20 @@ object IME {
return highLayers.keys.toList()
}
private fun String.toViewCount() = when (this.lowercase()) {
"none" -> TerrarumIMEViewCount.NONE
"one" -> TerrarumIMEViewCount.ONE
"many" -> TerrarumIMEViewCount.MANY
else -> throw IllegalArgumentException(this)
}
private fun parseKeylayoutFile(file: File): TerrarumKeyLayout {
val src = file.readText(Charsets.UTF_8)
val jsval = context.eval("js", "'use strict';Object.freeze($src)")
val name = jsval.getMember("n").asString()
val out = Array(256) { Array<String?>(4) { null } }
for (keycode in 0L until 256L) {
val a = jsval.getMember("t").getArrayElement(keycode)
if (!a.isNull) {
@@ -113,26 +137,30 @@ object IME {
private fun String.toCanditates(): List<String> =
this.split(',').mapNotNull { it.ifBlank { null } }
private fun parseImeFile(file: File): TerrarumInputMethod {
private fun parseImeFile(file: File): TerrarumIME {
val code = file.readText(Charsets.UTF_8)
val jsval = context.eval("js", "\"use strict\";(function(){$code})()")
val name = jsval.getMember("n").asString()
val candidatesCount = jsval.getMember("v").asString().toViewCount()
val copying = jsval.getMember("c").asString()
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()
}, {
jsval.invokeMember("end").asString()
}, {
jsval.invokeMember("reset")
}, {
jsval.invokeMember("composing").asBoolean()
}, {
jsval.invokeMember("maxCandidates").asInt()
}
return TerrarumIME(
name,
TerrarumIMEConf(
name, copying, candidatesCount
),
{ 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()
}, {
jsval.invokeMember("end").asString()
}, {
jsval.invokeMember("reset")
}, {
jsval.invokeMember("composing").asBoolean()
}
)
}

View File

@@ -3,6 +3,7 @@ package net.torvald.terrarum.gamecontroller
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Input
import net.torvald.terrarum.App
import net.torvald.terrarum.TerrarumAppConfiguration
/**
* BIG WARNING SIGN: since the strober will run on separate thread, ALWAYS BEWARE OF THE [ConcurrentModificationException]!
@@ -23,9 +24,9 @@ object InputStrober {
/** always Low Layer */
// private var keymap = IME.getLowLayerByName(App.getConfigString("basekeyboardlayout"))
private val thread = Thread { while (!Thread.interrupted()) {
if (Gdx.input != null) withKeyboardEvent()
} }
private val thread = Thread({ while (!Thread.interrupted()) {
try { if (Gdx.input != null) withKeyboardEvent() } catch (e: InterruptedException) { break }
} }, "${TerrarumAppConfiguration.GAME_NAME}${this.javaClass.simpleName}")
init {
// println("InputStrobe start")

View File

@@ -75,7 +75,7 @@ object UILoadGovernor {
*/
class UILoadDemoSavefiles(val remoCon: UIRemoCon) : UICanvas() {
private val hash = RandomWordsName(3)
// private val hash = RandomWordsName(3)
init {
CommonResourcePool.addToLoadingList("inventory_category") {
@@ -359,7 +359,7 @@ class UILoadDemoSavefiles(val remoCon: UIRemoCon) : UICanvas() {
batch.draw(saveTex, (width - uiWidth - 10) / 2f, 0f)
// draw texts
val loadGameTitleStr = Lang[titles[mode]] + "$EMDASH$hash"
val loadGameTitleStr = Lang[titles[mode]]// + "$EMDASH$hash"
// "Game Load"
App.fontGame.draw(batch, loadGameTitleStr, (width - App.fontGame.getWidth(loadGameTitleStr)).div(2).toFloat(), titleTextPosY.toFloat())
// Control help

View File

@@ -12,6 +12,7 @@ import net.torvald.terrarum.ccE
import net.torvald.terrarum.console.Authenticator
import net.torvald.terrarum.console.CommandInterpreter
import net.torvald.terrarum.gameactors.AVKey
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
import net.torvald.terrarum.langpack.Lang
import net.torvald.util.CircularArray
@@ -32,14 +33,16 @@ class ConsoleWindow : UICanvas() {
private var messageDisplayPos: Int = 0
private var messagesCount: Int = 0
private var commandInputPool: StringBuilder? = null
// private var commandInputPool: StringBuilder? = null
private var commandHistory = CircularArray<String>(COMMAND_HISTORY_MAX, true)
private val LINE_HEIGHT = 20
private val MESSAGES_DISPLAY_COUNT = 11
private val inputToMsgboxGap = 3
override var width: Int = App.scr.width
override var height: Int = LINE_HEIGHT * (MESSAGES_DISPLAY_COUNT + 1)
override var height: Int = LINE_HEIGHT * (MESSAGES_DISPLAY_COUNT + 1) + inputToMsgboxGap
override var openCloseTime = 0f
@@ -51,8 +54,12 @@ class ConsoleWindow : UICanvas() {
private var iMadeTheGameToPause = false
private val textinput = UIItemTextLineInput(this, 0, 0, this.width)
init {
reset()
addUIitem(textinput)
textinput.isActive = false
}
private val lb = ArrayList<String>()
@@ -73,6 +80,8 @@ class ConsoleWindow : UICanvas() {
it.setTooltipMessage(null)
}
}
uiItems.forEach { it.update(delta) }
}
override fun renderUI(batch: SpriteBatch, camera: Camera) {
@@ -81,65 +90,75 @@ class ConsoleWindow : UICanvas() {
Toolkit.fillArea(batch, drawOffX, drawOffY, width.toFloat(), height.toFloat())
Toolkit.fillArea(batch, drawOffX, drawOffY, width.toFloat(), LINE_HEIGHT.toFloat())
val input = commandInputPool!!.toString()
val inputDrawWidth = App.fontGame.getWidth(input)
val inputDrawHeight = App.fontGame.lineHeight
// text and cursor
batch.color = Color.WHITE
App.fontGame.draw(batch, input, 1f + drawOffX, drawOffY)
batch.color = Color(0x7f7f7f_ff)
Toolkit.fillArea(batch, inputDrawWidth.toFloat() + drawOffX + 1, drawOffY, 2f, inputDrawHeight)
batch.color = Color.WHITE
Toolkit.fillArea(batch, inputDrawWidth.toFloat() + drawOffX + 1, drawOffY, 1f, inputDrawHeight - 1)
// val input = commandInputPool!!.toString()
// val inputDrawWidth = App.fontGame.getWidth(input)
// val inputDrawHeight = App.fontGame.lineHeight
//
// text and cursor
// batch.color = Color.WHITE
// App.fontGame.draw(batch, input, 1f + drawOffX, drawOffY)
//
// batch.color = Color(0x7f7f7f_ff)
// Toolkit.fillArea(batch, inputDrawWidth.toFloat() + drawOffX + 1, drawOffY, 2f, inputDrawHeight)
// batch.color = Color.WHITE
// Toolkit.fillArea(batch, inputDrawWidth.toFloat() + drawOffX + 1, drawOffY, 1f, inputDrawHeight - 1)
// messages
batch.color = Color.WHITE
for (i in 0 until MESSAGES_DISPLAY_COUNT) {
val message = messages[messageDisplayPos + i] ?: ""
App.fontGame.draw(batch, message, 1f + drawOffX, (LINE_HEIGHT * (MESSAGES_DISPLAY_COUNT - i)).toFloat() + drawOffY)
App.fontGame.draw(batch, message, 1f + drawOffX, (LINE_HEIGHT * (MESSAGES_DISPLAY_COUNT - i)).toFloat() + drawOffY + inputToMsgboxGap)
}
uiItems.forEach { it.render(batch, camera) }
}
override fun inputStrobed(e: TerrarumKeyboardEvent) {
uiItems.forEach { it.inputStrobed(e) }
}
override fun keyDown(key: Int): Boolean {
// history
if (key == Input.Keys.UP && historyIndex < commandHistory.elemCount)
historyIndex++
else if (key == Input.Keys.DOWN && historyIndex >= 0)
historyIndex--
else if (key != Input.Keys.UP && key != Input.Keys.DOWN)
historyIndex = -1
try {
val textOnBuffer = textinput.getText()
// execute
if (key == Input.Keys.ENTER && commandInputPool!!.isNotEmpty()) {
commandHistory.appendHead(commandInputPool!!.toString())
executeCommand()
commandInputPool = StringBuilder()
// history
if (key == Input.Keys.UP && historyIndex < commandHistory.elemCount)
historyIndex++
else if (key == Input.Keys.DOWN && historyIndex >= 0)
historyIndex--
else if (key != Input.Keys.UP && key != Input.Keys.DOWN)
historyIndex = -1
// execute
if (key == Input.Keys.ENTER && textOnBuffer.isNotEmpty()) {
commandHistory.appendHead(textOnBuffer)
executeCommand(textOnBuffer)
textinput.clearText()
}
// scroll
else if (key == Input.Keys.UP || key == Input.Keys.DOWN) {
// create new stringbuilder
textinput.clearText()
if (historyIndex >= 0) // just leave blank if index is -1
textinput.setText(commandHistory[historyIndex] ?: "")
}
// delete input
// else if (key == Input.Keys.BACKSPACE) {
// commandInputPool = StringBuilder()
// }
// message scroll up
else if (key == Input.Keys.PAGE_UP) {
setDisplayPos(-MESSAGES_DISPLAY_COUNT + 1)
}
// message scroll down
else if (key == Input.Keys.PAGE_DOWN) {
setDisplayPos(MESSAGES_DISPLAY_COUNT - 1)
}
}
// erase last letter
else if (key == Input.Keys.BACKSPACE && commandInputPool!!.isNotEmpty()) {
commandInputPool!!.deleteCharAt(commandInputPool!!.length - 1)
}
// scroll
else if (key == Input.Keys.UP || key == Input.Keys.DOWN) {
// create new stringbuilder
commandInputPool = StringBuilder()
if (historyIndex >= 0) // just leave blank if index is -1
commandInputPool!!.append(commandHistory[historyIndex])
}
// delete input
else if (key == Input.Keys.BACKSPACE) {
commandInputPool = StringBuilder()
}
// message scroll up
else if (key == Input.Keys.PAGE_UP) {
setDisplayPos(-MESSAGES_DISPLAY_COUNT + 1)
}
// message scroll down
else if (key == Input.Keys.PAGE_DOWN) {
setDisplayPos(MESSAGES_DISPLAY_COUNT - 1)
catch (e: ConcurrentModificationException) {
System.err.println("[ConsoleWindow] ConcurrentModificationException")
}
@@ -148,7 +167,7 @@ class ConsoleWindow : UICanvas() {
val acceptedChars = "1234567890-=qwfpgjluy;[]\\arstdhneio'zxcvbkm,./!@#$%^&*()_+QWFPGJLUY:{}|ARSTDHNEIO\"ZXCVBKM<>? ".toSet()
override fun keyTyped(character: Char): Boolean {
/*override fun keyTyped(character: Char): Boolean {
if (character in acceptedChars) {
commandInputPool!!.append(character)
inputCursorPos += 1
@@ -158,14 +177,14 @@ class ConsoleWindow : UICanvas() {
else {
return false
}
}
}*/
override fun keyUp(keycode: Int): Boolean {
return false
}
private fun executeCommand() {
CommandInterpreter.execute(commandInputPool!!.toString())
private fun executeCommand(s: String) {
CommandInterpreter.execute(s)
}
fun sendMessage(msg: String) {
@@ -200,7 +219,7 @@ class ConsoleWindow : UICanvas() {
messagesCount = 0
inputCursorPos = 0
commandHistory = CircularArray<String>(COMMAND_HISTORY_MAX, true)
commandInputPool = StringBuilder()
textinput.clearText()
if (Authenticator.b()) {
sendMessage("$ccE${TerrarumAppConfiguration.GAME_NAME} ${App.getVERSION_STRING()} $EMDASH ${TerrarumAppConfiguration.COPYRIGHT_DATE_NAME}")
@@ -232,11 +251,13 @@ class ConsoleWindow : UICanvas() {
drawOffY = MovementInterpolator.fastPullOut(openingTimeCounter.toFloat() / openCloseTime.toFloat(),
0f, -height.toFloat()
)*/
textinput.isActive = false
}
override fun endOpening(delta: Float) {
drawOffY = 0f
openingTimeCounter = 0f
textinput.isActive = true
}
override fun endClosing(delta: Float) {
@@ -252,5 +273,6 @@ class ConsoleWindow : UICanvas() {
}
override fun dispose() {
uiItems.forEach { it.dispose() }
}
}

View File

@@ -9,7 +9,6 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.glutils.FrameBuffer
import com.jme3.math.FastMath
import net.torvald.terrarum.*
import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.gamecontroller.*
import net.torvald.terrarum.utils.Clipboard
import net.torvald.terrarumsansbitmap.gdx.CodepointSequence
@@ -44,7 +43,8 @@ data class InputLenCap(val count: Int, val unit: CharLenUnit) {
}
/**
* Make sure `inputStrobed()` of the parentUI is up and running.
* UIItemTextLineInput does not require any GDX's input event handlers, but it does require InputStrober
* to be running and `inputStrobed()` of the parentUI is calling the same method on this.
*
* 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.
@@ -126,7 +126,7 @@ class UIItemTextLineInput(
private val candidatesBackCol = TEXTINPUT_COL_BACKGROUND.cpy().mul(1f,1f,1f,1.5f)
private val candidateNumberStrWidth = App.fontGame.getWidth("8. ")
private fun getIME(): TerrarumInputMethod? {
private fun getIME(): TerrarumIME? {
if (!imeOn) return null
val selectedIME = App.getConfigString("inputmethod")
@@ -165,100 +165,105 @@ class UIItemTextLineInput(
val (eventType, char, headkey, repeatCount, keycodes) = e
if (eventType == InputStrober.KEY_DOWN || eventType == InputStrober.KEY_CHANGE) {
fboUpdateLatch = true
forceLitCursor()
val ime = getIME()
try {
if (eventType == InputStrober.KEY_DOWN || eventType == InputStrober.KEY_CHANGE) {
fboUpdateLatch = true
forceLitCursor()
val ime = getIME()
if (keycodes.contains(App.getConfigInt("control_key_toggleime")) && repeatCount == 1) {
toggleIME()
}
else if (keycodes.contains(Input.Keys.V) && (keycodes.contains(Input.Keys.CONTROL_LEFT) || keycodes.contains(Input.Keys.CONTROL_RIGHT))) {
endComposing()
paste(Clipboard.fetch().substringBefore('\n').substringBefore('\t').toCodePoints())
}
else if (keycodes.contains(Input.Keys.C) && (keycodes.contains(Input.Keys.CONTROL_LEFT) || keycodes.contains(Input.Keys.CONTROL_RIGHT))) {
endComposing()
copyToClipboard()
}
else if (keycodes.contains(Input.Keys.BACKSPACE)) {
if (ime != null && ime.composing()) {
candidates = ime.backspace().map { CodepointSequence(it.toCodePoints()) }
if (keycodes.contains(App.getConfigInt("control_key_toggleime")) && repeatCount == 1) {
toggleIME()
}
else if (cursorX <= 0) {
cursorX = 0
cursorDrawX = 0
cursorDrawScroll = 0
}
else {
else if (keycodes.contains(Input.Keys.V) && (keycodes.contains(Input.Keys.CONTROL_LEFT) || keycodes.contains(Input.Keys.CONTROL_RIGHT))) {
endComposing()
if (cursorX > 0) {
while (true) {
cursorX -= 1
val oldCode = textbuf.removeAt(cursorX)
// continue deleting hangul pieces because of the font...
if (cursorX == 0 || (oldCode !in 0x115F..0x11FF && oldCode !in 0xD7B0..0xD7FF)) break
}
cursorDrawX = App.fontGame.getWidth(CodepointSequence(textbuf.subList(0, cursorX)))
tryCursorForward()
}
paste(Clipboard.fetch().substringBefore('\n').substringBefore('\t').toCodePoints())
}
}
else if (keycodes.contains(Input.Keys.LEFT)) {
endComposing()
if (cursorX > 0) {
cursorX -= 1
cursorDrawX = App.fontGame.getWidth(CodepointSequence(textbuf.subList(0, cursorX)))
tryCursorForward()
if (cursorX <= 0) {
else if (keycodes.contains(Input.Keys.C) && (keycodes.contains(Input.Keys.CONTROL_LEFT) || keycodes.contains(Input.Keys.CONTROL_RIGHT))) {
endComposing()
copyToClipboard()
}
else if (keycodes.contains(Input.Keys.BACKSPACE)) {
if (ime != null && ime.composing()) {
candidates = ime.backspace().map { CodepointSequence(it.toCodePoints()) }
}
else if (cursorX <= 0) {
cursorX = 0
cursorDrawX = 0
cursorDrawScroll = 0
}
}
}
else if (keycodes.contains(Input.Keys.RIGHT)) {
endComposing()
else {
endComposing()
if (cursorX > 0) {
while (true) {
cursorX -= 1
val oldCode = textbuf.removeAt(cursorX)
// continue deleting hangul pieces because of the font...
if (cursorX == 0 || (oldCode !in 0x115F..0x11FF && oldCode !in 0xD7B0..0xD7FF)) break
}
if (cursorX < textbuf.size) {
cursorX += 1
cursorDrawX = App.fontGame.getWidth(CodepointSequence(textbuf.subList(0, cursorX)))
tryCursorBack()
cursorDrawX = App.fontGame.getWidth(CodepointSequence(textbuf.subList(0, cursorX)))
tryCursorForward()
}
}
}
}
// accept:
// - literal "<"
// - keysymbol that does not start with "<" (not always has length of 1 because UTF-16)
else if (char != null && char.length > 0 && char[0].code >= 32 && (char == "<" || !char.startsWith("<"))) {
val shiftin = keycodes.contains(Input.Keys.SHIFT_LEFT) || keycodes.contains(Input.Keys.SHIFT_RIGHT)
val altgrin = keycodes.contains(Input.Keys.ALT_RIGHT)
else if (keycodes.contains(Input.Keys.LEFT)) {
endComposing()
val codepoints = if (ime != null) {
val newStatus = ime.acceptChar(headkey, shiftin, altgrin, char)
candidates = newStatus.first.map { CodepointSequence(it.toCodePoints()) }
newStatus.second.toCodePoints()
if (cursorX > 0) {
cursorX -= 1
cursorDrawX = App.fontGame.getWidth(CodepointSequence(textbuf.subList(0, cursorX)))
tryCursorForward()
if (cursorX <= 0) {
cursorX = 0
cursorDrawX = 0
cursorDrawScroll = 0
}
}
}
else char.toCodePoints()
else if (keycodes.contains(Input.Keys.RIGHT)) {
endComposing()
if (cursorX < textbuf.size) {
cursorX += 1
cursorDrawX = App.fontGame.getWidth(CodepointSequence(textbuf.subList(0, cursorX)))
tryCursorBack()
}
}
// accept:
// - literal "<"
// - keysymbol that does not start with "<" (not always has length of 1 because UTF-16)
else if (char != null && char.length > 0 && char[0].code >= 32 && (char == "<" || !char.startsWith("<"))) {
val shiftin = keycodes.contains(Input.Keys.SHIFT_LEFT) || keycodes.contains(Input.Keys.SHIFT_RIGHT)
val altgrin = keycodes.contains(Input.Keys.ALT_RIGHT)
val codepoints = if (ime != null) {
val newStatus = ime.acceptChar(headkey, shiftin, altgrin, char)
candidates = newStatus.first.map { CodepointSequence(it.toCodePoints()) }
newStatus.second.toCodePoints()
}
else char.toCodePoints()
// println("textinput codepoints: ${codepoints.map { it.toString(16) }.joinToString()}")
if (!maxLen.exceeds(textbuf, codepoints)) {
textbuf.addAll(cursorX, codepoints)
if (!maxLen.exceeds(textbuf, codepoints)) {
textbuf.addAll(cursorX, codepoints)
cursorX += codepoints.size
cursorDrawX = App.fontGame.getWidth(CodepointSequence(textbuf.subList(0, cursorX)))
cursorX += codepoints.size
cursorDrawX = App.fontGame.getWidth(CodepointSequence(textbuf.subList(0, cursorX)))
tryCursorBack()
tryCursorBack()
}
}
else if (keycodes.contains(Input.Keys.ENTER) || keycodes.contains(Input.Keys.NUMPAD_ENTER)) {
endComposing()
}
}
else if (keycodes.contains(Input.Keys.ENTER) || keycodes.contains(Input.Keys.NUMPAD_ENTER)) {
endComposing()
}
// don't put innards of tryCursorBack/Forward here -- you absolutely don't want that behaviour
// don't put innards of tryCursorBack/Forward here -- you absolutely don't want that behaviour
}
}
catch (e: NullPointerException) {
e.printStackTrace()
}
if (textbuf.size == 0) {
@@ -454,7 +459,7 @@ class UIItemTextLineInput(
// draw candidates view
if (candidates.isNotEmpty()) {
val textWidths = candidates.map { App.fontGame.getWidth(CodepointSequence(it)) }
val candidatesMax = getIME()!!.maxCandidates()
val candidatesMax = getIME()!!.config.candidates.toInt()
val candidatesCount = minOf(candidatesMax, candidates.size)
val isOnecolumn = (candidatesCount <= 3)
val halfcount = if (isOnecolumn) candidatesCount else FastMath.ceil(candidatesCount / 2f)
@@ -510,6 +515,17 @@ class UIItemTextLineInput(
fun getText() = textbufToString()
fun getTextOrPlaceholder(): String = if (textbuf.isEmpty()) currentPlaceholderText.toJavaString() else getText()
fun clearText() {
resetIME()
textbuf.clear()
cursorX = 0
cursorDrawScroll = 0
cursorDrawX = 0
}
fun setText(s: String) {
clearText()
textbuf.addAll(s.toCodePoints())
}
override fun dispose() {
fbo.dispose()