Skip to content

Commit

Permalink
[web] KeyEvent resolved via code rather than keyCode (#1404)
Browse files Browse the repository at this point in the history
  • Loading branch information
Schahen committed Jun 14, 2024
1 parent 03d732f commit f7e2596
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,6 @@ package androidx.compose.ui.input.key
import androidx.compose.ui.input.pointer.PointerKeyboardModifiers
import org.w3c.dom.events.KeyboardEvent

private fun Key(keyCode: Long, location: Int) = Key(
keyCode = if (location == KeyboardEvent.DOM_KEY_LOCATION_RIGHT) {
when (keyCode) {
Key.CtrlLeft.keyCode,
Key.ShiftLeft.keyCode,
Key.MetaLeft.keyCode -> keyCode or 0x80000000
else -> keyCode
}
} else {
keyCode
}
)

private fun KeyboardEvent.toInputModifiers(): PointerKeyboardModifiers {
return PointerKeyboardModifiers(
isAltPressed = altKey,
Expand All @@ -42,7 +29,7 @@ private fun KeyboardEvent.toInputModifiers(): PointerKeyboardModifiers {
}

internal fun KeyboardEvent.toComposeEvent(): KeyEvent {
val composeKey = Key(keyCode.toLong(), location)
val composeKey = toKey()
return KeyEvent(
nativeKeyEvent = InternalKeyEvent(
key = composeKey,
Expand Down Expand Up @@ -81,3 +68,130 @@ internal fun String.codePointAt(index: Int): CodePoint {
}
return high.code
}

private val codeMap = mapOf(
"KeyA" to Key.A,
"KeyB" to Key.B,
"KeyC" to Key.C,
"KeyD" to Key.D,
"KeyE" to Key.E,
"KeyF" to Key.F,
"KeyG" to Key.G,
"KeyH" to Key.H,
"KeyI" to Key.I,
"KeyJ" to Key.J,
"KeyK" to Key.K,
"KeyL" to Key.L,
"KeyM" to Key.M,
"KeyN" to Key.N,
"KeyO" to Key.O,
"KeyP" to Key.P,
"KeyQ" to Key.Q,
"KeyR" to Key.R,
"KeyS" to Key.S,
"KeyT" to Key.T,
"KeyU" to Key.U,
"KeyV" to Key.V,
"KeyW" to Key.W,
"KeyX" to Key.X,
"KeyY" to Key.Y,
"KeyZ" to Key.Z,

"Digit0" to Key.Zero,
"Digit1" to Key.One,
"Digit2" to Key.Two,
"Digit3" to Key.Three,
"Digit4" to Key.Four,
"Digit5" to Key.Five,
"Digit6" to Key.Six,
"Digit7" to Key.Seven,
"Digit8" to Key.Eight,
"Digit9" to Key.Nine,

"Numpad0" to Key.NumPad0,
"Numpad1" to Key.NumPad1,
"Numpad2" to Key.NumPad2,
"Numpad3" to Key.NumPad3,
"Numpad4" to Key.NumPad4,
"Numpad5" to Key.NumPad5,
"Numpad6" to Key.NumPad6,
"Numpad7" to Key.NumPad7,
"Numpad8" to Key.NumPad8,
"Numpad9" to Key.NumPad9,

"NumpadDivide" to Key.NumPadDivide,
"NumpadMultiply" to Key.NumPadMultiply,
"NumpadSubtract" to Key.NumPadSubtract,
"NumpadAdd" to Key.NumPadAdd,
"NumpadEnter" to Key.NumPadEnter,
"NumpadEqual" to Key.NumPadEquals,
"NumpadDecimal" to Key.NumPadDot,

"NumLock" to Key.NumLock,

"Minus" to Key.Minus,
"Equal" to Key.Equals,
"Backspace" to Key.Backspace,
"BracketLeft" to Key.LeftBracket,
"BracketRight" to Key.RightBracket,
"Backslash" to Key.Backslash,
"Semicolon" to Key.Semicolon,
"Enter" to Key.Enter,
"Comma" to Key.Comma,
"Period" to Key.Period,
"Slash" to Key.Slash,

"ArrowLeft" to Key.DirectionLeft,
"ArrowUp" to Key.DirectionUp,
"ArrowRight" to Key.DirectionRight,
"ArrowDown" to Key.DirectionDown,

"Home" to Key.MoveHome,
"PageUp" to Key.PageUp,
"PageDown" to Key.PageDown,
"Delete" to Key.Delete,
"End" to Key.MoveEnd,

"Backquote" to Key.Grave,
"Tab" to Key.Tab,
"CapsLock" to Key.CapsLock,

"ShiftLeft" to Key.ShiftLeft,
"ControlLeft" to Key.CtrlLeft,
"AltLeft" to Key.AltLeft,
"MetaLeft" to Key.MetaLeft,

"ShiftRight" to Key.ShiftRight,
"ControlRight" to Key.CtrlRight,
"AltRight" to Key.AltRight,
"MetaRight" to Key.MetaRight,
"Insert" to Key.Insert,

"Escape" to Key.Escape,

"F1" to Key.F1,
"F2" to Key.F2,
"F3" to Key.F3,
"F4" to Key.F4,
"F5" to Key.F5,
"F6" to Key.F6,
"F7" to Key.F7,
"F8" to Key.F8,
"F9" to Key.F9,
"F10" to Key.F10,
"F11" to Key.F11,
"F12" to Key.F12,

"Space" to Key.Spacebar,
)

private fun KeyboardEvent.toKey(): Key {
// code is empty string if the actual keyboard event actually is generated by virtual keyboard
val keyResolved = if (code.isEmpty()) {
codeMap[key]
} else {
codeMap[code]
}

return keyResolved ?: Key.Unknown
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,27 +80,16 @@ class KeyEventConversionTests {
keyDownEvent("8", code = "Digit8").assertEquivalence(key = Key.Eight)
keyDownEvent("9", code = "Digit9").assertEquivalence(key = Key.Nine)

keyDownEvent("0", code = "Numpad0").assertEquivalence(key = Key.Zero)
keyDownEvent("1", code = "Numpad1").assertEquivalence(key = Key.One)
keyDownEvent("2", code = "Numpad2").assertEquivalence(key = Key.Two)
keyDownEvent("3", code = "Numpad3").assertEquivalence(key = Key.Three)
keyDownEvent("4", code = "Numpad4").assertEquivalence(key = Key.Four)
keyDownEvent("5", code = "Numpad5").assertEquivalence(key = Key.Five)
keyDownEvent("6", code = "Numpad6").assertEquivalence(key = Key.Six)
keyDownEvent("7", code = "Numpad7").assertEquivalence(key = Key.Seven)
keyDownEvent("8", code = "Numpad8").assertEquivalence(key = Key.Eight)
keyDownEvent("9", code = "Numpad9").assertEquivalence(key = Key.Nine)

keyDownEvent("0", code = "Numpad0").assertEquivalence(key = Key.Zero, codePoint = 48)
keyDownEvent("1", code = "Numpad1").assertEquivalence(key = Key.One, codePoint = 49)
keyDownEvent("2", code = "Numpad2").assertEquivalence(key = Key.Two, codePoint = 50)
keyDownEvent("3", code = "Numpad3").assertEquivalence(key = Key.Three, codePoint = 51)
keyDownEvent("4", code = "Numpad4").assertEquivalence(key = Key.Four, codePoint = 52)
keyDownEvent("5", code = "Numpad5").assertEquivalence(key = Key.Five, codePoint = 53)
keyDownEvent("6", code = "Numpad6").assertEquivalence(key = Key.Six, codePoint = 54)
keyDownEvent("7", code = "Numpad7").assertEquivalence(key = Key.Seven, codePoint = 55)
keyDownEvent("8", code = "Numpad8").assertEquivalence(key = Key.Eight, codePoint = 56)
keyDownEvent("9", code = "Numpad9").assertEquivalence(key = Key.Nine, codePoint = 57)
keyDownEvent("0", code = "Numpad0").assertEquivalence(key = Key.NumPad0, codePoint = 48)
keyDownEvent("1", code = "Numpad1").assertEquivalence(key = Key.NumPad1, codePoint = 49)
keyDownEvent("2", code = "Numpad2").assertEquivalence(key = Key.NumPad2, codePoint = 50)
keyDownEvent("3", code = "Numpad3").assertEquivalence(key = Key.NumPad3, codePoint = 51)
keyDownEvent("4", code = "Numpad4").assertEquivalence(key = Key.NumPad4, codePoint = 52)
keyDownEvent("5", code = "Numpad5").assertEquivalence(key = Key.NumPad5, codePoint = 53)
keyDownEvent("6", code = "Numpad6").assertEquivalence(key = Key.NumPad6, codePoint = 54)
keyDownEvent("7", code = "Numpad7").assertEquivalence(key = Key.NumPad7, codePoint = 55)
keyDownEvent("8", code = "Numpad8").assertEquivalence(key = Key.NumPad8, codePoint = 56)
keyDownEvent("9", code = "Numpad9").assertEquivalence(key = Key.NumPad9, codePoint = 57)

keyDownEvent("=", code = "NumpadEqual", keyCode = Key.NumPadEquals.keyCode.toInt()).assertEquivalence(key = Key.NumPadEquals, codePoint = 61)
keyDownEvent("/", code = "NumpadDivide", keyCode = Key.NumPadDivide.keyCode.toInt()).assertEquivalence(key = Key.NumPadDivide, codePoint = 47)
Expand Down Expand Up @@ -164,6 +153,7 @@ class KeyEventConversionTests {
keyDownEvent("F11", code = "F11", keyCode = Key.F11.keyCode.toInt()).assertEquivalence(key = Key.F11)
keyDownEvent("F12", code = "F12", keyCode = Key.F12.keyCode.toInt()).assertEquivalence(key = Key.F12)

keyDownEvent("", code = "Space", keyCode = Key.Spacebar.keyCode.toInt()).assertEquivalence(key = Key.Spacebar)
}

@Test
Expand Down Expand Up @@ -210,5 +200,15 @@ class KeyEventConversionTests {
keyDownEvent("+", code = "Equal", keyCode = Key.Equals.keyCode.toInt()).assertEquivalence(key = Key.Equals, codePoint = 43)
}

@Test
fun standardVirtualKeyboardLayout() {
// Virtual keyboard generates actual keyboard events for some of the keys pressed
// This keyboard events, however, actually differ - the code is always "" while key contains the value that we need
keyDownEvent("ArrowRight", code = "", keyCode = Key.DirectionRight.keyCode.toInt()).assertEquivalence(key = Key.DirectionRight)
keyDownEvent("ArrowLeft", code = "", keyCode = Key.DirectionLeft.keyCode.toInt()).assertEquivalence(key = Key.DirectionLeft)
keyDownEvent("Delete", code = "", keyCode = Key.Delete.keyCode.toInt()).assertEquivalence(key = Key.Delete)
keyDownEvent("Backspace", code = "", keyCode = Key.Backspace.keyCode.toInt()).assertEquivalence(key = Key.Backspace)
keyDownEvent("Enter", code = "", keyCode = Key.Enter.keyCode.toInt()).assertEquivalence(key = Key.Enter)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ class CanvasBasedWindowTests {
)

('0'..'9').forEachIndexed { index, c ->
canvasElement.dispatchEvent(keyDownEvent(c.toString()))
val id = c.toString()
canvasElement.dispatchEvent(keyDownEvent(id, code = "Digit${id}" ))
assertEquals(listOfNumbers[index], k)
}
}
Expand Down

0 comments on commit f7e2596

Please sign in to comment.