mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-09 19:50:27 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
ad36c99b4f
@ -220,6 +220,44 @@ fun main() {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 发送引用回复消息(仅支持群消息)
|
||||||
|
|
||||||
|
```
|
||||||
|
[POST] /sendQuoteMessage
|
||||||
|
```
|
||||||
|
|
||||||
|
使用此方法向指定的消息进行引用回复
|
||||||
|
|
||||||
|
#### 请求
|
||||||
|
|
||||||
|
```json5
|
||||||
|
{
|
||||||
|
"sessionKey": "YourSession",
|
||||||
|
"target": 987654321,
|
||||||
|
"messageChain": [
|
||||||
|
{ "type": "Plain", "text":"hello\n" },
|
||||||
|
{ "type": "Plain", "text":"world" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| 名字 | 类型 | 可选 | 举例 | 说明 |
|
||||||
|
| ------------ | ------ | ----- | ----------- | -------------------------------- |
|
||||||
|
| sessionKey | String | false | YourSession | 已经激活的Session |
|
||||||
|
| target | Long | false | 987654321 | 引用消息的Message Source的Uid |
|
||||||
|
| messageChain | Array | false | [] | 消息链,是一个消息对象构成的数组 |
|
||||||
|
|
||||||
|
#### 响应: 返回统一状态码
|
||||||
|
|
||||||
|
```json5
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"msg": "success"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 发送图片消息(通过URL)
|
### 发送图片消息(通过URL)
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -308,6 +346,9 @@ Content-Type:multipart/form-data
|
|||||||
[{
|
[{
|
||||||
"type": "GroupMessage", // 消息类型:GroupMessage或FriendMessage
|
"type": "GroupMessage", // 消息类型:GroupMessage或FriendMessage
|
||||||
"messageChain": [{ // 消息链,是一个消息对象构成的数组
|
"messageChain": [{ // 消息链,是一个消息对象构成的数组
|
||||||
|
"type": "Source",
|
||||||
|
"uid": 123456
|
||||||
|
},{
|
||||||
"type": "Plain",
|
"type": "Plain",
|
||||||
"text": "Miral牛逼"
|
"text": "Miral牛逼"
|
||||||
}],
|
}],
|
||||||
@ -350,6 +391,19 @@ Content-Type:multipart/form-data
|
|||||||
+ [ ] Xml,Xml卡片消息
|
+ [ ] Xml,Xml卡片消息
|
||||||
+ [ ] 敬请期待
|
+ [ ] 敬请期待
|
||||||
|
|
||||||
|
#### Source
|
||||||
|
|
||||||
|
```json5
|
||||||
|
{
|
||||||
|
"type": "Source",
|
||||||
|
"uid": 123456
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| 名字 | 类型 | 说明 |
|
||||||
|
| ---- | ---- | ------------------------------------------------------------ |
|
||||||
|
| uid | Long | 消息的识别号,用于引用回复(Source类型只在群消息中返回,且永远为chain的第一个元素) |
|
||||||
|
|
||||||
#### At
|
#### At
|
||||||
|
|
||||||
```json5
|
```json5
|
||||||
|
@ -36,6 +36,9 @@ data class UnKnownMessagePacketDTO(val msg: String) : MessagePacketDTO()
|
|||||||
|
|
||||||
// Message
|
// Message
|
||||||
@Serializable
|
@Serializable
|
||||||
|
@SerialName("Source")
|
||||||
|
data class MessageSourceDTO(val uid: Long) : MessageDTO()
|
||||||
|
@Serializable
|
||||||
@SerialName("At")
|
@SerialName("At")
|
||||||
data class AtDTO(val target: Long, val display: String) : MessageDTO()
|
data class AtDTO(val target: Long, val display: String) : MessageDTO()
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -85,6 +88,7 @@ fun MessageChainDTO.toMessageChain() =
|
|||||||
|
|
||||||
@UseExperimental(ExperimentalUnsignedTypes::class)
|
@UseExperimental(ExperimentalUnsignedTypes::class)
|
||||||
fun Message.toDTO() = when (this) {
|
fun Message.toDTO() = when (this) {
|
||||||
|
is MessageSource -> MessageSourceDTO(messageUid)
|
||||||
is At -> AtDTO(target, display)
|
is At -> AtDTO(target, display)
|
||||||
is AtAll -> AtAllDTO(0L)
|
is AtAll -> AtAllDTO(0L)
|
||||||
is Face -> FaceDTO(id.value.toInt())
|
is Face -> FaceDTO(id.value.toInt())
|
||||||
@ -102,7 +106,7 @@ fun MessageDTO.toMessage() = when (this) {
|
|||||||
is PlainDTO -> PlainText(text)
|
is PlainDTO -> PlainText(text)
|
||||||
is ImageDTO -> Image(imageId)
|
is ImageDTO -> Image(imageId)
|
||||||
is XmlDTO -> XMLMessage(xml)
|
is XmlDTO -> XMLMessage(xml)
|
||||||
is UnknownMessageDTO -> PlainText("assert cannot reach")
|
is MessageSourceDTO, is UnknownMessageDTO -> PlainText("assert cannot reach")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,17 +9,32 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.api.http.queue
|
package net.mamoe.mirai.api.http.queue
|
||||||
|
|
||||||
|
import net.mamoe.mirai.message.GroupMessage
|
||||||
import net.mamoe.mirai.message.MessagePacket
|
import net.mamoe.mirai.message.MessagePacket
|
||||||
|
import net.mamoe.mirai.message.data.MessageSource
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import java.util.concurrent.ConcurrentLinkedDeque
|
import java.util.concurrent.ConcurrentLinkedDeque
|
||||||
|
|
||||||
class MessageQueue : ConcurrentLinkedDeque<MessagePacket<*, *>>() {
|
class MessageQueue : ConcurrentLinkedDeque<MessagePacket<*, *>>() {
|
||||||
|
|
||||||
|
val quoteCache = ConcurrentHashMap<Long, GroupMessage>()
|
||||||
|
|
||||||
fun fetch(size: Int): List<MessagePacket<*, *>> {
|
fun fetch(size: Int): List<MessagePacket<*, *>> {
|
||||||
var count = size
|
var count = size
|
||||||
|
quoteCache.clear()
|
||||||
val ret = ArrayList<MessagePacket<*, *>>(count)
|
val ret = ArrayList<MessagePacket<*, *>>(count)
|
||||||
while (!this.isEmpty() && count-- > 0) {
|
while (!this.isEmpty() && count-- > 0) {
|
||||||
ret.add(this.pop())
|
val packet = pop()
|
||||||
|
ret.add(packet)
|
||||||
|
|
||||||
|
if (packet is GroupMessage) {
|
||||||
|
addCache(packet)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun addCache(msg: GroupMessage) {
|
||||||
|
quoteCache[msg.message[MessageSource].messageUid] = msg
|
||||||
|
}
|
||||||
}
|
}
|
@ -52,6 +52,12 @@ fun Application.messageModule() {
|
|||||||
call.respondStateCode(StateCode.Success)
|
call.respondStateCode(StateCode.Success)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
miraiVerify<SendDTO>("/quoteMessage") {
|
||||||
|
it.session.messageQueue.quoteCache[it.target]?.quoteReply(it.messageChain.toMessageChain())
|
||||||
|
?: throw NoSuchElementException()
|
||||||
|
call.respondStateCode(StateCode.Success)
|
||||||
|
}
|
||||||
|
|
||||||
miraiVerify<SendImageDTO>("sendImageMessage") {
|
miraiVerify<SendImageDTO>("sendImageMessage") {
|
||||||
val bot = it.session.bot
|
val bot = it.session.bot
|
||||||
val contact = when {
|
val contact = when {
|
||||||
@ -72,12 +78,14 @@ fun Application.messageModule() {
|
|||||||
if (!SessionManager.containSession(sessionKey)) throw IllegalSessionException
|
if (!SessionManager.containSession(sessionKey)) throw IllegalSessionException
|
||||||
val session = try {
|
val session = try {
|
||||||
SessionManager[sessionKey] as AuthedSession
|
SessionManager[sessionKey] as AuthedSession
|
||||||
} catch (e: TypeCastException) { throw NotVerifiedSessionException }
|
} catch (e: TypeCastException) {
|
||||||
|
throw NotVerifiedSessionException
|
||||||
|
}
|
||||||
|
|
||||||
val type = parts.value("type")
|
val type = parts.value("type")
|
||||||
parts.file("img")?.apply {
|
parts.file("img")?.apply {
|
||||||
val image = streamProvider().use {
|
val image = streamProvider().use {
|
||||||
when(type) {
|
when (type) {
|
||||||
"group" -> session.bot.groups.toList().random().uploadImage(it)
|
"group" -> session.bot.groups.toList().random().uploadImage(it)
|
||||||
"friend" -> session.bot.qqs.toList().random().uploadImage(it)
|
"friend" -> session.bot.qqs.toList().random().uploadImage(it)
|
||||||
else -> null
|
else -> null
|
||||||
|
@ -13,6 +13,7 @@ import kotlinx.serialization.*
|
|||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.modules.SerializersModule
|
import kotlinx.serialization.modules.SerializersModule
|
||||||
import net.mamoe.mirai.api.http.data.common.*
|
import net.mamoe.mirai.api.http.data.common.*
|
||||||
|
import net.mamoe.mirai.message.data.MessageSource
|
||||||
|
|
||||||
// 解析失败时直接返回null,由路由判断响应400状态
|
// 解析失败时直接返回null,由路由判断响应400状态
|
||||||
@UseExperimental(ImplicitReflectionSerializer::class)
|
@UseExperimental(ImplicitReflectionSerializer::class)
|
||||||
@ -50,6 +51,7 @@ object MiraiJson {
|
|||||||
UnKnownMessagePacketDTO::class with UnKnownMessagePacketDTO.serializer()
|
UnKnownMessagePacketDTO::class with UnKnownMessagePacketDTO.serializer()
|
||||||
}
|
}
|
||||||
polymorphic(MessageDTO.serializer()) {
|
polymorphic(MessageDTO.serializer()) {
|
||||||
|
MessageSourceDTO::class with MessageSourceDTO.serializer()
|
||||||
AtDTO::class with AtDTO.serializer()
|
AtDTO::class with AtDTO.serializer()
|
||||||
AtAllDTO::class with AtAllDTO.serializer()
|
AtAllDTO::class with AtAllDTO.serializer()
|
||||||
FaceDTO::class with FaceDTO.serializer()
|
FaceDTO::class with FaceDTO.serializer()
|
||||||
|
@ -42,5 +42,6 @@ dependencies {
|
|||||||
api(group = "com.alibaba", name = "fastjson", version = "1.2.62")
|
api(group = "com.alibaba", name = "fastjson", version = "1.2.62")
|
||||||
api(group = "org.yaml", name = "snakeyaml", version = "1.25")
|
api(group = "org.yaml", name = "snakeyaml", version = "1.25")
|
||||||
api(group = "com.moandjiezana.toml", name = "toml4j", version = "0.7.2")
|
api(group = "com.moandjiezana.toml", name = "toml4j", version = "0.7.2")
|
||||||
|
api(group = "com.googlecode.lanterna", name = "lanterna", version = "3.0.2")
|
||||||
// classpath is not set correctly by IDE
|
// classpath is not set correctly by IDE
|
||||||
}
|
}
|
@ -17,6 +17,7 @@ import net.mamoe.mirai.plugins.withDefaultWriteSave
|
|||||||
import net.mamoe.mirai.api.http.MiraiHttpAPIServer
|
import net.mamoe.mirai.api.http.MiraiHttpAPIServer
|
||||||
import net.mamoe.mirai.api.http.generateSessionKey
|
import net.mamoe.mirai.api.http.generateSessionKey
|
||||||
import net.mamoe.mirai.contact.sendMessage
|
import net.mamoe.mirai.contact.sendMessage
|
||||||
|
import net.mamoe.mirai.utils.MiraiLogger
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import kotlin.concurrent.thread
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
@ -37,7 +38,7 @@ object MiraiConsole {
|
|||||||
get() = PluginManager
|
get() = PluginManager
|
||||||
|
|
||||||
var logger: MiraiConsoleLogger =
|
var logger: MiraiConsoleLogger =
|
||||||
DefaultLogger
|
UIPushLogger()
|
||||||
|
|
||||||
var path: String = System.getProperty("user.dir")
|
var path: String = System.getProperty("user.dir")
|
||||||
|
|
||||||
@ -254,14 +255,11 @@ object MiraiConsole {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MiraiConsoleLogger {
|
class UIPushLogger(override val identity: String?, override var follower: MiraiLogger?) : MiraiLogger {
|
||||||
operator fun invoke(any: Any? = null)
|
|
||||||
}
|
|
||||||
|
|
||||||
object DefaultLogger : MiraiConsoleLogger {
|
|
||||||
override fun invoke(any: Any?) {
|
override fun invoke(any: Any?) {
|
||||||
|
MiraiConsoleUI.start()
|
||||||
if (any != null) {
|
if (any != null) {
|
||||||
println("[Mirai$version $build]: " + any.toString())
|
MiraiConsoleUI.pushLog(0, "[Mirai$version $build]: $any")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -287,6 +285,7 @@ class MiraiConsoleLoader {
|
|||||||
Runtime.getRuntime().addShutdownHook(thread(start = false) {
|
Runtime.getRuntime().addShutdownHook(thread(start = false) {
|
||||||
MiraiConsole.stop()
|
MiraiConsole.stop()
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
318
mirai-console/src/main/kotlin/net/mamoe/mirai/MiraiConsoleUI.kt
Normal file
318
mirai-console/src/main/kotlin/net/mamoe/mirai/MiraiConsoleUI.kt
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
package net.mamoe.mirai
|
||||||
|
|
||||||
|
import com.googlecode.lanterna.SGR
|
||||||
|
import com.googlecode.lanterna.TerminalSize
|
||||||
|
import com.googlecode.lanterna.TextColor
|
||||||
|
import com.googlecode.lanterna.graphics.TextGraphics
|
||||||
|
import com.googlecode.lanterna.input.KeyStroke
|
||||||
|
import com.googlecode.lanterna.input.KeyType
|
||||||
|
import com.googlecode.lanterna.terminal.DefaultTerminalFactory
|
||||||
|
import com.googlecode.lanterna.terminal.Terminal
|
||||||
|
import com.googlecode.lanterna.terminal.TerminalResizeListener
|
||||||
|
import com.googlecode.lanterna.terminal.swing.SwingTerminal
|
||||||
|
import com.googlecode.lanterna.terminal.swing.SwingTerminalFrame
|
||||||
|
import java.lang.StringBuilder
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
|
|
||||||
|
object MiraiConsoleUI {
|
||||||
|
|
||||||
|
val log = mutableMapOf<Long, LimitLinkedQueue<String>>().also { it[0L] = LimitLinkedQueue(50) }
|
||||||
|
|
||||||
|
|
||||||
|
private val screens = mutableListOf(0L)
|
||||||
|
private var currentScreenId = 0
|
||||||
|
|
||||||
|
fun addBotScreen(uin: Long) {
|
||||||
|
screens.add(uin)
|
||||||
|
log[uin] = LimitLinkedQueue()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pushLog(uin: Long, str: String) {
|
||||||
|
log[uin]!!.push(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasStart = false
|
||||||
|
fun start() {
|
||||||
|
if (hasStart) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hasStart = true
|
||||||
|
val defaultTerminalFactory = DefaultTerminalFactory()
|
||||||
|
var terminal: Terminal? = null
|
||||||
|
try {
|
||||||
|
terminal = defaultTerminalFactory.createTerminal()
|
||||||
|
terminal.enterPrivateMode()
|
||||||
|
terminal.clearScreen()
|
||||||
|
terminal.setCursorVisible(false)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
terminal = SwingTerminalFrame("Mirai Console")
|
||||||
|
terminal.enterPrivateMode()
|
||||||
|
terminal.clearScreen()
|
||||||
|
terminal.setCursorVisible(false)
|
||||||
|
}
|
||||||
|
if (terminal == null) {
|
||||||
|
error("can not create terminal")
|
||||||
|
}
|
||||||
|
|
||||||
|
val textGraphics: TextGraphics = terminal.newTextGraphics()
|
||||||
|
|
||||||
|
try {
|
||||||
|
fun getLeftScreenId(): Int {
|
||||||
|
var newId = currentScreenId - 1
|
||||||
|
if (newId < 0) {
|
||||||
|
newId = screens.size - 1
|
||||||
|
}
|
||||||
|
return newId
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getRightScreenId(): Int {
|
||||||
|
var newId = 1 + currentScreenId
|
||||||
|
if (newId >= screens.size) {
|
||||||
|
newId = 0
|
||||||
|
}
|
||||||
|
return newId
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getScreenName(id: Int): String {
|
||||||
|
return when (screens[id]) {
|
||||||
|
0L -> {
|
||||||
|
"Console Screen"
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
"Bot: ${screens[id]}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var inited = false
|
||||||
|
fun clearRows(row: Int) {
|
||||||
|
textGraphics.putString(0, row, " ".repeat(terminal.terminalSize.columns))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun drawFrame(
|
||||||
|
title: String
|
||||||
|
) {
|
||||||
|
val width = terminal.terminalSize.columns
|
||||||
|
val height = terminal.terminalSize.rows
|
||||||
|
terminal.setBackgroundColor(TextColor.ANSI.DEFAULT)
|
||||||
|
if (!inited) {
|
||||||
|
val mainTitle = "Mirai Console v0.01 Core v0.14"
|
||||||
|
textGraphics.foregroundColor = TextColor.ANSI.WHITE
|
||||||
|
textGraphics.backgroundColor = TextColor.ANSI.GREEN
|
||||||
|
textGraphics.putString((width - mainTitle.length) / 2, 1, mainTitle, SGR.BOLD)
|
||||||
|
textGraphics.foregroundColor = TextColor.ANSI.DEFAULT
|
||||||
|
textGraphics.backgroundColor = TextColor.ANSI.DEFAULT
|
||||||
|
textGraphics.putString(2, 3, "-".repeat(width - 4))
|
||||||
|
textGraphics.putString(2, 5, "-".repeat(width - 4))
|
||||||
|
textGraphics.putString(2, height - 4, "-".repeat(width - 4))
|
||||||
|
textGraphics.putString(2, height - 3, "|>>>")
|
||||||
|
textGraphics.putString(width - 3, height - 3, "|")
|
||||||
|
textGraphics.putString(2, height - 2, "-".repeat(width - 4))
|
||||||
|
inited = true
|
||||||
|
}
|
||||||
|
textGraphics.foregroundColor = TextColor.ANSI.DEFAULT
|
||||||
|
textGraphics.backgroundColor = TextColor.ANSI.DEFAULT
|
||||||
|
val leftName = getScreenName(getLeftScreenId())
|
||||||
|
clearRows(2)
|
||||||
|
textGraphics.putString((width - title.length) / 2 - "$leftName << ".length, 2, "$leftName << ")
|
||||||
|
textGraphics.foregroundColor = TextColor.ANSI.WHITE
|
||||||
|
textGraphics.backgroundColor = TextColor.ANSI.YELLOW
|
||||||
|
textGraphics.putString((width - title.length) / 2, 2, title, SGR.BOLD)
|
||||||
|
textGraphics.foregroundColor = TextColor.ANSI.DEFAULT
|
||||||
|
textGraphics.backgroundColor = TextColor.ANSI.DEFAULT
|
||||||
|
val rightName = getScreenName(getRightScreenId())
|
||||||
|
textGraphics.putString((width + title.length) / 2 + 1, 2, ">> $rightName")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun drawMainFrame(
|
||||||
|
onlineBotCount: Number
|
||||||
|
) {
|
||||||
|
drawFrame("Console Screen")
|
||||||
|
val width = terminal.terminalSize.columns
|
||||||
|
textGraphics.foregroundColor = TextColor.ANSI.DEFAULT
|
||||||
|
textGraphics.backgroundColor = TextColor.ANSI.DEFAULT
|
||||||
|
clearRows(4)
|
||||||
|
textGraphics.putString(2, 4, "|Online Bots: $onlineBotCount")
|
||||||
|
textGraphics.putString(
|
||||||
|
width - 2 - "Powered By Mamoe Technologies|".length,
|
||||||
|
4,
|
||||||
|
"Powered By Mamoe Technologies|"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun drawBotFrame(
|
||||||
|
qq: Long,
|
||||||
|
adminCount: Number
|
||||||
|
) {
|
||||||
|
drawFrame("Bot: $qq")
|
||||||
|
val width = terminal.terminalSize.columns
|
||||||
|
textGraphics.foregroundColor = TextColor.ANSI.DEFAULT
|
||||||
|
textGraphics.backgroundColor = TextColor.ANSI.DEFAULT
|
||||||
|
clearRows(4)
|
||||||
|
textGraphics.putString(2, 4, "|Admins: $adminCount")
|
||||||
|
textGraphics.putString(width - 2 - "Add admins via commands|".length, 4, "Add admins via commands|")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun drawLogs(values: List<String>) {
|
||||||
|
val width = terminal.terminalSize.columns - 6
|
||||||
|
val heightMin = 5
|
||||||
|
|
||||||
|
var currentHeight = terminal.terminalSize.rows - 5
|
||||||
|
|
||||||
|
for (index in heightMin until currentHeight) {
|
||||||
|
clearRows(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
values.forEach {
|
||||||
|
if (currentHeight > heightMin) {
|
||||||
|
var x = it
|
||||||
|
while (currentHeight > heightMin) {
|
||||||
|
if (x.isEmpty() || x.isBlank()) break
|
||||||
|
textGraphics.foregroundColor = TextColor.ANSI.GREEN
|
||||||
|
textGraphics.backgroundColor = TextColor.ANSI.DEFAULT
|
||||||
|
val towrite = if (x.length > width) {
|
||||||
|
x.substring(0, width).also {
|
||||||
|
x = x.substring(width)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
x.also {
|
||||||
|
x = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
textGraphics.putString(3, currentHeight, towrite, SGR.ITALIC)
|
||||||
|
--currentHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (terminal is SwingTerminalFrame) {
|
||||||
|
terminal.flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var commandBuilder = StringBuilder()
|
||||||
|
|
||||||
|
fun redrawCommand() {
|
||||||
|
val height = terminal.terminalSize.rows
|
||||||
|
val width = terminal.terminalSize.columns
|
||||||
|
clearRows(height - 3)
|
||||||
|
textGraphics.foregroundColor = TextColor.ANSI.DEFAULT
|
||||||
|
textGraphics.putString(2, height - 3, "|>>>")
|
||||||
|
textGraphics.putString(width - 3, height - 3, "|")
|
||||||
|
textGraphics.foregroundColor = TextColor.ANSI.BLUE
|
||||||
|
textGraphics.putString(7, height - 3, commandBuilder.toString())
|
||||||
|
if (terminal is SwingTerminalFrame) {
|
||||||
|
terminal.flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addCommandChar(
|
||||||
|
c: Char
|
||||||
|
) {
|
||||||
|
if (commandBuilder.isEmpty() && c != '/') {
|
||||||
|
addCommandChar('/')
|
||||||
|
}
|
||||||
|
textGraphics.foregroundColor = TextColor.ANSI.BLUE
|
||||||
|
val height = terminal.terminalSize.rows
|
||||||
|
commandBuilder.append(c)
|
||||||
|
if (terminal is SwingTerminalFrame) {
|
||||||
|
redrawCommand()
|
||||||
|
} else {
|
||||||
|
textGraphics.putString(6 + commandBuilder.length, height - 3, c.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteCommandChar() {
|
||||||
|
if (!commandBuilder.isEmpty()) {
|
||||||
|
commandBuilder = StringBuilder(commandBuilder.toString().substring(0, commandBuilder.length - 1))
|
||||||
|
}
|
||||||
|
val height = terminal.terminalSize.rows
|
||||||
|
if (terminal is SwingTerminalFrame) {
|
||||||
|
redrawCommand()
|
||||||
|
} else {
|
||||||
|
textGraphics.putString(7 + commandBuilder.length, height - 3, " ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun emptyCommand() {
|
||||||
|
commandBuilder = StringBuilder()
|
||||||
|
redrawCommand()
|
||||||
|
if (terminal is SwingTerminal) {
|
||||||
|
terminal.flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun update() {
|
||||||
|
when (screens[currentScreenId]) {
|
||||||
|
0L -> {
|
||||||
|
drawMainFrame(screens.size - 1)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
drawBotFrame(screens[currentScreenId], 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
terminal.flush()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
terminal.addResizeListener(TerminalResizeListener { terminal1: Terminal, newSize: TerminalSize ->
|
||||||
|
terminal.clearScreen()
|
||||||
|
inited = false
|
||||||
|
update()
|
||||||
|
redrawCommand()
|
||||||
|
})
|
||||||
|
|
||||||
|
update()
|
||||||
|
|
||||||
|
val charList = listOf(',', '.', '/', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '=', '+', '!', ' ')
|
||||||
|
thread {
|
||||||
|
while (true) {
|
||||||
|
var keyStroke: KeyStroke = terminal.readInput()
|
||||||
|
|
||||||
|
when (keyStroke.keyType) {
|
||||||
|
KeyType.ArrowLeft -> {
|
||||||
|
currentScreenId = getLeftScreenId()
|
||||||
|
update()
|
||||||
|
}
|
||||||
|
KeyType.ArrowRight -> {
|
||||||
|
currentScreenId = getRightScreenId()
|
||||||
|
update()
|
||||||
|
}
|
||||||
|
KeyType.Enter -> {
|
||||||
|
emptyCommand()
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
if (keyStroke.character != null) {
|
||||||
|
if (keyStroke.character.toInt() == 8) {
|
||||||
|
deleteCommandChar()
|
||||||
|
}
|
||||||
|
if (keyStroke.character.isLetterOrDigit() || charList.contains(keyStroke.character)) {
|
||||||
|
addCommandChar(keyStroke.character)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LimitLinkedQueue<T>(
|
||||||
|
val limit: Int = 50
|
||||||
|
) : LinkedList<T>() {
|
||||||
|
override fun push(e: T) {
|
||||||
|
if (size >= limit) {
|
||||||
|
pollLast()
|
||||||
|
}
|
||||||
|
super.push(e)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user