mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-03 02:44:34 -05:00
* [#1575] Support paste * WebView: Implement copy * Localize copy dialog, lint * Implement a custom context menu for copy/paste * Remove click event which causes double events * WebView: Fix input events broken by moved preventDefault We want to fall back to the `input` event for Android bug and paste, but we want to prevent the event for the others, so change the order
This commit is contained in:
@@ -27,7 +27,10 @@ import org.cef.network.CefCookieManager
|
||||
import org.cef.network.CefRequest
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.awt.Component
|
||||
import java.awt.HeadlessException
|
||||
import java.awt.Rectangle
|
||||
import java.awt.Toolkit
|
||||
import java.awt.datatransfer.DataFlavor
|
||||
import java.awt.event.InputEvent
|
||||
import java.awt.event.KeyEvent
|
||||
import java.awt.event.MouseEvent
|
||||
@@ -113,6 +116,12 @@ class KcefWebView {
|
||||
val error: String? = null,
|
||||
) : Event()
|
||||
|
||||
@Serializable
|
||||
@SerialName("copy")
|
||||
private data class CopyEvent(
|
||||
val content: String,
|
||||
) : Event()
|
||||
|
||||
private inner class DisplayHandler : CefDisplayHandlerAdapter() {
|
||||
override fun onConsoleMessage(
|
||||
browser: CefBrowser,
|
||||
@@ -346,6 +355,16 @@ class KcefWebView {
|
||||
modifier: Int,
|
||||
): KeyEvent? {
|
||||
val char = if (msg.key?.length == 1) msg.key[0] else KeyEvent.CHAR_UNDEFINED
|
||||
return keyEvent(char, component, id, modifier, msg.key)
|
||||
}
|
||||
|
||||
private fun keyEvent(
|
||||
char: Char,
|
||||
component: Component,
|
||||
id: Int,
|
||||
modifier: Int,
|
||||
strKey: String? = null,
|
||||
): KeyEvent? {
|
||||
val code =
|
||||
when (char.uppercaseChar()) {
|
||||
in 'A'..'Z', in '0'..'9' -> char.uppercaseChar().code
|
||||
@@ -379,7 +398,7 @@ class KcefWebView {
|
||||
' ' -> KeyEvent.VK_SPACE
|
||||
'_' -> KeyEvent.VK_UNDERSCORE
|
||||
else ->
|
||||
when (msg.key) {
|
||||
when (strKey) {
|
||||
"Alt" -> KeyEvent.VK_ALT
|
||||
"Backspace" -> KeyEvent.VK_BACK_SPACE
|
||||
"Delete" -> KeyEvent.VK_DELETE
|
||||
@@ -560,6 +579,39 @@ class KcefWebView {
|
||||
}
|
||||
}
|
||||
|
||||
fun paste(msg: String) {
|
||||
val component = browser?.uiComponent ?: return
|
||||
for (c in msg) {
|
||||
browser!!.sendKeyEvent(keyEvent(c, component, KeyEvent.KEY_PRESSED, 0)!!)
|
||||
keyEvent(c, component, KeyEvent.KEY_TYPED, 0)?.let { browser!!.sendKeyEvent(it) }
|
||||
browser!!.sendKeyEvent(keyEvent(c, component, KeyEvent.KEY_RELEASED, 0)!!)
|
||||
}
|
||||
}
|
||||
|
||||
fun copy() {
|
||||
val frame = browser?.focusedFrame ?: return
|
||||
frame.copy()
|
||||
val clip =
|
||||
try {
|
||||
Toolkit.getDefaultToolkit().getSystemClipboard()
|
||||
} catch (e: HeadlessException) {
|
||||
logger.warn(e) { "Failed to get clipboard" }
|
||||
return
|
||||
}
|
||||
val text =
|
||||
try {
|
||||
clip.getData(DataFlavor.stringFlavor) as String
|
||||
} catch (e: Exception) {
|
||||
logger.warn(e) { "Failed to get clipboard contents" }
|
||||
return
|
||||
}
|
||||
WebView.notifyAllClients(
|
||||
Json.encodeToString<Event>(
|
||||
CopyEvent(text),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun canGoBack(): Boolean = browser!!.canGoBack()
|
||||
|
||||
fun goBack() {
|
||||
|
||||
@@ -79,6 +79,16 @@ object WebView : Websocket<String>() {
|
||||
val deltaY: Float? = null,
|
||||
) : TypeObject()
|
||||
|
||||
@Serializable
|
||||
@SerialName("paste")
|
||||
data class JsPasteMessage(
|
||||
val data: String,
|
||||
) : TypeObject()
|
||||
|
||||
@Serializable
|
||||
@SerialName("copy")
|
||||
class JsCopyMessage : TypeObject()
|
||||
|
||||
override fun handleRequest(ctx: WsMessageContext) {
|
||||
val dr = driver ?: return
|
||||
try {
|
||||
@@ -97,6 +107,12 @@ object WebView : Websocket<String>() {
|
||||
is JsEventMessage -> {
|
||||
dr.event(event)
|
||||
}
|
||||
is JsPasteMessage -> {
|
||||
dr.paste(event.data)
|
||||
}
|
||||
is JsCopyMessage -> {
|
||||
dr.copy()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logger.warn(e) { "Failed to deserialize client request: ${ctx.message()}" }
|
||||
|
||||
Reference in New Issue
Block a user