Skip to content

Commit

Permalink
fix: [#1512] Grab window focus by default for x-origin iframes
Browse files Browse the repository at this point in the history
  • Loading branch information
eonarheim committed Jun 14, 2023
1 parent 848f1da commit 8958619
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 6 deletions.
13 changes: 13 additions & 0 deletions sandbox/tests/iframe/frame.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Frame</title>
</head>
<body>
<script src="../../lib/excalibur.js"></script>
<script src="./main.js"></script>
</body>
</html>
13 changes: 13 additions & 0 deletions sandbox/tests/iframe/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button>Other things that have focus</button>
<iframe src="frame.html" width="600" height="400" frameborder="0"></iframe>
</body>
</html>
21 changes: 21 additions & 0 deletions sandbox/tests/iframe/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// window.focus();
// document.body.addEventListener('keydown', (evt) => {
// console.log(evt.code);
// })


var engine = new ex.Engine({
width: 600,
height: 400
});

engine.input.keyboard.on('press', (evt) => {
console.log(evt.key);
});

engine.onPostDraw = (ctx: ex.ExcaliburGraphicsContext) => {
const keys = engine.input.keyboard.getKeys();
ctx.debug.drawText(keys.join(','), ex.vec(200, 200));
}

engine.start();
14 changes: 13 additions & 1 deletion src/engine/Engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,15 @@ export interface EngineOptions {
*/
suppressPlayButton?: boolean;

/**
* Sets the focus of the window, this is needed when hosting excalibur in a cross-origin iframe in order for certain events (like keyboard)
* to work.
* For example: itch.io or codesandbox.io
*
* By default set to true,
*/
grabWindowFocus?: boolean;

/**
* Scroll prevention method.
*/
Expand Down Expand Up @@ -547,6 +556,7 @@ export class Engine extends Class implements CanInitialize, CanUpdate, CanDraw {
suppressMinimumBrowserFeatureDetection: null,
suppressHiDPIScaling: null,
suppressPlayButton: null,
grabWindowFocus: true,
scrollPreventionMode: ScrollPreventionMode.Canvas,
backgroundColor: Color.fromHex('#2185d0') // Excalibur blue
};
Expand Down Expand Up @@ -1102,7 +1112,9 @@ O|===|* >________________>\n\
pointers: new PointerEventReceiver(pointerTarget, this),
gamepads: new Input.Gamepads()
};
this.input.keyboard.init();
this.input.keyboard.init({
grabWindowFocus: this._originalOptions?.grabWindowFocus ?? true
});
this.input.pointers.init();
this.input.gamepads.init();

Expand Down
20 changes: 15 additions & 5 deletions src/engine/Input/Keyboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@ export class KeyEvent extends Events.GameEvent<any> {
}
}

export interface KeyboardOptions {
global?: GlobalEventHandlers,
grabWindowFocus: boolean
}

/**
* Provides keyboard support for Excalibur.
*/
Expand All @@ -212,7 +217,8 @@ export class Keyboard extends Class {
/**
* Initialize Keyboard event listeners
*/
init(global?: GlobalEventHandlers): void {
init(keyboardOptions: KeyboardOptions): void {
let { global, grabWindowFocus} = keyboardOptions;
if (!global) {
try {
// Try and listen to events on top window frame if within an iframe.
Expand All @@ -233,10 +239,14 @@ export class Keyboard extends Class {
// fallback to current frame
global = window;

Logger.getInstance().warn(
'Failed to bind to keyboard events to top frame. ' +
'If you are trying to embed Excalibur in a cross-origin iframe, keyboard events will not fire.'
);
// Workaround for iframes like for itch.io or codesandbox
// https://www.reddit.com/r/gamemaker/comments/kfs5cs/keyboard_inputs_no_longer_working_in_html5_game/
// https://forum.gamemaker.io/index.php?threads/solved-keyboard-issue-on-itch-io.87336/
if (grabWindowFocus) {
window.focus();
}

Logger.getInstance().warn('Excalibur might be in an iframe, in order to receive keyboard events it must be in focus');
}
}

Expand Down

0 comments on commit 8958619

Please sign in to comment.