Unverified Commit 9bf726fc authored by Roman Sedaikin's avatar Roman Sedaikin Committed by GitHub

SkikoEvents update: Keyboard/Mouse events, Refactoring. (#410)

* SkikoEvents update: Keyboard/Mouse events, Refactoring.
parent 2f400e63
...@@ -26,6 +26,7 @@ class Clocks(private val layer: SkiaLayer): SkikoView { ...@@ -26,6 +26,7 @@ class Clocks(private val layer: SkiaLayer): SkikoView {
override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) { override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
canvas.translate(xOffset.toFloat(), yOffset.toFloat()) canvas.translate(xOffset.toFloat(), yOffset.toFloat())
canvas.scale(scale.toFloat(), scale.toFloat()) canvas.scale(scale.toFloat(), scale.toFloat())
canvas.rotate(rotate.toFloat(), (width / 2).toFloat(), (height / 2).toFloat())
val watchFill = Paint().apply { color = 0xFFFFFFFF.toInt() } val watchFill = Paint().apply { color = 0xFFFFFFFF.toInt() }
val watchStroke = Paint().apply { val watchStroke = Paint().apply {
color = 0xFF000000.toInt() color = 0xFF000000.toInt()
...@@ -40,7 +41,11 @@ class Clocks(private val layer: SkiaLayer): SkikoView { ...@@ -40,7 +41,11 @@ class Clocks(private val layer: SkiaLayer): SkikoView {
val watchFillHover = Paint().apply { color = 0xFFE4FF01.toInt() } val watchFillHover = Paint().apply { color = 0xFFE4FF01.toInt() }
for (x in 0 .. width - 50 step 50) { for (x in 0 .. width - 50 step 50) {
for (y in 20 .. height - 50 step 50) { for (y in 20 .. height - 50 step 50) {
val hover = xpos / scale > x && xpos / scale < x + 50 && ypos / scale > y && ypos / scale < y + 50 val hover =
(xpos - xOffset) / scale > x &&
(xpos - xOffset) / scale < x + 50 &&
(ypos - yOffset) / scale > y &&
(ypos - yOffset) / scale < y + 50
val fill = if (hover) watchFillHover else watchFill val fill = if (hover) watchFillHover else watchFill
val stroke = if (x > width / 2) watchStrokeAA else watchStroke val stroke = if (x > width / 2) watchStrokeAA else watchStroke
canvas.drawOval(Rect.makeXYWH(x + 5f, y + 5f, 40f, 40f), fill) canvas.drawOval(Rect.makeXYWH(x + 5f, y + 5f, 40f, 40f), fill)
...@@ -92,7 +97,9 @@ class Clocks(private val layer: SkiaLayer): SkikoView { ...@@ -92,7 +97,9 @@ class Clocks(private val layer: SkiaLayer): SkikoView {
.popStyle() .popStyle()
.build() .build()
frames.layout(Float.POSITIVE_INFINITY) frames.layout(Float.POSITIVE_INFINITY)
frames.paint(canvas, (xpos / scale).toFloat(), (ypos / scale).toFloat()) frames.paint(canvas, ((xpos - xOffset) / scale).toFloat(), ((ypos - yOffset) / scale).toFloat())
canvas.resetMatrix()
} }
override fun onPointerEvent(event: SkikoPointerEvent) { override fun onPointerEvent(event: SkikoPointerEvent) {
...@@ -102,9 +109,26 @@ class Clocks(private val layer: SkiaLayer): SkikoView { ...@@ -102,9 +109,26 @@ class Clocks(private val layer: SkiaLayer): SkikoView {
xpos = event.x xpos = event.x
ypos = event.y ypos = event.y
} }
SkikoPointerEventKind.DRAG -> {
xOffset += event.x - xpos
yOffset += event.y - ypos
xpos = event.x
ypos = event.y
}
SkikoPointerEventKind.SCROLL -> {
when (event.modifiers) {
SkikoInputModifiers.CONTROL -> {
rotate += if (event.y < 0) -5.0 else 5.0
}
else -> {
if (event.y != 0.0) {
scale *= if (event.y < 0) 0.9 else 1.1
}
}
}
}
else -> {} else -> {}
} }
// TODO: provide example that covers all features of pointer event
} }
override fun onInputEvent(event: SkikoInputEvent) { override fun onInputEvent(event: SkikoInputEvent) {
...@@ -112,8 +136,36 @@ class Clocks(private val layer: SkiaLayer): SkikoView { ...@@ -112,8 +136,36 @@ class Clocks(private val layer: SkiaLayer): SkikoView {
} }
override fun onKeyboardEvent(event: SkikoKeyboardEvent) { override fun onKeyboardEvent(event: SkikoKeyboardEvent) {
println(event.kind) if (event.kind == SkikoKeyboardEventKind.DOWN) {
// TODO: provide example that covers all features of keyboard event when (event.key) {
SkikoKey.KEY_NUMPAD_ADD,
SkikoKey.KEY_I -> scale *= 1.1
SkikoKey.KEY_NUMPAD_SUBTRACT,
SkikoKey.KEY_O -> scale *= 0.9
SkikoKey.KEY_R -> {
if (event.modifiers == SkikoInputModifiers.SHIFT) {
rotate -= 5.0
} else {
rotate += 5.0
}
}
SkikoKey.KEY_NUMPAD_4,
SkikoKey.KEY_LEFT -> xOffset -= 5.0
SkikoKey.KEY_NUMPAD_8,
SkikoKey.KEY_UP -> yOffset -= 5.0
SkikoKey.KEY_NUMPAD_6,
SkikoKey.KEY_RIGHT -> xOffset += 5.0
SkikoKey.KEY_NUMPAD_2,
SkikoKey.KEY_DOWN -> yOffset += 5.0
SkikoKey.KEY_SPACE -> {
xOffset = 0.0
yOffset = 0.0
rotate = 0.0
scale = 1.0
}
else -> {}
}
}
} }
override fun onGestureEvent(event: SkikoGestureEvent) { override fun onGestureEvent(event: SkikoGestureEvent) {
...@@ -134,7 +186,7 @@ class Clocks(private val layer: SkiaLayer): SkikoView { ...@@ -134,7 +186,7 @@ class Clocks(private val layer: SkiaLayer): SkikoView {
yOffset = event.y - ypos yOffset = event.y - ypos
} }
SkikoGestureEventKind.ROTATION -> { SkikoGestureEventKind.ROTATION -> {
rotate = (event.rotation * PI) rotate = event.rotation * 180.0 / PI
} }
else -> {} else -> {}
} }
......
...@@ -9,7 +9,7 @@ import org.w3c.dom.HTMLCanvasElement ...@@ -9,7 +9,7 @@ import org.w3c.dom.HTMLCanvasElement
fun main() { fun main() {
onWasmReady { onWasmReady {
val skiaLayer = SkiaLayer() val skiaLayer = SkiaLayer()
val game = BouncingBalls() val game = Clocks(skiaLayer)
skiaLayer.skikoView = GenericSkikoView(skiaLayer, game) skiaLayer.skikoView = GenericSkikoView(skiaLayer, game)
val canvas = document.getElementById("SkikoTarget") as HTMLCanvasElement val canvas = document.getElementById("SkikoTarget") as HTMLCanvasElement
canvas.setAttribute("tabindex", "0") canvas.setAttribute("tabindex", "0")
......
...@@ -6,12 +6,25 @@ import org.jetbrains.skia.* ...@@ -6,12 +6,25 @@ import org.jetbrains.skia.*
import org.jetbrains.skiko.* import org.jetbrains.skiko.*
import kotlinx.cinterop.* import kotlinx.cinterop.*
import platform.Foundation.NSMakeRect import platform.Foundation.NSMakeRect
import platform.Foundation.NSBundle
import platform.Foundation.NSNotification
import platform.Foundation.NSSelectorFromString
import platform.darwin.NSObject import platform.darwin.NSObject
fun makeApp(skiaLayer: SkiaLayer) = Clocks(skiaLayer) fun makeApp(skiaLayer: SkiaLayer) = Clocks(skiaLayer)
fun main() { fun main() {
val app = NSApplication.sharedApplication() val app = NSApplication.sharedApplication()
app.setActivationPolicy(NSApplicationActivationPolicy.NSApplicationActivationPolicyRegular)
val appName = "SkikoNative"
var bar = NSMenu()
app.setMainMenu(bar)
var appMenuItem = bar.addItemWithTitle(appName, null, "");
var appMenu = NSMenu()
appMenuItem.setSubmenu(appMenu)
appMenu.addItemWithTitle("About $appName", NSSelectorFromString("orderFrontStandardAboutPanel:"), "a")
appMenu.addItemWithTitle("Quit $appName", NSSelectorFromString("terminate:"), "q")
app.delegate = object: NSObject(), NSApplicationDelegateProtocol { app.delegate = object: NSObject(), NSApplicationDelegateProtocol {
override fun applicationShouldTerminateAfterLastWindowClosed(sender: NSApplication): Boolean { override fun applicationShouldTerminateAfterLastWindowClosed(sender: NSApplication): Boolean {
return true return true
...@@ -21,14 +34,19 @@ fun main() { ...@@ -21,14 +34,19 @@ fun main() {
NSWindowStyleMaskMiniaturizable or NSWindowStyleMaskMiniaturizable or
NSWindowStyleMaskClosable or NSWindowStyleMaskClosable or
NSWindowStyleMaskResizable NSWindowStyleMaskResizable
val window = NSWindow( val window = object: NSWindow(
contentRect = NSMakeRect(0.0, 0.0, 640.0, 480.0), contentRect = NSMakeRect(0.0, 0.0, 640.0, 480.0),
styleMask = windowStyle, styleMask = windowStyle,
backing = NSBackingStoreBuffered, backing = NSBackingStoreBuffered,
defer = true) defer = false
) {
override fun canBecomeKeyWindow(): Boolean {
return true
}
}
val skiaLayer = SkiaLayer() val skiaLayer = SkiaLayer()
skiaLayer.skikoView = GenericSkikoView(skiaLayer, makeApp(skiaLayer)) skiaLayer.skikoView = GenericSkikoView(skiaLayer, makeApp(skiaLayer))
skiaLayer.attachTo(window) skiaLayer.attachTo(window)
window.orderFrontRegardless() window.makeKeyAndOrderFront(app)
app.run() app.run()
} }
...@@ -1218,6 +1218,10 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int ...@@ -1218,6 +1218,10 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int
return concat(Matrix33.makeRotate(deg)) return concat(Matrix33.makeRotate(deg))
} }
fun rotate(deg: Float, x: Float, y: Float): Canvas {
return concat(Matrix33.makeRotate(deg, x, y))
}
fun skew(sx: Float, sy: Float): Canvas { fun skew(sx: Float, sy: Float): Canvas {
return concat(Matrix33.makeSkew(sx, sy)) return concat(Matrix33.makeSkew(sx, sy))
} }
......
...@@ -90,6 +90,113 @@ inline class SkikoInputModifiers(val value: Int) { ...@@ -90,6 +90,113 @@ inline class SkikoInputModifiers(val value: Int) {
} }
} }
expect enum class SkikoKey {
KEY_UNKNOWN,
KEY_A,
KEY_S,
KEY_D,
KEY_F,
KEY_H,
KEY_G,
KEY_Z,
KEY_X,
KEY_C,
KEY_V,
KEY_B,
KEY_Q,
KEY_W,
KEY_E,
KEY_R,
KEY_Y,
KEY_T,
KEY_U,
KEY_I,
KEY_P,
KEY_L,
KEY_J,
KEY_K,
KEY_N,
KEY_M,
KEY_O,
KEY_1,
KEY_2,
KEY_3,
KEY_4,
KEY_5,
KEY_6,
KEY_7,
KEY_8,
KEY_9,
KEY_0,
KEY_CLOSE_BRACKET,
KEY_OPEN_BRACKET,
KEY_QUOTE,
KEY_SEMICOLON,
KEY_SLASH,
KEY_COMMA,
KEY_BACKSLASH,
KEY_PERIOD,
KEY_BACK_QUOTE,
KEY_EQUALS,
KEY_MINUS,
KEY_ENTER,
KEY_ESCAPE,
KEY_TAB,
KEY_BACKSPACE,
KEY_SPACE,
KEY_CAPSLOCK,
KEY_LEFT_META,
KEY_LEFT_SHIFT,
KEY_LEFT_ALT,
KEY_LEFT_CONTROL,
KEY_RIGHT_META,
KEY_RIGHT_SHIFT,
KEY_RIGHT_ALT,
KEY_RIGHT_CONTROL,
KEY_UP,
KEY_DOWN,
KEY_LEFT,
KEY_RIGHT,
KEY_F1,
KEY_F2,
KEY_F3,
KEY_F4,
KEY_F5,
KEY_F6,
KEY_F7,
KEY_F8,
KEY_F9,
KEY_F10,
KEY_F11,
KEY_F12,
KEY_PRINTSCEEN,
KEY_SCROLL_LOCK,
KEY_PAUSE,
KEY_INSERT,
KEY_HOME,
KEY_PGUP,
KEY_DELETE,
KEY_END,
KEY_PGDOWN,
KEY_NUM_LOCK,
KEY_NUMPAD_0,
KEY_NUMPAD_1,
KEY_NUMPAD_2,
KEY_NUMPAD_3,
KEY_NUMPAD_4,
KEY_NUMPAD_5,
KEY_NUMPAD_6,
KEY_NUMPAD_7,
KEY_NUMPAD_8,
KEY_NUMPAD_9,
KEY_NUMPAD_ENTER,
KEY_NUMPAD_ADD,
KEY_NUMPAD_SUBTRACT,
KEY_NUMPAD_MULTIPLY,
KEY_NUMPAD_DIVIDE,
KEY_NUMPAD_DECIMAC;
}
enum class SkikoGestureEventKind { enum class SkikoGestureEventKind {
PRESS, TAP, PAN, PINCH, ROTATION, LONGPRESS, SWIPE, UNKNOWN PRESS, TAP, PAN, PINCH, ROTATION, LONGPRESS, SWIPE, UNKNOWN
} }
...@@ -122,7 +229,7 @@ enum class SkikoKeyboardEventKind { ...@@ -122,7 +229,7 @@ enum class SkikoKeyboardEventKind {
} }
expect class SkikoPlatformKeyboardEvent expect class SkikoPlatformKeyboardEvent
data class SkikoKeyboardEvent( data class SkikoKeyboardEvent(
val code: Int, val key: SkikoKey,
val modifiers: SkikoInputModifiers = SkikoInputModifiers.EMPTY, val modifiers: SkikoInputModifiers = SkikoInputModifiers.EMPTY,
val kind: SkikoKeyboardEventKind, val kind: SkikoKeyboardEventKind,
val platform: SkikoPlatformKeyboardEvent? val platform: SkikoPlatformKeyboardEvent?
...@@ -131,6 +238,7 @@ data class SkikoKeyboardEvent( ...@@ -131,6 +238,7 @@ data class SkikoKeyboardEvent(
enum class SkikoPointerEventKind { enum class SkikoPointerEventKind {
UP, DOWN, MOVE, DRAG, SCROLL, ENTER, EXIT, UNKNOWN UP, DOWN, MOVE, DRAG, SCROLL, ENTER, EXIT, UNKNOWN
} }
expect class SkikoPlatformPointerEvent expect class SkikoPlatformPointerEvent
data class SkikoPointerEvent( data class SkikoPointerEvent(
val x: Double, val y: Double, val x: Double, val y: Double,
......
...@@ -189,3 +189,117 @@ actual typealias SkikoGesturePlatformEvent = UIEvent ...@@ -189,3 +189,117 @@ actual typealias SkikoGesturePlatformEvent = UIEvent
actual typealias SkikoPlatformInputEvent = UIEvent actual typealias SkikoPlatformInputEvent = UIEvent
actual typealias SkikoPlatformKeyboardEvent = UIEvent actual typealias SkikoPlatformKeyboardEvent = UIEvent
actual typealias SkikoPlatformPointerEvent = UIEvent actual typealias SkikoPlatformPointerEvent = UIEvent
actual enum class SkikoKey(val value: Int) {
KEY_UNKNOWN(-1),
KEY_A(0),
KEY_S(1),
KEY_D(2),
KEY_F(3),
KEY_H(4),
KEY_G(5),
KEY_Z(6),
KEY_X(7),
KEY_C(8),
KEY_V(9),
KEY_B(11),
KEY_Q(12),
KEY_W(13),
KEY_E(14),
KEY_R(15),
KEY_Y(16),
KEY_T(17),
KEY_U(32),
KEY_I(34),
KEY_P(35),
KEY_L(37),
KEY_J(38),
KEY_K(40),
KEY_N(45),
KEY_M(46),
KEY_O(31),
KEY_1(18),
KEY_2(19),
KEY_3(20),
KEY_4(21),
KEY_5(23),
KEY_6(22),
KEY_7(26),
KEY_8(28),
KEY_9(25),
KEY_0(29),
KEY_CLOSE_BRACKET(30),
KEY_OPEN_BRACKET(33),
KEY_QUOTE(39),
KEY_SEMICOLON(41),
KEY_SLASH(42),
KEY_COMMA(43),
KEY_BACKSLASH(44),
KEY_PERIOD(47),
KEY_BACK_QUOTE(50),
KEY_EQUALS(24),
KEY_MINUS(27),
KEY_ENTER(36),
KEY_ESCAPE(53),
KEY_TAB(48),
KEY_BACKSPACE(51),
KEY_SPACE(49),
KEY_CAPSLOCK(57),
KEY_LEFT_META(55),
KEY_LEFT_SHIFT(56),
KEY_LEFT_ALT(58),
KEY_LEFT_CONTROL(59),
KEY_RIGHT_META(54),
KEY_RIGHT_SHIFT(60),
KEY_RIGHT_ALT(61),
KEY_RIGHT_CONTROL(62),
KEY_UP(126),
KEY_DOWN(125),
KEY_LEFT(123),
KEY_RIGHT(124),
KEY_F1(122),
KEY_F2(120),
KEY_F3(99),
KEY_F4(118),
KEY_F5(96),
KEY_F6(97),
KEY_F7(98),
KEY_F8(100),
KEY_F9(101),
KEY_F10(109),
KEY_F11(103),
KEY_F12(111),
KEY_PRINTSCEEN(105),
KEY_SCROLL_LOCK(107),
KEY_PAUSE(113),
KEY_INSERT(114),
KEY_HOME(115),
KEY_PGUP(116),
KEY_DELETE(117),
KEY_END(119),
KEY_PGDOWN(121),
KEY_NUM_LOCK(71),
KEY_NUMPAD_0(82),
KEY_NUMPAD_1(83),
KEY_NUMPAD_2(84),
KEY_NUMPAD_3(85),
KEY_NUMPAD_4(86),
KEY_NUMPAD_5(87),
KEY_NUMPAD_6(88),
KEY_NUMPAD_7(88),
KEY_NUMPAD_8(91),
KEY_NUMPAD_9(92),
KEY_NUMPAD_ENTER(76),
KEY_NUMPAD_ADD(69),
KEY_NUMPAD_SUBTRACT(78),
KEY_NUMPAD_MULTIPLY(67),
KEY_NUMPAD_DIVIDE(75),
KEY_NUMPAD_DECIMAC(65);
companion object {
fun valueOf(value: Int): SkikoKey {
val key = SkikoKey.values().firstOrNull { it.value == value }
return if (key == null) SkikoKey.KEY_UNKNOWN else key
}
}
}
\ No newline at end of file
...@@ -2,6 +2,7 @@ package org.jetbrains.skiko ...@@ -2,6 +2,7 @@ package org.jetbrains.skiko
import org.w3c.dom.events.MouseEvent import org.w3c.dom.events.MouseEvent
import org.w3c.dom.events.KeyboardEvent import org.w3c.dom.events.KeyboardEvent
import org.w3c.dom.events.WheelEvent
fun toSkikoEvent( fun toSkikoEvent(
event: MouseEvent, event: MouseEvent,
...@@ -18,19 +19,59 @@ fun toSkikoEvent( ...@@ -18,19 +19,59 @@ fun toSkikoEvent(
) )
} }
fun toSkikoDragEvent(
event: MouseEvent
): SkikoPointerEvent {
return SkikoPointerEvent(
event.offsetX,
event.offsetY,
toSkikoMouseButtons(event, true),
toSkikoModifiers(event),
SkikoPointerEventKind.DRAG,
event
)
}
fun toSkikoEvent( fun toSkikoEvent(
event: KeyboardEvent, event: KeyboardEvent,
kind: SkikoKeyboardEventKind kind: SkikoKeyboardEventKind
): SkikoKeyboardEvent { ): SkikoKeyboardEvent {
var key = event.keyCode
val side = event.location
if (side == KeyboardEvent.DOM_KEY_LOCATION_RIGHT) {
if (
key == SkikoKey.KEY_LEFT_CONTROL.value ||
key == SkikoKey.KEY_LEFT_SHIFT.value ||
key == SkikoKey.KEY_LEFT_META.value
)
key = key.or(0x80000000.toInt())
}
return SkikoKeyboardEvent( return SkikoKeyboardEvent(
event.keyCode, SkikoKey.valueOf(key),
toSkikoModifiers(event), toSkikoModifiers(event),
kind, kind,
event event
) )
} }
private fun toSkikoMouseButtons(event: MouseEvent, pressed: Boolean): SkikoMouseButtons { fun toSkikoScrollEvent(
event: WheelEvent,
buttons: Boolean
): SkikoPointerEvent {
return SkikoPointerEvent(
event.deltaX,
event.deltaY,
toSkikoMouseButtons(event, buttons),
toSkikoModifiers(event),
SkikoPointerEventKind.SCROLL,
event
)
}
private fun toSkikoMouseButtons(
event: MouseEvent,
pressed: Boolean
): SkikoMouseButtons {
// https://www.w3schools.com/jsref/event_button.asp // https://www.w3schools.com/jsref/event_button.asp
var result = 0 var result = 0
if (pressed && event.button.toInt() == 0) { if (pressed && event.button.toInt() == 0) {
......
...@@ -5,6 +5,7 @@ import org.w3c.dom.HTMLCanvasElement ...@@ -5,6 +5,7 @@ import org.w3c.dom.HTMLCanvasElement
import org.w3c.dom.events.InputEvent import org.w3c.dom.events.InputEvent
import org.w3c.dom.events.KeyboardEvent import org.w3c.dom.events.KeyboardEvent
import org.w3c.dom.events.MouseEvent import org.w3c.dom.events.MouseEvent
import org.w3c.dom.events.WheelEvent
actual open class SkiaLayer { actual open class SkiaLayer {
private var state: CanvasRenderer? = null private var state: CanvasRenderer? = null
...@@ -37,6 +38,8 @@ actual open class SkiaLayer { ...@@ -37,6 +38,8 @@ actual open class SkiaLayer {
// TODO: when switch to the frame dispatcher - stop it here. // TODO: when switch to the frame dispatcher - stop it here.
} }
private var isPointerPressed = false
fun attachTo(htmlCanvas: HTMLCanvasElement, autoDetach: Boolean = true) { fun attachTo(htmlCanvas: HTMLCanvasElement, autoDetach: Boolean = true) {
state = object: CanvasRenderer(htmlCanvas) { state = object: CanvasRenderer(htmlCanvas) {
override fun drawFrame(currentTimestamp: Double) { override fun drawFrame(currentTimestamp: Double) {
...@@ -49,15 +52,25 @@ actual open class SkiaLayer { ...@@ -49,15 +52,25 @@ actual open class SkiaLayer {
// https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events // https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events
htmlCanvas.addEventListener("pointerdown", { event -> htmlCanvas.addEventListener("pointerdown", { event ->
event as MouseEvent event as MouseEvent
isPointerPressed = true
skikoView?.onPointerEvent(toSkikoEvent(event, true, SkikoPointerEventKind.DOWN)) skikoView?.onPointerEvent(toSkikoEvent(event, true, SkikoPointerEventKind.DOWN))
}) })
htmlCanvas.addEventListener("pointerup", { event -> htmlCanvas.addEventListener("pointerup", { event ->
event as MouseEvent event as MouseEvent
isPointerPressed = false
skikoView?.onPointerEvent(toSkikoEvent(event, true, SkikoPointerEventKind.UP)) skikoView?.onPointerEvent(toSkikoEvent(event, true, SkikoPointerEventKind.UP))
}) })
htmlCanvas.addEventListener("pointermove", { event -> htmlCanvas.addEventListener("pointermove", { event ->
event as MouseEvent event as MouseEvent
if (isPointerPressed) {
skikoView?.onPointerEvent(toSkikoDragEvent(event))
} else {
skikoView?.onPointerEvent(toSkikoEvent(event, false, SkikoPointerEventKind.MOVE)) skikoView?.onPointerEvent(toSkikoEvent(event, false, SkikoPointerEventKind.MOVE))
}
})
htmlCanvas.addEventListener("wheel", { event ->
event as WheelEvent
skikoView?.onPointerEvent(toSkikoScrollEvent(event, isPointerPressed))
}) })
htmlCanvas.addEventListener("contextmenu", { event -> htmlCanvas.addEventListener("contextmenu", { event ->
event.preventDefault() event.preventDefault()
...@@ -72,9 +85,124 @@ actual open class SkiaLayer { ...@@ -72,9 +85,124 @@ actual open class SkiaLayer {
}) })
} }
} }
private var ticking = false
actual typealias SkikoGesturePlatformEvent = Any actual typealias SkikoGesturePlatformEvent = Any
actual typealias SkikoPlatformInputEvent = InputEvent actual typealias SkikoPlatformInputEvent = InputEvent
actual typealias SkikoPlatformKeyboardEvent = KeyboardEvent actual typealias SkikoPlatformKeyboardEvent = KeyboardEvent
// MouseEvent is base class of PointerEvent // MouseEvent is base class of PointerEvent
actual typealias SkikoPlatformPointerEvent = MouseEvent actual typealias SkikoPlatformPointerEvent = MouseEvent
actual enum class SkikoKey(val value: Int) {
KEY_UNKNOWN(-1),
KEY_A(65),
KEY_S(83),
KEY_D(68),
KEY_F(70),
KEY_H(72),
KEY_G(71),
KEY_Z(90),
KEY_X(88),
KEY_C(67),
KEY_V(86),
KEY_B(66),
KEY_Q(81),
KEY_W(87),
KEY_E(69),
KEY_R(82),
KEY_Y(89),
KEY_T(54),
KEY_U(85),
KEY_I(73),
KEY_P(80),
KEY_L(76),
KEY_J(74),
KEY_K(75),
KEY_N(78),
KEY_M(77),
KEY_O(79),
KEY_1(49),
KEY_2(50),
KEY_3(51),
KEY_4(52),
KEY_5(53),
KEY_6(54),
KEY_7(55),
KEY_8(56),
KEY_9(57),
KEY_0(48),
KEY_CLOSE_BRACKET(221),
KEY_OPEN_BRACKET(219),
KEY_QUOTE(222),
KEY_SEMICOLON(59),
KEY_SLASH(191),
KEY_COMMA(188),
KEY_BACKSLASH(220),
KEY_PERIOD(190),
KEY_BACK_QUOTE(192),
KEY_EQUALS(61),
KEY_MINUS(173),
KEY_ENTER(13),
KEY_ESCAPE(27),
KEY_TAB(9),
KEY_BACKSPACE(8),
KEY_SPACE(32),
KEY_CAPSLOCK(20),
KEY_LEFT_META(224),
KEY_LEFT_SHIFT(16),
KEY_LEFT_ALT(18),
KEY_LEFT_CONTROL(17),
KEY_RIGHT_META(0x80000000.toInt() or 224),
KEY_RIGHT_SHIFT(0x80000000.toInt() or 16),
KEY_RIGHT_ALT(225),
KEY_RIGHT_CONTROL(0x80000000.toInt() or 17),
KEY_UP(38),
KEY_DOWN(40),
KEY_LEFT(37),
KEY_RIGHT(39),
KEY_F1(112),
KEY_F2(113),
KEY_F3(114),
KEY_F4(115),
KEY_F5(116),
KEY_F6(117),
KEY_F7(118),
KEY_F8(119),
KEY_F9(120),
KEY_F10(121),
KEY_F11(122),
KEY_F12(123),
KEY_PRINTSCEEN(44),
KEY_SCROLL_LOCK(145),
KEY_PAUSE(19),
KEY_INSERT(45),
KEY_HOME(36),
KEY_PGUP(33),
KEY_DELETE(46),
KEY_END(35),
KEY_PGDOWN(34),
KEY_NUM_LOCK(144),
KEY_NUMPAD_0(96),
KEY_NUMPAD_1(97),
KEY_NUMPAD_2(98),
KEY_NUMPAD_3(99),
KEY_NUMPAD_4(100),
KEY_NUMPAD_5(101),
KEY_NUMPAD_6(102),
KEY_NUMPAD_7(103),
KEY_NUMPAD_8(104),
KEY_NUMPAD_9(105),
KEY_NUMPAD_ENTER(14),
KEY_NUMPAD_ADD(107),
KEY_NUMPAD_SUBTRACT(109),
KEY_NUMPAD_MULTIPLY(106),
KEY_NUMPAD_DIVIDE(111),
KEY_NUMPAD_DECIMAC(110);
companion object {
fun valueOf(value: Int): SkikoKey {
val key = SkikoKey.values().firstOrNull { it.value == value }
return if (key == null) SkikoKey.KEY_UNKNOWN else key
}
}
}
...@@ -12,8 +12,8 @@ import org.jetbrains.skiko.wasm.CreateWebGLContext ...@@ -12,8 +12,8 @@ import org.jetbrains.skiko.wasm.CreateWebGLContext
import org.jetbrains.skiko.wasm.GL import org.jetbrains.skiko.wasm.GL
import org.w3c.dom.HTMLCanvasElement import org.w3c.dom.HTMLCanvasElement
fun Surface.Companion.createFromGL(width: Int, height: Int) = makeFromBackendRenderTarget( fun Surface.Companion.createFromGL(context: DirectContext, width: Int, height: Int) = makeFromBackendRenderTarget(
DirectContext.makeGL(), context,
BackendRenderTarget.makeGL( BackendRenderTarget.makeGL(
width, height, 1, 8, 0, 0x8058 width, height, 1, 8, 0, 0x8058
), ),
...@@ -29,8 +29,8 @@ abstract class CanvasRenderer constructor(htmlCanvas: HTMLCanvasElement, val wid ...@@ -29,8 +29,8 @@ abstract class CanvasRenderer constructor(htmlCanvas: HTMLCanvasElement, val wid
init { init {
GL.makeContextCurrent(contextPointer) GL.makeContextCurrent(contextPointer)
} }
private val context = DirectContext.makeGL()
private val surface = Surface.createFromGL(width, height) private val surface = Surface.createFromGL(context, width, height)
val canvas: Canvas val canvas: Canvas
get() = surface.canvas get() = surface.canvas
...@@ -39,8 +39,10 @@ abstract class CanvasRenderer constructor(htmlCanvas: HTMLCanvasElement, val wid ...@@ -39,8 +39,10 @@ abstract class CanvasRenderer constructor(htmlCanvas: HTMLCanvasElement, val wid
fun draw() { fun draw() {
window.requestAnimationFrame { timestamp -> window.requestAnimationFrame { timestamp ->
GL.makeContextCurrent(contextPointer) GL.makeContextCurrent(contextPointer)
canvas.clear(-1)
drawFrame(timestamp) drawFrame(timestamp)
surface.flushAndSubmit() surface.flushAndSubmit()
context.flush()
} }
} }
} }
\ No newline at end of file
...@@ -10,6 +10,7 @@ import java.awt.Transparency ...@@ -10,6 +10,7 @@ import java.awt.Transparency
import java.awt.color.ColorSpace import java.awt.color.ColorSpace
import java.awt.image.* import java.awt.image.*
import java.awt.event.* import java.awt.event.*
import java.awt.event.KeyEvent.*
import java.nio.ByteBuffer import java.nio.ByteBuffer
private class DirectDataBuffer(val backing: ByteBuffer): DataBuffer(TYPE_BYTE, backing.limit()) { private class DirectDataBuffer(val backing: ByteBuffer): DataBuffer(TYPE_BYTE, backing.limit()) {
...@@ -78,13 +79,13 @@ fun BufferedImage.toImage(): Image { ...@@ -78,13 +79,13 @@ fun BufferedImage.toImage(): Image {
return Image.makeFromBitmap(toBitmap()) return Image.makeFromBitmap(toBitmap())
} }
fun toSkikoEvent(e: MouseEvent): SkikoPointerEvent { fun toSkikoEvent(event: MouseEvent): SkikoPointerEvent {
return SkikoPointerEvent( return SkikoPointerEvent(
e.x.toDouble(), event.x.toDouble(),
e.y.toDouble(), event.y.toDouble(),
toSkikoMouseButtons(e.modifiersEx), toSkikoMouseButtons(event.modifiersEx),
toSkikoModifiers(e.modifiersEx), toSkikoModifiers(event.modifiersEx),
when(e.id) { when(event.id) {
MouseEvent.MOUSE_PRESSED -> SkikoPointerEventKind.DOWN MouseEvent.MOUSE_PRESSED -> SkikoPointerEventKind.DOWN
MouseEvent.MOUSE_RELEASED -> SkikoPointerEventKind.UP MouseEvent.MOUSE_RELEASED -> SkikoPointerEventKind.UP
MouseEvent.MOUSE_DRAGGED -> SkikoPointerEventKind.DRAG MouseEvent.MOUSE_DRAGGED -> SkikoPointerEventKind.DRAG
...@@ -93,42 +94,61 @@ fun toSkikoEvent(e: MouseEvent): SkikoPointerEvent { ...@@ -93,42 +94,61 @@ fun toSkikoEvent(e: MouseEvent): SkikoPointerEvent {
MouseEvent.MOUSE_EXITED -> SkikoPointerEventKind.EXIT MouseEvent.MOUSE_EXITED -> SkikoPointerEventKind.EXIT
else -> SkikoPointerEventKind.UNKNOWN else -> SkikoPointerEventKind.UNKNOWN
}, },
e event
) )
} }
fun toSkikoEvent(e: MouseWheelEvent): SkikoPointerEvent { fun toSkikoEvent(event: MouseWheelEvent): SkikoPointerEvent {
val scrollAmount = event.getPreciseWheelRotation()
val modifiers = toSkikoModifiers(event.modifiersEx)
val isShiftPressed = modifiers.has(SkikoInputModifiers.SHIFT)
val x = if (isShiftPressed) scrollAmount else 0.0
val y = if (isShiftPressed) 0.0 else scrollAmount
return SkikoPointerEvent( return SkikoPointerEvent(
e.x.toDouble(), x,
e.y.toDouble(), y,
toSkikoMouseButtons(e.modifiersEx), toSkikoMouseButtons(event.modifiersEx),
toSkikoModifiers(e.modifiersEx), modifiers,
when(e.id) { when(event.id) {
MouseEvent.MOUSE_WHEEL-> SkikoPointerEventKind.SCROLL MouseEvent.MOUSE_WHEEL-> SkikoPointerEventKind.SCROLL
else -> SkikoPointerEventKind.UNKNOWN else -> SkikoPointerEventKind.UNKNOWN
}, },
e event
) )
} }
fun toSkikoEvent(e: KeyEvent): SkikoKeyboardEvent { fun toSkikoEvent(event: KeyEvent): SkikoKeyboardEvent {
var key = event.keyCode
val side = event.getKeyLocation()
if (side == KEY_LOCATION_RIGHT) {
if (
key == SkikoKey.KEY_LEFT_CONTROL.value ||
key == SkikoKey.KEY_LEFT_SHIFT.value ||
key == SkikoKey.KEY_LEFT_META.value
)
key = key.or(0x80000000.toInt())
}
if (side == KEY_LOCATION_NUMPAD) {
if (key == SkikoKey.KEY_ENTER.value) {
key = key.or(0x80000000.toInt())
}
}
return SkikoKeyboardEvent( return SkikoKeyboardEvent(
e.keyCode, SkikoKey.valueOf(key),
toSkikoModifiers(e.modifiersEx), toSkikoModifiers(event.modifiersEx),
when(e.id) { when(event.id) {
KeyEvent.KEY_PRESSED -> SkikoKeyboardEventKind.DOWN KeyEvent.KEY_PRESSED -> SkikoKeyboardEventKind.DOWN
KeyEvent.KEY_RELEASED -> SkikoKeyboardEventKind.UP KeyEvent.KEY_RELEASED -> SkikoKeyboardEventKind.UP
KeyEvent.KEY_TYPED -> SkikoKeyboardEventKind.TYPE
else -> SkikoKeyboardEventKind.UNKNOWN else -> SkikoKeyboardEventKind.UNKNOWN
}, },
e event
) )
} }
fun toSkikoEvent(e: InputMethodEvent): SkikoInputEvent { fun toSkikoEvent(event: InputMethodEvent): SkikoInputEvent {
return SkikoInputEvent( return SkikoInputEvent(
"", // TODO: this parameter should be reconsidered "", // TODO: this parameter should be reconsidered
e event
) )
} }
......
...@@ -7,6 +7,7 @@ import java.awt.Color ...@@ -7,6 +7,7 @@ import java.awt.Color
import java.awt.Component import java.awt.Component
import java.awt.Graphics import java.awt.Graphics
import java.awt.event.* import java.awt.event.*
import java.awt.event.KeyEvent.*
import java.awt.im.InputMethodRequests import java.awt.im.InputMethodRequests
import java.awt.Window import java.awt.Window
import java.util.concurrent.CancellationException import java.util.concurrent.CancellationException
...@@ -197,9 +198,6 @@ actual open class SkiaLayer internal constructor( ...@@ -197,9 +198,6 @@ actual open class SkiaLayer internal constructor(
override fun keyReleased(e: KeyEvent) { override fun keyReleased(e: KeyEvent) {
skikoView?.onKeyboardEvent(toSkikoEvent(e)) skikoView?.onKeyboardEvent(toSkikoEvent(e))
} }
override fun keyTyped(e: KeyEvent) {
skikoView?.onKeyboardEvent(toSkikoEvent(e))
}
}) })
addInputMethodListener(object : InputMethodListener { addInputMethodListener(object : InputMethodListener {
...@@ -551,3 +549,117 @@ actual typealias SkikoGesturePlatformEvent = Any ...@@ -551,3 +549,117 @@ actual typealias SkikoGesturePlatformEvent = Any
actual typealias SkikoPlatformInputEvent = InputMethodEvent actual typealias SkikoPlatformInputEvent = InputMethodEvent
actual typealias SkikoPlatformKeyboardEvent = KeyEvent actual typealias SkikoPlatformKeyboardEvent = KeyEvent
actual typealias SkikoPlatformPointerEvent = MouseEvent actual typealias SkikoPlatformPointerEvent = MouseEvent
actual enum class SkikoKey(val value: Int) {
KEY_UNKNOWN(-1),
KEY_A(VK_A),
KEY_S(VK_B),
KEY_D(VK_D),
KEY_F(VK_F),
KEY_H(VK_H),
KEY_G(VK_G),
KEY_Z(VK_Z),
KEY_X(VK_X),
KEY_C(VK_C),
KEY_V(VK_V),
KEY_B(VK_B),
KEY_Q(VK_Q),
KEY_W(VK_W),
KEY_E(VK_E),
KEY_R(VK_R),
KEY_Y(VK_Y),
KEY_T(VK_T),
KEY_U(VK_U),
KEY_I(VK_I),
KEY_P(VK_P),
KEY_L(VK_L),
KEY_J(VK_J),
KEY_K(VK_K),
KEY_N(VK_N),
KEY_M(VK_M),
KEY_O(VK_O),
KEY_1(VK_1),
KEY_2(VK_2),
KEY_3(VK_3),
KEY_4(VK_4),
KEY_5(VK_5),
KEY_6(VK_6),
KEY_7(VK_7),
KEY_8(VK_8),
KEY_9(VK_9),
KEY_0(VK_0),
KEY_CLOSE_BRACKET(VK_CLOSE_BRACKET),
KEY_OPEN_BRACKET(VK_OPEN_BRACKET),
KEY_QUOTE(VK_QUOTE),
KEY_SEMICOLON(VK_SEMICOLON),
KEY_SLASH(VK_SLASH),
KEY_COMMA(VK_COMMA),
KEY_BACKSLASH(VK_BACK_SLASH),
KEY_PERIOD(VK_PERIOD),
KEY_BACK_QUOTE(VK_BACK_QUOTE),
KEY_EQUALS(VK_EQUALS),
KEY_MINUS(VK_MINUS),
KEY_ENTER(VK_ENTER),
KEY_ESCAPE(VK_ESCAPE),
KEY_TAB(VK_TAB),
KEY_BACKSPACE(VK_BACK_SPACE),
KEY_SPACE(VK_SPACE),
KEY_CAPSLOCK(VK_CAPS_LOCK),
KEY_LEFT_META(VK_META),
KEY_LEFT_SHIFT(VK_SHIFT),
KEY_LEFT_ALT(VK_ALT),
KEY_LEFT_CONTROL(VK_CONTROL),
KEY_RIGHT_META(0x80000000.toInt() or VK_META),
KEY_RIGHT_SHIFT(0x80000000.toInt() or VK_SHIFT),
KEY_RIGHT_ALT(VK_ALT_GRAPH),
KEY_RIGHT_CONTROL(0x80000000.toInt() or VK_CONTROL),
KEY_UP(VK_UP),
KEY_DOWN(VK_DOWN),
KEY_LEFT(VK_LEFT),
KEY_RIGHT(VK_RIGHT),
KEY_F1(VK_F1),
KEY_F2(VK_F2),
KEY_F3(VK_F3),
KEY_F4(VK_F4),
KEY_F5(VK_F5),
KEY_F6(VK_F6),
KEY_F7(VK_F7),
KEY_F8(VK_F8),
KEY_F9(VK_F9),
KEY_F10(VK_F10),
KEY_F11(VK_F11),
KEY_F12(VK_F12),
KEY_PRINTSCEEN(VK_PRINTSCREEN),
KEY_SCROLL_LOCK(VK_SCROLL_LOCK),
KEY_PAUSE(VK_PAUSE),
KEY_INSERT(VK_INSERT),
KEY_HOME(VK_HOME),
KEY_PGUP(VK_PAGE_UP),
KEY_DELETE(VK_DELETE),
KEY_END(VK_END),
KEY_PGDOWN(VK_PAGE_DOWN),
KEY_NUM_LOCK(VK_NUM_LOCK),
KEY_NUMPAD_0(VK_NUMPAD0),
KEY_NUMPAD_1(VK_NUMPAD1),
KEY_NUMPAD_2(VK_NUMPAD2),
KEY_NUMPAD_3(VK_NUMPAD3),
KEY_NUMPAD_4(VK_NUMPAD4),
KEY_NUMPAD_5(VK_NUMPAD5),
KEY_NUMPAD_6(VK_NUMPAD6),
KEY_NUMPAD_7(VK_NUMPAD7),
KEY_NUMPAD_8(VK_NUMPAD8),
KEY_NUMPAD_9(VK_NUMPAD9),
KEY_NUMPAD_ENTER(0x80000000.toInt() or VK_ENTER),
KEY_NUMPAD_ADD(VK_ADD),
KEY_NUMPAD_SUBTRACT(VK_SUBTRACT),
KEY_NUMPAD_MULTIPLY(VK_MULTIPLY),
KEY_NUMPAD_DIVIDE(VK_DIVIDE),
KEY_NUMPAD_DECIMAC(VK_DECIMAL);
companion object {
fun valueOf(value: Int): SkikoKey {
val key = SkikoKey.values().firstOrNull { it.value == value }
return if (key == null) SkikoKey.KEY_UNKNOWN else key
}
}
}
\ No newline at end of file
...@@ -29,3 +29,117 @@ actual typealias SkikoGesturePlatformEvent = Any ...@@ -29,3 +29,117 @@ actual typealias SkikoGesturePlatformEvent = Any
actual typealias SkikoPlatformInputEvent = Any actual typealias SkikoPlatformInputEvent = Any
actual typealias SkikoPlatformKeyboardEvent = Any actual typealias SkikoPlatformKeyboardEvent = Any
actual typealias SkikoPlatformPointerEvent = Any actual typealias SkikoPlatformPointerEvent = Any
actual enum class SkikoKey(val value: Int) {
KEY_UNKNOWN(-1),
KEY_A(0),
KEY_S(1),
KEY_D(2),
KEY_F(3),
KEY_H(4),
KEY_G(5),
KEY_Z(6),
KEY_X(7),
KEY_C(8),
KEY_V(9),
KEY_B(11),
KEY_Q(12),
KEY_W(13),
KEY_E(14),
KEY_R(15),
KEY_Y(16),
KEY_T(17),
KEY_U(32),
KEY_I(34),
KEY_P(35),
KEY_L(37),
KEY_J(38),
KEY_K(40),
KEY_N(45),
KEY_M(46),
KEY_O(31),
KEY_1(18),
KEY_2(19),
KEY_3(20),
KEY_4(21),
KEY_5(23),
KEY_6(22),
KEY_7(26),
KEY_8(28),
KEY_9(25),
KEY_0(29),
KEY_CLOSE_BRACKET(30),
KEY_OPEN_BRACKET(33),
KEY_QUOTE(39),
KEY_SEMICOLON(41),
KEY_SLASH(42),
KEY_COMMA(43),
KEY_BACKSLASH(44),
KEY_PERIOD(47),
KEY_BACK_QUOTE(50),
KEY_EQUALS(24),
KEY_MINUS(27),
KEY_ENTER(36),
KEY_ESCAPE(53),
KEY_TAB(48),
KEY_BACKSPACE(51),
KEY_SPACE(49),
KEY_CAPSLOCK(57),
KEY_LEFT_META(55),
KEY_LEFT_SHIFT(56),
KEY_LEFT_ALT(58),
KEY_LEFT_CONTROL(59),
KEY_RIGHT_META(54),
KEY_RIGHT_SHIFT(60),
KEY_RIGHT_ALT(61),
KEY_RIGHT_CONTROL(62),
KEY_UP(126),
KEY_DOWN(125),
KEY_LEFT(123),
KEY_RIGHT(124),
KEY_F1(122),
KEY_F2(120),
KEY_F3(99),
KEY_F4(118),
KEY_F5(96),
KEY_F6(97),
KEY_F7(98),
KEY_F8(100),
KEY_F9(101),
KEY_F10(109),
KEY_F11(103),
KEY_F12(111),
KEY_PRINTSCEEN(105),
KEY_SCROLL_LOCK(107),
KEY_PAUSE(113),
KEY_INSERT(114),
KEY_HOME(115),
KEY_PGUP(116),
KEY_DELETE(117),
KEY_END(119),
KEY_PGDOWN(121),
KEY_NUM_LOCK(71),
KEY_NUMPAD_0(82),
KEY_NUMPAD_1(83),
KEY_NUMPAD_2(84),
KEY_NUMPAD_3(85),
KEY_NUMPAD_4(86),
KEY_NUMPAD_5(87),
KEY_NUMPAD_6(88),
KEY_NUMPAD_7(88),
KEY_NUMPAD_8(91),
KEY_NUMPAD_9(92),
KEY_NUMPAD_ENTER(76),
KEY_NUMPAD_ADD(69),
KEY_NUMPAD_SUBTRACT(78),
KEY_NUMPAD_MULTIPLY(67),
KEY_NUMPAD_DIVIDE(75),
KEY_NUMPAD_DECIMAC(65);
companion object {
fun valueOf(value: Int): SkikoKey {
val key = SkikoKey.values().firstOrNull { it.value == value }
return if (key == null) SkikoKey.KEY_UNKNOWN else key
}
}
}
\ No newline at end of file
...@@ -18,37 +18,162 @@ fun toSkikoEvent( ...@@ -18,37 +18,162 @@ fun toSkikoEvent(
return SkikoPointerEvent( return SkikoPointerEvent(
xpos, xpos,
ypos, ypos,
toSkikoMouseButtons(event), toSkikoMouseButtons(event, kind),
toSkikoModifiers(event), toSkikoModifiers(event),
kind, kind,
event event
) )
} }
fun toSkikoEvent(
event: NSEvent,
button: SkikoMouseButtons,
kind: SkikoPointerEventKind,
view: NSView
): SkikoPointerEvent {
var (xpos, ypos) = event.locationInWindow.useContents {
x to y
}
// Translate.
view.frame.useContents {
ypos = size.height - ypos
}
var buttons: SkikoMouseButtons
if (kind == SkikoPointerEventKind.DOWN) {
buttonsFlags = buttonsFlags.or(button.value)
buttons = SkikoMouseButtons(buttonsFlags)
} else {
buttons = SkikoMouseButtons(buttonsFlags)
buttonsFlags = buttonsFlags.xor(button.value)
}
return SkikoPointerEvent(
xpos,
ypos,
buttons,
toSkikoModifiers(event),
kind,
event
)
}
fun toSkikoScrollEvent(
event: NSEvent
): SkikoPointerEvent {
return SkikoPointerEvent(
event.deltaX,
event.deltaY,
SkikoMouseButtons.NONE,
toSkikoModifiers(event),
SkikoPointerEventKind.SCROLL,
event
)
}
fun toSkikoEvent( fun toSkikoEvent(
event: NSEvent, event: NSEvent,
kind: SkikoKeyboardEventKind kind: SkikoKeyboardEventKind
): SkikoKeyboardEvent { ): SkikoKeyboardEvent {
return SkikoKeyboardEvent( return SkikoKeyboardEvent(
event.keyCode.toInt(), SkikoKey.valueOf(event.keyCode.toInt()),
toSkikoModifiers(event), toSkikoModifiers(event),
kind, kind,
event event
) )
} }
private fun toSkikoMouseButtons(event: NSEvent): SkikoMouseButtons { private val actionAllKeyUpFlag = 256.toULong() // MacOS specific
var result = 0 private var modifierKeyUpFlag = actionAllKeyUpFlag
val mask = event.buttonMask.toInt() fun toSkikoEvent(
if ((mask and 1) != 0 || event.buttonNumber == 0L) { event: NSEvent
result = result.or(SkikoMouseButtons.LEFT.value) ): SkikoKeyboardEvent {
// NSView.keyDown(NSEvent)/keyUp(NSEvent) does not work with modifier keys,
// so we need to use NSView.flagsChanged(NSEvent)
// and convert modifier key event to regular key event.
// Unfortunately, NSEvent does not give us any information about the type of action,
// so we need to check it manually.
val action = event.modifierFlags and NSEventModifierFlagDeviceIndependentFlagsMask.inv()
var kind = SkikoKeyboardEventKind.DOWN
val key = SkikoKey.valueOf(event.keyCode.toInt())
if (action >= modifierKeyUpFlag) {
kind = SkikoKeyboardEventKind.DOWN
} else {
kind = SkikoKeyboardEventKind.UP
}
modifierKeyUpFlag = action
if (modifierKeyUpFlag == actionAllKeyUpFlag) {
kind = SkikoKeyboardEventKind.UP
}
return SkikoKeyboardEvent(
SkikoKey.valueOf(event.keyCode.toInt()),
toSkikoModifiers(event),
kind,
event
)
}
private var buttonsFlags = 0
private fun toSkikoMouseButtons(
event: NSEvent,
kind: SkikoPointerEventKind
): SkikoMouseButtons {
val button = event.buttonNumber.toInt()
if (kind == SkikoPointerEventKind.DOWN) {
buttonsFlags = buttonsFlags.or(getSkikoButtonValue(button))
return SkikoMouseButtons(buttonsFlags)
}
return SkikoMouseButtons(buttonsFlags).also {
buttonsFlags = buttonsFlags.xor(getSkikoButtonValue(button))
} }
if ((mask and 2) != 0 || event.buttonNumber == 1L) { }
result = result.or(SkikoMouseButtons.RIGHT.value)
private fun getSkikoButtonValue(button: Int): Int {
return when (button) {
2 -> SkikoMouseButtons.MIDDLE.value
3 -> SkikoMouseButtons.BUTTON_4.value
4 -> SkikoMouseButtons.BUTTON_5.value
5 -> SkikoMouseButtons.BUTTON_6.value
6 -> SkikoMouseButtons.BUTTON_7.value
7 -> SkikoMouseButtons.BUTTON_8.value
else -> 0
} }
return SkikoMouseButtons(result)
} }
private fun toSkikoModifiers(event: NSEvent): SkikoInputModifiers { private fun toSkikoModifiers(event: NSEvent): SkikoInputModifiers {
return SkikoInputModifiers.EMPTY var result = 0
val modifiers = event.modifierFlags
if (modifiers and NSEventModifierFlagOption != 0.toULong()) {
result = result.or(SkikoInputModifiers.ALT.value)
}
if (modifiers and NSEventModifierFlagShift != 0.toULong()) {
result = result.or(SkikoInputModifiers.SHIFT.value)
}
if (modifiers and NSEventModifierFlagControl != 0.toULong()) {
result = result.or(SkikoInputModifiers.CONTROL.value)
}
if (modifiers and NSEventModifierFlagCommand != 0.toULong()) {
result = result.or(SkikoInputModifiers.META.value)
}
return SkikoInputModifiers(result)
}
private fun keyToModifier(key: SkikoKey): ULong {
return when (key) {
SkikoKey.KEY_LEFT_ALT,
SkikoKey.KEY_RIGHT_ALT -> {
NSEventModifierFlagOption
}
SkikoKey.KEY_LEFT_SHIFT,
SkikoKey.KEY_RIGHT_SHIFT -> {
NSEventModifierFlagShift
}
SkikoKey.KEY_LEFT_CONTROL,
SkikoKey.KEY_RIGHT_CONTROL -> {
NSEventModifierFlagControl
}
SkikoKey.KEY_LEFT_META,
SkikoKey.KEY_RIGHT_META -> {
NSEventModifierFlagCommand
}
else -> 0.toULong()
}
} }
\ No newline at end of file
...@@ -64,25 +64,34 @@ actual open class SkiaLayer() { ...@@ -64,25 +64,34 @@ actual open class SkiaLayer() {
} }
override fun updateTrackingAreas() { override fun updateTrackingAreas() {
trackingArea?.let { removeTrackingArea(it) } trackingArea?.let { removeTrackingArea(it) }
trackingArea = NSTrackingArea(rect = bounds, trackingArea = NSTrackingArea(
rect = bounds,
options = NSTrackingActiveAlways or options = NSTrackingActiveAlways or
NSTrackingMouseEnteredAndExited or NSTrackingMouseEnteredAndExited or
NSTrackingMouseMoved or NSTrackingMouseMoved or
NSTrackingActiveInKeyWindow or
NSTrackingAssumeInside or
NSTrackingInVisibleRect, NSTrackingInVisibleRect,
owner = nsView, userInfo = null) owner = nsView, userInfo = null)
nsView.addTrackingArea(trackingArea!!) nsView.addTrackingArea(trackingArea!!)
} }
override fun mouseDown(event: NSEvent) {
skikoView?.onPointerEvent(toSkikoEvent(event, SkikoMouseButtons.LEFT, SkikoPointerEventKind.DOWN, nsView))
}
override fun mouseUp(event: NSEvent) {
skikoView?.onPointerEvent(toSkikoEvent(event, SkikoMouseButtons.LEFT, SkikoPointerEventKind.UP, nsView))
}
override fun rightMouseDown(event: NSEvent) { override fun rightMouseDown(event: NSEvent) {
skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.DOWN, nsView)) skikoView?.onPointerEvent(toSkikoEvent(event, SkikoMouseButtons.RIGHT, SkikoPointerEventKind.DOWN, nsView))
} }
override fun rightMouseUp(event: NSEvent) { override fun rightMouseUp(event: NSEvent) {
skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.UP, nsView)) skikoView?.onPointerEvent(toSkikoEvent(event, SkikoMouseButtons.RIGHT, SkikoPointerEventKind.UP, nsView))
} }
override fun mouseDown(event: NSEvent) { override fun otherMouseDown(event: NSEvent) {
skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.DOWN, nsView)) skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.DOWN, nsView))
} }
override fun mouseUp(event: NSEvent) { override fun otherMouseUp(event: NSEvent) {
skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.UP, nsView)) skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.UP, nsView))
} }
override fun mouseMoved(event: NSEvent) { override fun mouseMoved(event: NSEvent) {
...@@ -91,9 +100,15 @@ actual open class SkiaLayer() { ...@@ -91,9 +100,15 @@ actual open class SkiaLayer() {
override fun mouseDragged(event: NSEvent) { override fun mouseDragged(event: NSEvent) {
skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.DRAG, nsView)) skikoView?.onPointerEvent(toSkikoEvent(event, SkikoPointerEventKind.DRAG, nsView))
} }
override fun scrollWheel(event: NSEvent) {
skikoView?.onPointerEvent(toSkikoScrollEvent(event))
}
override fun keyDown(event: NSEvent) { override fun keyDown(event: NSEvent) {
skikoView?.onKeyboardEvent(toSkikoEvent(event, SkikoKeyboardEventKind.DOWN)) skikoView?.onKeyboardEvent(toSkikoEvent(event, SkikoKeyboardEventKind.DOWN))
} }
override fun flagsChanged(event: NSEvent) {
skikoView?.onKeyboardEvent(toSkikoEvent(event))
}
override fun keyUp(event: NSEvent) { override fun keyUp(event: NSEvent) {
skikoView?.onKeyboardEvent(toSkikoEvent(event, SkikoKeyboardEventKind.UP)) skikoView?.onKeyboardEvent(toSkikoEvent(event, SkikoKeyboardEventKind.UP))
} }
...@@ -124,6 +139,7 @@ actual open class SkiaLayer() { ...@@ -124,6 +139,7 @@ actual open class SkiaLayer() {
} }
} }
window.contentView!!.addSubview(nsView) window.contentView!!.addSubview(nsView)
window.makeFirstResponder(nsView)
redrawer = createNativeRedrawer(this, renderApi).apply { redrawer = createNativeRedrawer(this, renderApi).apply {
syncSize() syncSize()
needRedraw() needRedraw()
...@@ -166,3 +182,117 @@ actual typealias SkikoGesturePlatformEvent = NSEvent ...@@ -166,3 +182,117 @@ actual typealias SkikoGesturePlatformEvent = NSEvent
actual typealias SkikoPlatformInputEvent = NSEvent actual typealias SkikoPlatformInputEvent = NSEvent
actual typealias SkikoPlatformKeyboardEvent = NSEvent actual typealias SkikoPlatformKeyboardEvent = NSEvent
actual typealias SkikoPlatformPointerEvent = NSEvent actual typealias SkikoPlatformPointerEvent = NSEvent
actual enum class SkikoKey(val value: Int) {
KEY_UNKNOWN(-1),
KEY_A(0),
KEY_S(1),
KEY_D(2),
KEY_F(3),
KEY_H(4),
KEY_G(5),
KEY_Z(6),
KEY_X(7),
KEY_C(8),
KEY_V(9),
KEY_B(11),
KEY_Q(12),
KEY_W(13),
KEY_E(14),
KEY_R(15),
KEY_Y(16),
KEY_T(17),
KEY_U(32),
KEY_I(34),
KEY_P(35),
KEY_L(37),
KEY_J(38),
KEY_K(40),
KEY_N(45),
KEY_M(46),
KEY_O(31),
KEY_1(18),
KEY_2(19),
KEY_3(20),
KEY_4(21),
KEY_5(23),
KEY_6(22),
KEY_7(26),
KEY_8(28),
KEY_9(25),
KEY_0(29),
KEY_CLOSE_BRACKET(30),
KEY_OPEN_BRACKET(33),
KEY_QUOTE(39),
KEY_SEMICOLON(41),
KEY_SLASH(42),
KEY_COMMA(43),
KEY_BACKSLASH(44),
KEY_PERIOD(47),
KEY_BACK_QUOTE(50),
KEY_EQUALS(24),
KEY_MINUS(27),
KEY_ENTER(36),
KEY_ESCAPE(53),
KEY_TAB(48),
KEY_BACKSPACE(51),
KEY_SPACE(49),
KEY_CAPSLOCK(57),
KEY_LEFT_META(55),
KEY_LEFT_SHIFT(56),
KEY_LEFT_ALT(58),
KEY_LEFT_CONTROL(59),
KEY_RIGHT_META(54),
KEY_RIGHT_SHIFT(60),
KEY_RIGHT_ALT(61),
KEY_RIGHT_CONTROL(62),
KEY_UP(126),
KEY_DOWN(125),
KEY_LEFT(123),
KEY_RIGHT(124),
KEY_F1(122),
KEY_F2(120),
KEY_F3(99),
KEY_F4(118),
KEY_F5(96),
KEY_F6(97),
KEY_F7(98),
KEY_F8(100),
KEY_F9(101),
KEY_F10(109),
KEY_F11(103),
KEY_F12(111),
KEY_PRINTSCEEN(105),
KEY_SCROLL_LOCK(107),
KEY_PAUSE(113),
KEY_INSERT(114),
KEY_HOME(115),
KEY_PGUP(116),
KEY_DELETE(117),
KEY_END(119),
KEY_PGDOWN(121),
KEY_NUM_LOCK(71),
KEY_NUMPAD_0(82),
KEY_NUMPAD_1(83),
KEY_NUMPAD_2(84),
KEY_NUMPAD_3(85),
KEY_NUMPAD_4(86),
KEY_NUMPAD_5(87),
KEY_NUMPAD_6(88),
KEY_NUMPAD_7(88),
KEY_NUMPAD_8(91),
KEY_NUMPAD_9(92),
KEY_NUMPAD_ENTER(76),
KEY_NUMPAD_ADD(69),
KEY_NUMPAD_SUBTRACT(78),
KEY_NUMPAD_MULTIPLY(67),
KEY_NUMPAD_DIVIDE(75),
KEY_NUMPAD_DECIMAC(65);
companion object {
fun valueOf(value: Int): SkikoKey {
val key = SkikoKey.values().firstOrNull { it.value == value }
return if (key == null) SkikoKey.KEY_UNKNOWN else key
}
}
}
\ No newline at end of file
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