Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 48 additions & 21 deletions Backends/HTML5/kha/SystemImpl.hx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -59,6 +62,7 @@ class SystemImpl {
static var firefox: Bool = false;
public static var safari: Bool = false;
public static var ie: Bool = false;
public static var macos: Bool = false;
public static var insideInputEvent: Bool = false;
static public var activeMouseEvent: Null<MouseEvent>;
static public var activeWheelEvent: Null<WheelEvent>;
Expand Down Expand Up @@ -104,6 +108,7 @@ class SystemImpl {
firefox = isFirefox();
safari = isSafari();
ie = isIE();
macos = isMacOS();

mobileAudioPlaying = !mobile && !chrome && !firefox;

Expand Down Expand Up @@ -197,6 +202,11 @@ class SystemImpl {
return false;
}

static function isMacOS(): Bool {
var agent = js.Browser.navigator.userAgent;
return agent.contains("Mac") || isIOS();
}

public static function setCanvas(canvas: CanvasElement): Void {
khanvas = canvas;
}
Expand Down Expand Up @@ -247,9 +257,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<Gamepad>();
gamepadStates = new Array<GamepadStates>();
Expand Down Expand Up @@ -498,7 +508,6 @@ class SystemImpl {
if (keyboard != null) {
canvas.onkeydown = keyDown;
canvas.onkeyup = keyUp;
canvas.onkeypress = keyPress;
}
canvas.onblur = onBlur;
canvas.onfocus = onFocus;
Expand Down Expand Up @@ -991,12 +1000,18 @@ class SystemImpl {
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();
}
Expand Down Expand Up @@ -1139,10 +1154,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 (isPrintableText(event)) {
keyboard.sendPressEvent(event.key);
}

activeKeyEvent = null;
insideInputEvent = false;
}
Expand All @@ -1158,6 +1180,26 @@ class SystemImpl {
}
}

static function isPrintableText(event: KeyboardEvent): Bool {
if (event.key == null || event.key.length != 1)
return false;

if (event.metaKey)
return false;
if (macos) {
if (event.ctrlKey)
return false;
}
else {
// detect ctrl+alt chars
if (event.getModifierState("AltGraph"))
return true;
if (event.ctrlKey || event.altKey)
return false;
}
return true;
}

static function preventDefaultKeyBehavior(event: KeyboardEvent): Void {
switch (Keyboard.keyBehavior) {
case Default:
Expand Down Expand Up @@ -1209,21 +1251,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 ||
Expand Down
91 changes: 91 additions & 0 deletions Backends/HTML5/kha/input/KeyboardImpl.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package kha.input;

import js.Browser.document;
import js.html.InputElement;
import js.html.InputEvent;
import js.html.KeyboardEvent;

using StringTools;

class KeyboardImpl extends 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 == null || e.key.length == 1)
return;
final keyEvent = copyKeyboardEventFrom(e);
SystemImpl.khanvas.dispatchEvent(keyEvent);
}
input.onkeyup = (e: KeyboardEvent) -> {
if (e.key == null || e.key.length == 1)
return;
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();
input?.remove();
}
}
Loading