Unverified Commit f49e7468 authored by Shagen Ogandzhanian's avatar Shagen Ogandzhanian Committed by GitHub

Remove js/wasm events handling from skiko (almost) completely (#864)

This is first part of achieving goal of COMPOSE-891
parent 21d7a12b
package org.jetbrains.skiko
import org.w3c.dom.TouchEvent
import org.w3c.dom.asList
import org.w3c.dom.events.KeyboardEvent
import org.w3c.dom.events.MouseEvent
import org.w3c.dom.events.WheelEvent
internal fun toSkikoEvent(
event: MouseEvent,
kind: SkikoPointerEventKind
): SkikoPointerEvent {
return SkikoPointerEvent(
x = event.offsetX,
y = event.offsetY,
pressedButtons = toSkikoPressedMouseButtons(event, kind),
button = toSkikoMouseButton(event),
modifiers = toSkikoModifiers(event),
kind = kind,
timestamp = getEventTimestamp(event),
platform = event
)
}
internal fun toSkikoDragEvent(
event: MouseEvent
): SkikoPointerEvent {
return SkikoPointerEvent(
x = event.offsetX,
y = event.offsetY,
pressedButtons = SkikoMouseButtons(buttonsFlags),
button = toSkikoMouseButton(event),
modifiers = toSkikoModifiers(event),
kind = SkikoPointerEventKind.DRAG,
timestamp = getEventTimestamp(event),
platform = event
)
}
internal fun toSkikoEvent(
event: TouchEvent,
kind: SkikoPointerEventKind,
offsetX: Double,
offsetY: Double
): SkikoPointerEvent {
val touches = event.changedTouches.asList()
val pointers = touches.map { touch ->
val x = touch.clientX.toDouble() - offsetX
val y = touch.clientY.toDouble() - offsetY
val force = touch.asDynamic().force as Double
SkikoPointer(
x = x,
y = y,
pressed = kind in listOf(SkikoPointerEventKind.DOWN, SkikoPointerEventKind.MOVE),
device = SkikoPointerDevice.TOUCH,
id = touch.identifier.toLong(),
pressure = force
)
}
return SkikoPointerEvent(
x = pointers.centroidX,
y = pointers.centroidY,
kind = kind,
timestamp = (currentNanoTime() / 1E6).toLong(),
pointers = pointers,
platform = event
)
}
internal fun toSkikoTypeEvent(
character: String,
event: KeyboardEvent?,
): SkikoInputEvent? {
return if (SPECIAL_KEYS.contains(character)) {
null
} else {
val input = when (character) {
"Enter" -> "\n"
"Tab" -> "\t"
else -> character
}
val key = if (event != null) SkikoKey.valueOf(event.keyCode) else SkikoKey.KEY_UNKNOWN
val modifiers = if (event != null) toSkikoModifiers(event) else SkikoInputModifiers.EMPTY
SkikoInputEvent(
input,
key,
modifiers,
SkikoKeyboardEventKind.TYPE,
event
)
}
}
internal fun toSkikoEvent(
event: KeyboardEvent,
kind: SkikoKeyboardEventKind
): SkikoKeyboardEvent {
return SkikoKeyboardEvent(
SkikoKey.valueOf(toSkikoKey(event)),
toSkikoModifiers(event),
kind,
getEventTimestamp(event),
event
)
}
internal fun toSkikoScrollEvent(
event: WheelEvent,
): SkikoPointerEvent {
return SkikoPointerEvent(
x = event.offsetX,
y = event.offsetY,
deltaX = event.deltaX,
deltaY = event.deltaY,
pressedButtons = SkikoMouseButtons(buttonsFlags),
button = SkikoMouseButtons.NONE,
modifiers = toSkikoModifiers(event),
kind = SkikoPointerEventKind.SCROLL,
timestamp = getEventTimestamp(event),
platform = event
)
}
private var buttonsFlags = 0
private fun toSkikoPressedMouseButtons(
event: MouseEvent,
kind: SkikoPointerEventKind
): SkikoMouseButtons {
// https://www.w3schools.com/jsref/event_button.asp
val button = event.button.toInt()
if (kind == SkikoPointerEventKind.DOWN) {
buttonsFlags = buttonsFlags.or(getSkikoButtonValue(button))
return SkikoMouseButtons(buttonsFlags)
}
buttonsFlags = buttonsFlags.xor(getSkikoButtonValue(button))
return SkikoMouseButtons(buttonsFlags)
}
private fun toSkikoMouseButton(event: MouseEvent): SkikoMouseButtons {
return SkikoMouseButtons(getSkikoButtonValue(event.button.toInt()))
}
private fun getSkikoButtonValue(button: Int): Int {
return when (button) {
0 -> SkikoMouseButtons.LEFT.value
1 -> SkikoMouseButtons.MIDDLE.value
2 -> SkikoMouseButtons.RIGHT.value
3 -> SkikoMouseButtons.BUTTON_4.value
4 -> SkikoMouseButtons.BUTTON_5.value
else -> 0
}
}
private fun toSkikoModifiers(event: MouseEvent): SkikoInputModifiers {
var result = 0
if (event.altKey) {
result = result.or(SkikoInputModifiers.ALT.value)
}
if (event.shiftKey) {
result = result.or(SkikoInputModifiers.SHIFT.value)
}
if (event.ctrlKey) {
result = result.or(SkikoInputModifiers.CONTROL.value)
}
if (event.metaKey) {
result = result.or(SkikoInputModifiers.META.value)
}
return SkikoInputModifiers(result)
}
private fun toSkikoModifiers(event: KeyboardEvent): SkikoInputModifiers {
var result = 0
if (event.altKey) {
result = result.or(SkikoInputModifiers.ALT.value)
}
if (event.shiftKey) {
result = result.or(SkikoInputModifiers.SHIFT.value)
}
if (event.ctrlKey) {
result = result.or(SkikoInputModifiers.CONTROL.value)
}
if (event.metaKey) {
result = result.or(SkikoInputModifiers.META.value)
}
return SkikoInputModifiers(result)
}
private fun toSkikoKey(event: KeyboardEvent): Int {
var key = event.keyCode
val side = event.location
if (side == KeyboardEvent.DOM_KEY_LOCATION_RIGHT) {
if (
key == SkikoKey.KEY_LEFT_CONTROL.platformKeyCode ||
key == SkikoKey.KEY_LEFT_SHIFT.platformKeyCode ||
key == SkikoKey.KEY_LEFT_META.platformKeyCode
)
key = key.or(0x80000000.toInt())
}
return key
}
\ No newline at end of file
package org.jetbrains.skiko package org.jetbrains.skiko
import kotlinx.browser.window import kotlinx.browser.window
import org.jetbrains.skiko.w3c.HTMLCanvasElement
import org.w3c.dom.TouchEvent
import org.w3c.dom.events.KeyboardEvent import org.w3c.dom.events.KeyboardEvent
import org.w3c.dom.events.MouseEvent
import org.w3c.dom.events.WheelEvent
import org.w3c.dom.events.UIEvent import org.w3c.dom.events.UIEvent
internal actual fun SkiaLayer.bindCanvasEventsToSkikoView(
canvas: HTMLCanvasElement
) {
val htmlCanvas = canvas.unsafeCast<org.w3c.dom.HTMLCanvasElement>()
var offsetX = 0.0
var offsetY = 0.0
htmlCanvas.addEventListener("touchstart", { event ->
event.preventDefault()
event as TouchEvent
htmlCanvas.getBoundingClientRect().apply {
offsetX = left
offsetY = top
}
skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.DOWN, offsetX, offsetY))
})
htmlCanvas.addEventListener("touchmove", { event ->
event.preventDefault()
event as TouchEvent
skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.MOVE, offsetX, offsetY))
})
htmlCanvas.addEventListener("touchend", { event ->
event.preventDefault()
event as TouchEvent
skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.UP, offsetX, offsetY))
})
htmlCanvas.addEventListener("touchcancel", { event ->
event.preventDefault()
event as TouchEvent
skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.UP, offsetX, offsetY))
})
htmlCanvas.addEventListener("mousedown", { event ->
event as MouseEvent
isPointerPressed = true
skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.DOWN))
})
htmlCanvas.addEventListener("mouseup", { event ->
event as MouseEvent
isPointerPressed = false
skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.UP))
})
htmlCanvas.addEventListener("mousemove", { event ->
event as MouseEvent
if (isPointerPressed) {
skikoView?.onPointerEvent(toSkikoDragEvent(event))
} else {
skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.MOVE))
}
})
htmlCanvas.addEventListener("wheel", { event ->
event as WheelEvent
skikoView?.onPointerEvent(toSkikoScrollEvent(event))
})
htmlCanvas.addEventListener("contextmenu", { event ->
event.preventDefault()
})
htmlCanvas.addEventListener("keydown", { event ->
event as KeyboardEvent
skikoView?.onKeyboardEvent(toSkikoEvent(event, SkikoKeyboardEventKind.DOWN))
toSkikoTypeEvent(event.key, event)?.let { inputEvent ->
skikoView?.input?.onInputEvent(inputEvent)
}
})
htmlCanvas.addEventListener("keyup", { event ->
event as KeyboardEvent
skikoView?.onKeyboardEvent(toSkikoEvent(event, SkikoKeyboardEventKind.UP))
})
}
actual typealias SkikoGesturePlatformEvent = Any actual typealias SkikoGesturePlatformEvent = Any
actual typealias SkikoPlatformInputEvent = KeyboardEvent actual typealias SkikoPlatformInputEvent = KeyboardEvent
actual typealias SkikoPlatformKeyboardEvent = KeyboardEvent actual typealias SkikoPlatformKeyboardEvent = KeyboardEvent
......
...@@ -101,7 +101,6 @@ actual open class SkiaLayer { ...@@ -101,7 +101,6 @@ actual open class SkiaLayer {
}.apply { initCanvas(desiredWidth, desiredHeight, contentScale, pixelGeometry) } }.apply { initCanvas(desiredWidth, desiredHeight, contentScale, pixelGeometry) }
// See https://www.w3schools.com/jsref/dom_obj_event.asp // See https://www.w3schools.com/jsref/dom_obj_event.asp
// https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events // https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events
bindCanvasEventsToSkikoView(htmlCanvas)
} }
internal actual fun draw(canvas: Canvas) { internal actual fun draw(canvas: Canvas) {
...@@ -115,5 +114,4 @@ actual open class SkiaLayer { ...@@ -115,5 +114,4 @@ actual open class SkiaLayer {
} }
internal expect fun SkiaLayer.bindCanvasEventsToSkikoView(canvas: HTMLCanvasElement)
internal expect fun SkiaLayer.setOnChangeScaleNotifier() internal expect fun SkiaLayer.setOnChangeScaleNotifier()
package org.jetbrains.skiko
import org.w3c.dom.TouchEvent
import org.w3c.dom.asList
import org.w3c.dom.events.KeyboardEvent
import org.w3c.dom.events.MouseEvent
import org.w3c.dom.events.WheelEvent
internal external abstract class ExtendedTouchEvent: TouchEvent {
val force: Double
}
internal fun toSkikoEvent(
event: TouchEvent,
kind: SkikoPointerEventKind,
offsetX: Double,
offsetY: Double
): SkikoPointerEvent {
val touches = event.changedTouches.asList()
val pointers = touches.map { touch ->
val x = touch.clientX.toDouble() - offsetX
val y = touch.clientY.toDouble() - offsetY
val force = touch.unsafeCast<ExtendedTouchEvent>().force
SkikoPointer(
x = x,
y = y,
pressed = kind in listOf(SkikoPointerEventKind.DOWN, SkikoPointerEventKind.MOVE),
device = SkikoPointerDevice.TOUCH,
id = touch.identifier.toLong(),
pressure = force
)
}
return SkikoPointerEvent(
x = pointers.centroidX,
y = pointers.centroidY,
kind = kind,
timestamp = (currentNanoTime() / 1E6).toLong(),
pointers = pointers,
platform = event
)
}
internal fun toSkikoEvent(
event: MouseEvent,
kind: SkikoPointerEventKind
): SkikoPointerEvent {
return SkikoPointerEvent(
x = event.offsetX,
y = event.offsetY,
pressedButtons = toSkikoPressedMouseButtons(event, kind),
button = toSkikoMouseButton(event),
modifiers = toSkikoModifiers(event),
kind = kind,
timestamp = getEventTimestamp(event),
platform = event
)
}
internal fun toSkikoDragEvent(
event: MouseEvent
): SkikoPointerEvent {
return SkikoPointerEvent(
x = event.offsetX,
y = event.offsetY,
pressedButtons = SkikoMouseButtons(buttonsFlags),
button = toSkikoMouseButton(event),
modifiers = toSkikoModifiers(event),
kind = SkikoPointerEventKind.DRAG,
timestamp = getEventTimestamp(event),
platform = event
)
}
internal fun toSkikoTypeEvent(
character: String,
event: KeyboardEvent?,
): SkikoInputEvent? {
return if (SPECIAL_KEYS.contains(character)) {
null
} else {
val input = when (character) {
"Enter" -> "\n"
"Tab" -> "\t"
else -> character
}
val key = if (event != null) SkikoKey.valueOf(event.keyCode) else SkikoKey.KEY_UNKNOWN
val modifiers = if (event != null) toSkikoModifiers(event) else SkikoInputModifiers.EMPTY
SkikoInputEvent(
input,
key,
modifiers,
SkikoKeyboardEventKind.TYPE,
event
)
}
}
internal fun toSkikoEvent(
event: KeyboardEvent,
kind: SkikoKeyboardEventKind
): SkikoKeyboardEvent {
return SkikoKeyboardEvent(
SkikoKey.valueOf(toSkikoKey(event)),
toSkikoModifiers(event),
kind,
getEventTimestamp(event),
event
)
}
internal fun toSkikoScrollEvent(
event: WheelEvent,
): SkikoPointerEvent {
return SkikoPointerEvent(
x = event.offsetX,
y = event.offsetY,
deltaX = event.deltaX,
deltaY = event.deltaY,
pressedButtons = SkikoMouseButtons(buttonsFlags),
button = SkikoMouseButtons.NONE,
modifiers = toSkikoModifiers(event),
kind = SkikoPointerEventKind.SCROLL,
timestamp = getEventTimestamp(event),
platform = event
)
}
private var buttonsFlags = 0
private fun toSkikoPressedMouseButtons(
event: MouseEvent,
kind: SkikoPointerEventKind
): SkikoMouseButtons {
// https://www.w3schools.com/jsref/event_button.asp
val button = event.button.toInt()
if (kind == SkikoPointerEventKind.DOWN) {
buttonsFlags = buttonsFlags.or(getSkikoButtonValue(button))
return SkikoMouseButtons(buttonsFlags)
}
buttonsFlags = buttonsFlags.xor(getSkikoButtonValue(button))
return SkikoMouseButtons(buttonsFlags)
}
private fun toSkikoMouseButton(event: MouseEvent): SkikoMouseButtons {
return SkikoMouseButtons(getSkikoButtonValue(event.button.toInt()))
}
private fun getSkikoButtonValue(button: Int): Int {
return when (button) {
0 -> SkikoMouseButtons.LEFT.value
1 -> SkikoMouseButtons.MIDDLE.value
2 -> SkikoMouseButtons.RIGHT.value
3 -> SkikoMouseButtons.BUTTON_4.value
4 -> SkikoMouseButtons.BUTTON_5.value
else -> 0
}
}
private fun toSkikoModifiers(event: MouseEvent): SkikoInputModifiers {
var result = 0
if (event.altKey) {
result = result.or(SkikoInputModifiers.ALT.value)
}
if (event.shiftKey) {
result = result.or(SkikoInputModifiers.SHIFT.value)
}
if (event.ctrlKey) {
result = result.or(SkikoInputModifiers.CONTROL.value)
}
if (event.metaKey) {
result = result.or(SkikoInputModifiers.META.value)
}
return SkikoInputModifiers(result)
}
private fun toSkikoModifiers(event: KeyboardEvent): SkikoInputModifiers {
var result = 0
if (event.altKey) {
result = result.or(SkikoInputModifiers.ALT.value)
}
if (event.shiftKey) {
result = result.or(SkikoInputModifiers.SHIFT.value)
}
if (event.ctrlKey) {
result = result.or(SkikoInputModifiers.CONTROL.value)
}
if (event.metaKey) {
result = result.or(SkikoInputModifiers.META.value)
}
return SkikoInputModifiers(result)
}
private fun toSkikoKey(event: KeyboardEvent): Int {
var key = event.keyCode
val side = event.location
if (side == KeyboardEvent.DOM_KEY_LOCATION_RIGHT) {
if (
key == SkikoKey.KEY_LEFT_CONTROL.platformKeyCode ||
key == SkikoKey.KEY_LEFT_SHIFT.platformKeyCode ||
key == SkikoKey.KEY_LEFT_META.platformKeyCode
)
key = key.or(0x80000000.toInt())
}
return key
}
\ No newline at end of file
package org.jetbrains.skiko package org.jetbrains.skiko
import kotlinx.browser.window import kotlinx.browser.window
import org.jetbrains.skiko.w3c.HTMLCanvasElement
import org.w3c.dom.TouchEvent
import org.w3c.dom.events.KeyboardEvent import org.w3c.dom.events.KeyboardEvent
import org.w3c.dom.events.MouseEvent
import org.w3c.dom.events.UIEvent import org.w3c.dom.events.UIEvent
import org.w3c.dom.events.WheelEvent
internal actual fun SkiaLayer.bindCanvasEventsToSkikoView(
canvas: HTMLCanvasElement
) {
val htmlCanvas = canvas as org.w3c.dom.HTMLCanvasElement
var offsetX = 0.0
var offsetY = 0.0
htmlCanvas.addEventListener("touchstart", { event ->
event.preventDefault()
event as TouchEvent
htmlCanvas.getBoundingClientRect().apply {
offsetX = left
offsetY = top
}
skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.DOWN, offsetX, offsetY))
})
htmlCanvas.addEventListener("touchmove", { event ->
event.preventDefault()
event as TouchEvent
skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.MOVE, offsetX, offsetY))
})
htmlCanvas.addEventListener("touchend", { event ->
event.preventDefault()
event as TouchEvent
skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.UP, offsetX, offsetY))
})
htmlCanvas.addEventListener("touchcancel", { event ->
event.preventDefault()
event as TouchEvent
skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.UP, offsetX, offsetY))
})
htmlCanvas.addEventListener("mousedown", { event ->
event as MouseEvent
isPointerPressed = true
skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.DOWN))
})
htmlCanvas.addEventListener("mouseup", { event ->
event as MouseEvent
isPointerPressed = false
skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.UP))
})
htmlCanvas.addEventListener("mousemove", { event ->
event as MouseEvent
if (isPointerPressed) {
skikoView?.onPointerEvent(toSkikoDragEvent(event))
} else {
skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.MOVE))
}
})
htmlCanvas.addEventListener("wheel", { event ->
event as WheelEvent
skikoView?.onPointerEvent(toSkikoScrollEvent(event))
})
htmlCanvas.addEventListener("contextmenu", { event ->
event.preventDefault()
})
htmlCanvas.addEventListener("keydown", { event ->
event as KeyboardEvent
skikoView?.onKeyboardEvent(toSkikoEvent(event, SkikoKeyboardEventKind.DOWN))
toSkikoTypeEvent(event.key, event)?.let { inputEvent ->
skikoView?.input?.onInputEvent(inputEvent)
}
})
htmlCanvas.addEventListener("keyup", { event ->
event as KeyboardEvent
skikoView?.onKeyboardEvent(toSkikoEvent(event, SkikoKeyboardEventKind.UP))
})
}
actual typealias SkikoGesturePlatformEvent = Any actual typealias SkikoGesturePlatformEvent = Any
actual typealias SkikoPlatformInputEvent = KeyboardEvent actual typealias SkikoPlatformInputEvent = KeyboardEvent
actual typealias SkikoPlatformKeyboardEvent = KeyboardEvent actual typealias SkikoPlatformKeyboardEvent = KeyboardEvent
// MouseEvent is base class of PointerEvent
actual typealias SkikoPlatformPointerEvent = UIEvent actual typealias SkikoPlatformPointerEvent = UIEvent
internal actual fun SkiaLayer.setOnChangeScaleNotifier() { internal actual fun SkiaLayer.setOnChangeScaleNotifier() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment