diff --git a/Backends/HTML5/kha/SystemImpl.hx b/Backends/HTML5/kha/SystemImpl.hx
index f9960ea42..3202f6449 100644
--- a/Backends/HTML5/kha/SystemImpl.hx
+++ b/Backends/HTML5/kha/SystemImpl.hx
@@ -7,6 +7,7 @@ import js.html.ClipboardEvent;
import js.html.DeviceMotionEvent;
import js.html.DeviceOrientationEvent;
import js.html.DragEvent;
+import js.html.FocusEvent;
import js.html.KeyboardEvent;
import js.html.MouseEvent;
import js.html.PointerEvent;
@@ -20,7 +21,9 @@ import kha.graphics4.TextureFormat;
import kha.input.Gamepad;
import kha.input.KeyCode;
import kha.input.Keyboard;
+import kha.input.KeyboardImpl;
import kha.input.Mouse;
+import kha.input.MouseImpl;
import kha.input.Sensor;
import kha.input.Surface;
import kha.js.AudioElementAudio;
@@ -215,7 +218,8 @@ class SystemImpl {
}
public static function vibrate(ms: Int): Void {
- if (Browser.navigator.vibrate == null) return;
+ if (Browser.navigator.vibrate == null)
+ return;
Browser.navigator.vibrate(ms);
}
@@ -247,9 +251,9 @@ class SystemImpl {
static function init2(defaultWidth: Int, defaultHeight: Int, ?backbufferFormat: TextureFormat) {
#if !kha_no_keyboard
- keyboard = new Keyboard();
+ keyboard = new KeyboardImpl();
#end
- mouse = new kha.input.MouseImpl();
+ mouse = new MouseImpl();
surface = new Surface();
gamepads = new Array();
gamepadStates = new Array();
@@ -494,7 +498,6 @@ class SystemImpl {
if (keyboard != null) {
canvas.onkeydown = keyDown;
canvas.onkeyup = keyUp;
- canvas.onkeypress = keyPress;
}
canvas.onblur = onBlur;
canvas.onfocus = onFocus;
@@ -669,7 +672,7 @@ class SystemImpl {
static var iosSoundEnabled: Bool = false;
static function unlockiOSSound(): Void {
- if (!ios || iosSoundEnabled)
+ if (!ios || iosSoundEnabled || MobileWebAudio._context == null)
return;
var buffer = MobileWebAudio._context.createBuffer(1, 1, 22050);
@@ -929,6 +932,8 @@ class SystemImpl {
var id = touch.identifier;
if (ios) {
id = iosTouchs.indexOf(id);
+ if (id == -1)
+ continue;
iosTouchs[id] = -1;
}
@@ -974,8 +979,12 @@ class SystemImpl {
for (touch in event.changedTouches) {
var id = touch.identifier;
- if (ios)
+ if (ios) {
id = iosTouchs.indexOf(id);
+ if (id == -1)
+ continue;
+ iosTouchs[id] = -1;
+ }
setTouchXY(touch);
if (!Surface.listenedEventsBefore) {
@@ -983,147 +992,25 @@ class SystemImpl {
}
surface.sendTouchEndEvent(id, touchX, touchY);
}
- iosTouchs = [];
insideInputEvent = false;
}
- static function onBlur() {
+ static function onBlur(event: FocusEvent) {
+ final input = KeyboardImpl.input;
+ if (input != null && event.relatedTarget == input)
+ return;
// System.pause();
System.background();
}
- static function onFocus() {
+ static function onFocus(event: FocusEvent) {
+ final input = KeyboardImpl.input;
+ if (input != null && event.relatedTarget == input)
+ return;
// System.resume();
System.foreground();
}
- static function keycodeToChar(key: String, keycode: Int, shift: Bool): String {
- if (key != null) {
- if (key.length == 1)
- return key;
- switch (key) {
- case "Add":
- return "+";
- case "Subtract":
- return "-";
- case "Multiply":
- return "*";
- case "Divide":
- return "/";
- }
- }
- switch (keycode) {
- case 187:
- if (shift)
- return "*";
- else
- return "+";
- case 188:
- if (shift)
- return ";";
- else
- return ",";
- case 189:
- if (shift)
- return "_";
- else
- return "-";
- case 190:
- if (shift)
- return ":";
- else
- return ".";
- case 191:
- if (shift)
- return "'";
- else
- return "#";
- case 226:
- if (shift)
- return ">";
- else
- return "<";
- case 106:
- return "*";
- case 107:
- return "+";
- case 109:
- return "-";
- case 111:
- return "/";
- case 49:
- if (shift)
- return "!";
- else
- return "1";
- case 50:
- if (shift)
- return "\"";
- else
- return "2";
- case 51:
- if (shift)
- return "§";
- else
- return "3";
- case 52:
- if (shift)
- return "$";
- else
- return "4";
- case 53:
- if (shift)
- return "%";
- else
- return "5";
- case 54:
- if (shift)
- return "&";
- else
- return "6";
- case 55:
- if (shift)
- return "/";
- else
- return "7";
- case 56:
- if (shift)
- return "(";
- else
- return "8";
- case 57:
- if (shift)
- return ")";
- else
- return "9";
- case 48:
- if (shift)
- return "=";
- else
- return "0";
- case 219:
- if (shift)
- return "?";
- else
- return "ß";
- case 212:
- if (shift)
- return "`";
- else
- return "´";
- }
- if (keycode >= 96 && keycode <= 105) { // num block
- return String.fromCharCode("0".code - 96 + keycode);
- }
- if (keycode >= "A".code && keycode <= "Z".code) {
- if (shift)
- return String.fromCharCode(keycode);
- else
- return String.fromCharCode(keycode - "A".code + "a".code);
- }
- return String.fromCharCode(keycode);
- }
-
static function keyDown(event: KeyboardEvent): Void {
insideInputEvent = true;
activeKeyEvent = event;
@@ -1135,10 +1022,17 @@ class SystemImpl {
// prevent key repeat
if (event.repeat) {
event.preventDefault();
+ activeKeyEvent = null;
+ insideInputEvent = false;
return;
}
- var keyCode = fixedKeyCode(event);
+ final keyCode = fixedKeyCode(event);
keyboard.sendDownEvent(keyCode);
+
+ if (event.key.length == 1) {
+ keyboard.sendPressEvent(event.key);
+ }
+
activeKeyEvent = null;
insideInputEvent = false;
}
@@ -1168,24 +1062,26 @@ class SystemImpl {
}
static function defaultKeyBlock(e: KeyboardEvent): Void {
+ final keyCode: KeyCode = cast e.keyCode;
// block if ctrl key pressed
if (e.ctrlKey || e.metaKey) {
// except for cut-copy-paste
- if (e.keyCode == 67 || e.keyCode == 88 || e.keyCode == 86) {
+ if (keyCode == C || keyCode == X || keyCode == V) {
return;
}
// and quit on macOS
- if (e.metaKey && e.keyCode == 81) {
+ if (e.metaKey && keyCode == Q) {
return;
}
e.preventDefault();
return;
}
+
// allow F-keys
- if (e.keyCode >= 112 && e.keyCode <= 123)
+ if (e.keyCode >= F1.toInt() && e.keyCode <= F12.toInt())
return;
// allow char keys
- if (e.key == null || e.key.length == 1)
+ if (e.key.length == 1)
return;
e.preventDefault();
}
@@ -1205,21 +1101,6 @@ class SystemImpl {
insideInputEvent = false;
}
- static function keyPress(event: KeyboardEvent): Void {
- insideInputEvent = true;
- activeKeyEvent = event;
- unlockSound();
-
- if (event.which == 0)
- return; // for Firefox and Safari
- preventDefaultKeyBehavior(event);
- event.stopPropagation();
- keyboard.sendPressEvent(String.fromCharCode(event.which));
-
- activeKeyEvent = null;
- insideInputEvent = false;
- }
-
public static function canSwitchFullscreen(): Bool {
return Syntax.code("'fullscreenElement ' in document ||
'mozFullScreenElement' in document ||
diff --git a/Backends/HTML5/kha/input/KeyboardImpl.hx b/Backends/HTML5/kha/input/KeyboardImpl.hx
new file mode 100644
index 000000000..9edfb1e14
--- /dev/null
+++ b/Backends/HTML5/kha/input/KeyboardImpl.hx
@@ -0,0 +1,92 @@
+package kha.input;
+
+import js.Browser.document;
+import js.html.InputElement;
+import js.html.InputEvent;
+import js.html.KeyboardEvent;
+import kha.SystemImpl;
+import kha.input.Keyboard;
+
+using StringTools;
+
+class KeyboardImpl extends kha.input.Keyboard {
+ static var virtualKeyboardId = "kha-virtual-keyboard";
+ public static var input: InputElement;
+
+ public function new() {
+ super();
+ }
+
+ override function show(): Void {
+ input = cast document.getElementById(virtualKeyboardId);
+ input ??= createKeyboardInputElement();
+ document.body.appendChild(input);
+ input.focus();
+ }
+
+ static function createKeyboardInputElement(): InputElement {
+ final input = document.createInputElement();
+ input.id = virtualKeyboardId;
+ input.style.position = "fixed";
+ input.style.left = "0px";
+ input.style.top = "0px";
+ input.style.opacity = "0.0";
+ input.style.pointerEvents = "none";
+ input.type = "text";
+ input.autocomplete = "off";
+ input.spellcheck = false;
+ input.setAttribute("autocorrect", "off");
+ input.setAttribute("autocapitalize", "off");
+
+ input.onkeydown = (e: KeyboardEvent) -> {
+ if (e.repeat) {
+ e.preventDefault();
+ return;
+ }
+ // virtual keyboards do not report pressed chars in most cases
+ // so we only redirect non-printable keys to canvas there
+ if (e.key.length == 1)
+ return;
+ final keyEvent = copyKeyboardEventFrom(e);
+ SystemImpl.khanvas.dispatchEvent(keyEvent);
+ }
+ input.onkeyup = (e: KeyboardEvent) -> {
+ final keyEvent = copyKeyboardEventFrom(e);
+ SystemImpl.khanvas.dispatchEvent(keyEvent);
+ }
+ input.oninput = (e: InputEvent) -> {
+ // IME-composition, key is not final yet
+ if (e.isComposing)
+ return;
+ final str: String = (e : Dynamic).data ?? return;
+ final kb = Keyboard.get() ?? return;
+ for (code in str) {
+ final char = String.fromCharCode(code);
+ kb.sendPressEvent(char);
+ }
+ input.value = "";
+ }
+ return input;
+ }
+
+ static function copyKeyboardEventFrom(e: KeyboardEvent): KeyboardEvent {
+ return new KeyboardEvent(e.type, {
+ key: e.key,
+ code: e.code,
+ keyCode: e.keyCode,
+ location: e.location,
+ ctrlKey: e.ctrlKey,
+ shiftKey: e.shiftKey,
+ altKey: e.altKey,
+ metaKey: e.metaKey,
+ bubbles: true,
+ cancelable: true
+ });
+ }
+
+ override function hide(): Void {
+ SystemImpl.khanvas.focus();
+ if (input != null)
+ document.body.removeChild(input);
+ }
+}
diff --git a/Sources/kha/input/KeyCode.hx b/Sources/kha/input/KeyCode.hx
index df3a4af76..427ef9c41 100644
--- a/Sources/kha/input/KeyCode.hx
+++ b/Sources/kha/input/KeyCode.hx
@@ -188,4 +188,8 @@ enum abstract KeyCode(Int) to Int {
var Zoom = 251;
var PA1 = 253;
var WinOemClear = 254;
+
+ public inline function toInt(): Int {
+ return this;
+ }
}