Removed security issue

Completely forgot to remove the unsafeWindow craziness needed for testing v1.0.3.
It's been fixed now.
This commit is contained in:
FlamedDogo99 2024-06-25 21:43:23 -06:00
parent b2c577ad4f
commit b44dfed15c

View File

@ -6,25 +6,14 @@
// @downloadURL https://raw.githubusercontent.com/FlamedDogo99/EaglerMobile/main/eaglermobile.user.js // @downloadURL https://raw.githubusercontent.com/FlamedDogo99/EaglerMobile/main/eaglermobile.user.js
// @license Apache License 2.0 - http://www.apache.org/licenses/ // @license Apache License 2.0 - http://www.apache.org/licenses/
// @match https://eaglercraft.com/mc/* // @match https://eaglercraft.com/mc/*
// @version 3.0.5 // @version 3.0.5b
// @updateURL https://raw.githubusercontent.com/FlamedDogo99/EaglerMobile/main/eaglermobile.user.js // @updateURL https://raw.githubusercontent.com/FlamedDogo99/EaglerMobile/main/eaglermobile.user.js
// @run-at document-start // @run-at document-start
// @grant unsafeWindow // @grant none
// ==/UserScript== // ==/UserScript==
// This is generally a bad practice, but we need to run scripts in the main context before the DOM loads. Because we are only matching eaglercraft.com, unsafeWindow should be safe to use. // Removed brainless unsafeWindow
// If someone knows a better way of doing this, please create an issue console.log("Eagler Mobile v3.0.5b")
try {
unsafeWindow.console.warn("DANGER: This userscript is using unsafeWindow. Unsafe websites could potentially use this to gain access to data and other content that the browser normally wouldn't allow!")
Object.defineProperty(window, "clientWindow", {
value: unsafeWindow
}); // If this is a userscript, use unsafeWindow
} catch {
Object.defineProperty(window, "clientWindow", {
value: window
}); // If this is plain javascript, use window
}
clientWindow.console.log("Eagler Mobile v3.0.4")
// TODO: remove the mobile check is implement the dynamic enabling and disabling of individual features // TODO: remove the mobile check is implement the dynamic enabling and disabling of individual features
function isMobile() { function isMobile() {
try { try {
@ -38,13 +27,13 @@ if(!isMobile()) {
alert("WARNING: This script was created for mobile, and may break functionality in non-mobile browsers!"); alert("WARNING: This script was created for mobile, and may break functionality in non-mobile browsers!");
} }
// TODO: consolidate all of these into a single object? // TODO: consolidate all of these into a single object?
clientWindow.crouchLock = false; // Used for crouch mobile control window.crouchLock = false; // Used for crouch mobile control
clientWindow.sprintLock = false; // Used for sprint mobile control window.sprintLock = false; // Used for sprint mobile control
clientWindow.keyboardFix = false; // keyboardFix ? "Standard Keyboard" : "Compatibility Mode" window.keyboardFix = false; // keyboardFix ? "Standard Keyboard" : "Compatibility Mode"
clientWindow.inputFix = false; // If true, Duplicate Mode window.inputFix = false; // If true, Duplicate Mode
clientWindow.blockNextInput = false; // Used for Duplicate Mode window.blockNextInput = false; // Used for Duplicate Mode
clientWindow.hiddenInputFocused = false; // Used for keyboard display on mobile window.hiddenInputFocused = false; // Used for keyboard display on mobile
clientWindow.canvasTouchMode = 0; // Used for canvas touch handling window.canvasTouchMode = 0; // Used for canvas touch handling
/* /*
0 Idle 0 Idle
1 Touch initiated 1 Touch initiated
@ -53,12 +42,12 @@ clientWindow.canvasTouchMode = 0; // Used for canvas touch handling
4 Scroll 4 Scroll
5 Finished 5 Finished
*/ */
clientWindow.canvasTouchStartX = null; window.canvasTouchStartX = null;
clientWindow.canvasTouchStartY = null; window.canvasTouchStartY = null;
clientWindow.canvasTouchPreviousX = null; window.canvasTouchPreviousX = null;
clientWindow.canvasTouchPreviousY = null; window.canvasTouchPreviousY = null;
clientWindow.canvasPrimaryID = null; window.canvasPrimaryID = null;
clientWindow.buttonTouchStartX = null; window.buttonTouchStartX = null;
// charCodeAt is designed for unicode characters, and doesn't match the behavior of the keyCodes used by KeyboardEvents, thus necessitating this function // charCodeAt is designed for unicode characters, and doesn't match the behavior of the keyCodes used by KeyboardEvents, thus necessitating this function
String.prototype.toKeyCode = function() { String.prototype.toKeyCode = function() {
@ -72,7 +61,7 @@ Object.defineProperty(EventTarget.prototype, "addEventListener", {
value: function (type, fn, ...rest) { value: function (type, fn, ...rest) {
if(type == 'keydown') { // Check if a keydown event is being added if(type == 'keydown') { // Check if a keydown event is being added
_addEventListener.call(this, type, function(...args) { _addEventListener.call(this, type, function(...args) {
if(args[0].isTrusted && clientWindow.keyboardFix) { // When we are in compatibility mode, we ignore all trusted keyboard events if(args[0].isTrusted && window.keyboardFix) { // When we are in compatibility mode, we ignore all trusted keyboard events
return; return;
} }
return fn.apply(this, args); // Appends the rest of the function specified by addEventListener return fn.apply(this, args); // Appends the rest of the function specified by addEventListener
@ -102,7 +91,7 @@ function keyEvent(name, state) {
"keyCode": charCode, "keyCode": charCode,
"which": charCode "which": charCode
}); });
clientWindow.dispatchEvent(evt); window.dispatchEvent(evt);
} }
function mouseEvent(number, state, element, event = {"clientX": 0, "clientY" : 0, "screenX": 0, "screenY": 0}) { function mouseEvent(number, state, element, event = {"clientX": 0, "clientY" : 0, "screenX": 0, "screenY": 0}) {
element.dispatchEvent(new PointerEvent(state, { element.dispatchEvent(new PointerEvent(state, {
@ -126,12 +115,12 @@ function setButtonVisibility(pointerLocked) {
inMenuStyle.disabled = !pointerLocked; inMenuStyle.disabled = !pointerLocked;
} }
// POINTERLOCK // POINTERLOCK
// When requestpointerlock is called, this dispatches an event, saves the requested element to clientWindow.fakelock, and unhides the touch controls // When requestpointerlock is called, this dispatches an event, saves the requested element to window.fakelock, and unhides the touch controls
clientWindow.fakelock = null; window.fakelock = null;
Object.defineProperty(Element.prototype, "requestPointerLock", { Object.defineProperty(Element.prototype, "requestPointerLock", {
value: function() { value: function() {
clientWindow.fakelock = this window.fakelock = this
document.dispatchEvent(new Event('pointerlockchange')); document.dispatchEvent(new Event('pointerlockchange'));
setButtonVisibility(true); setButtonVisibility(true);
return true return true
@ -139,16 +128,16 @@ Object.defineProperty(Element.prototype, "requestPointerLock", {
}); });
// Makes pointerLockElement return clientWindow.fakelock // Makes pointerLockElement return window.fakelock
Object.defineProperty(Document.prototype, "pointerLockElement", { Object.defineProperty(Document.prototype, "pointerLockElement", {
get: function() { get: function() {
return clientWindow.fakelock; return window.fakelock;
} }
}); });
// When exitPointerLock is called, this dispatches an event, clears the // When exitPointerLock is called, this dispatches an event, clears the
Object.defineProperty(Document.prototype, "exitPointerLock", { Object.defineProperty(Document.prototype, "exitPointerLock", {
value: function() { value: function() {
clientWindow.fakelock = null window.fakelock = null
document.dispatchEvent(new Event('pointerlockchange')); document.dispatchEvent(new Event('pointerlockchange'));
setButtonVisibility(false); setButtonVisibility(false);
return true return true
@ -156,23 +145,23 @@ Object.defineProperty(Document.prototype, "exitPointerLock", {
}); });
// FULLSCREEN // FULLSCREEN
clientWindow.fakefull = null; window.fakefull = null;
// Stops the client from crashing when fullscreen is requested // Stops the client from crashing when fullscreen is requested
Object.defineProperty(Element.prototype, "requestFullscreen", { Object.defineProperty(Element.prototype, "requestFullscreen", {
value: function() { value: function() {
clientWindow.fakefull = this window.fakefull = this
document.dispatchEvent(new Event('fullscreenchange')); document.dispatchEvent(new Event('fullscreenchange'));
return true return true
} }
}); });
Object.defineProperty(document, "fullscreenElement", { Object.defineProperty(document, "fullscreenElement", {
get: function() { get: function() {
return clientWindow.fakefull; return window.fakefull;
} }
}); });
Object.defineProperty(Document.prototype, "exitFullscreen", { Object.defineProperty(Document.prototype, "exitFullscreen", {
value: function() { value: function() {
clientWindow.fakefull = null window.fakefull = null
document.dispatchEvent(new Event('fullscreenchange')); document.dispatchEvent(new Event('fullscreenchange'));
return true return true
} }
@ -192,7 +181,7 @@ document.createElement = function(type, ignore) {
element.hidden = true; element.hidden = true;
element.style.display = "none"; element.style.display = "none";
}, {passive: false, once: true}); }, {passive: false, once: true});
clientWindow.addEventListener('focus', function(e) { window.addEventListener('focus', function(e) {
setTimeout(() => { setTimeout(() => {
element.hidden = true; element.hidden = true;
element.style.display = "none"; element.style.display = "none";
@ -255,29 +244,29 @@ function insertCanvasElements() {
// Translates touchmove events to mousemove events when inGame, and touchmove events to wheele events when inMenu // Translates touchmove events to mousemove events when inGame, and touchmove events to wheele events when inMenu
var canvas = document.querySelector('canvas'); var canvas = document.querySelector('canvas');
canvas.addEventListener("touchstart", function(e) { canvas.addEventListener("touchstart", function(e) {
if(clientWindow.canvasTouchMode < 2) { // If a touch is initiated but not assigned if(window.canvasTouchMode < 2) { // If a touch is initiated but not assigned
if(clientWindow.canvasPrimaryID == null) { if(window.canvasPrimaryID == null) {
clientWindow.canvasTouchMode = 1; window.canvasTouchMode = 1;
const primaryTouch = e.changedTouches[0]; const primaryTouch = e.changedTouches[0];
clientWindow.canvasPrimaryID = primaryTouch.identifier window.canvasPrimaryID = primaryTouch.identifier
canvasTouchStartX = primaryTouch.clientX; canvasTouchStartX = primaryTouch.clientX;
canvasTouchStartY = primaryTouch.clientY; canvasTouchStartY = primaryTouch.clientY;
canvasTouchPreviousX = canvasTouchStartX canvasTouchPreviousX = canvasTouchStartX
canvasTouchPreviousY = canvasTouchStartY canvasTouchPreviousY = canvasTouchStartY
clientWindow.touchTimer = setTimeout(function(e) { window.touchTimer = setTimeout(function(e) {
// If our touch is still set to initiaited, set it to secondary touch // If our touch is still set to initiaited, set it to secondary touch
if(clientWindow.canvasTouchMode == 1) { if(window.canvasTouchMode == 1) {
clientWindow.canvasTouchMode = 3; window.canvasTouchMode = 3;
mouseEvent(2, "mousedown", canvas, primaryTouch) mouseEvent(2, "mousedown", canvas, primaryTouch)
if(clientWindow.fakelock) { // We only dispatch mouseup inGame because we want to be able to click + drag items in GUI's if(window.fakelock) { // We only dispatch mouseup inGame because we want to be able to click + drag items in GUI's
mouseEvent(2, "mouseup", canvas, primaryTouch) mouseEvent(2, "mouseup", canvas, primaryTouch)
} }
} }
}, 300); }, 300);
} else if(clientWindow.canvasTouchMode == 1 && !clientWindow.fakelock) { // If we already have a primary touch, it means we're using two fingers } else if(window.canvasTouchMode == 1 && !window.fakelock) { // If we already have a primary touch, it means we're using two fingers
clientWindow.canvasTouchMode = 4; window.canvasTouchMode = 4;
clearTimeout(clientWindow.crouchTimer); // TODO: Find out why this isn't redudnant clearTimeout(window.crouchTimer); // TODO: Find out why this isn't redudnant
} }
} }
}, false); }, false);
@ -286,7 +275,7 @@ function insertCanvasElements() {
e.preventDefault() // Prevents window zoom when using two fingers e.preventDefault() // Prevents window zoom when using two fingers
var primaryTouch; var primaryTouch;
for (let touchIndex = 0; touchIndex < e.targetTouches.length; touchIndex++) { // Iterate through our touches to find a touch event matching the primary touch ID for (let touchIndex = 0; touchIndex < e.targetTouches.length; touchIndex++) { // Iterate through our touches to find a touch event matching the primary touch ID
if(e.targetTouches[touchIndex].identifier == clientWindow.canvasPrimaryID) { if(e.targetTouches[touchIndex].identifier == window.canvasPrimaryID) {
primaryTouch = e.targetTouches[touchIndex]; primaryTouch = e.targetTouches[touchIndex];
break; break;
} }
@ -297,16 +286,16 @@ function insertCanvasElements() {
primaryTouch.squaredNorm = (primaryTouch.distanceX * primaryTouch.distanceX) + (primaryTouch.distanceY * primaryTouch.distanceY); primaryTouch.squaredNorm = (primaryTouch.distanceX * primaryTouch.distanceX) + (primaryTouch.distanceY * primaryTouch.distanceY);
primaryTouch.movementX = primaryTouch.clientX - canvasTouchPreviousX; primaryTouch.movementX = primaryTouch.clientX - canvasTouchPreviousX;
primaryTouch.movementY = primaryTouch.clientY - canvasTouchPreviousY; primaryTouch.movementY = primaryTouch.clientY - canvasTouchPreviousY;
if(clientWindow.canvasTouchMode == 1) { // If the primary touch is still only initiated if(window.canvasTouchMode == 1) { // If the primary touch is still only initiated
if (primaryTouch.squaredNorm > 25) { // If our touch becomes a touch + drag if (primaryTouch.squaredNorm > 25) { // If our touch becomes a touch + drag
clearTimeout(clientWindow.crouchTimer); clearTimeout(window.crouchTimer);
clientWindow.canvasTouchMode = 2; window.canvasTouchMode = 2;
if(!clientWindow.fakelock) { // When we're inGame, we don't want to be placing blocks when we are moving the camera around if(!window.fakelock) { // When we're inGame, we don't want to be placing blocks when we are moving the camera around
mouseEvent(1, "mousedown", canvas, primaryTouch); mouseEvent(1, "mousedown", canvas, primaryTouch);
} }
} }
} else { // If our touch is primary, secondary, scroll or finished } else { // If our touch is primary, secondary, scroll or finished
if(clientWindow.canvasTouchMode == 4) { // If our touch is scrolling if(window.canvasTouchMode == 4) { // If our touch is scrolling
wheelEvent(canvas, primaryTouch.movementY) wheelEvent(canvas, primaryTouch.movementY)
} else { } else {
canvas.dispatchEvent(new MouseEvent("mousemove", { canvas.dispatchEvent(new MouseEvent("mousemove", {
@ -326,27 +315,27 @@ function insertCanvasElements() {
function canvasTouchEnd(e) { function canvasTouchEnd(e) {
for(let touchIndex = 0; touchIndex < e.changedTouches.length; touchIndex++) { // Iterate through changed touches to find primary touch for(let touchIndex = 0; touchIndex < e.changedTouches.length; touchIndex++) { // Iterate through changed touches to find primary touch
if(e.changedTouches[touchIndex].identifier == clientWindow.canvasPrimaryID) { if(e.changedTouches[touchIndex].identifier == window.canvasPrimaryID) {
let primaryTouch = e.changedTouches[touchIndex] let primaryTouch = e.changedTouches[touchIndex]
// When any of the controlling fingers go away, we want to wait until we aren't receiving any other touch events // When any of the controlling fingers go away, we want to wait until we aren't receiving any other touch events
if(clientWindow.canvasTouchMode == 2) { if(window.canvasTouchMode == 2) {
mouseEvent(1, "mouseup", canvas, primaryTouch) mouseEvent(1, "mouseup", canvas, primaryTouch)
} else if (clientWindow.canvasTouchMode == 3) { } else if (window.canvasTouchMode == 3) {
e.preventDefault(); // This prevents some mobile devices from dispatching a mousedown + mouseup event after a touch is ended e.preventDefault(); // This prevents some mobile devices from dispatching a mousedown + mouseup event after a touch is ended
mouseEvent(2, "mouseup", canvas, primaryTouch) mouseEvent(2, "mouseup", canvas, primaryTouch)
} }
clientWindow.canvasTouchMode = 5; window.canvasTouchMode = 5;
} }
} }
if(e.targetTouches.length == 0) { // We want to wait until all fingers are off the canvas before we reset for the next cycle if(e.targetTouches.length == 0) { // We want to wait until all fingers are off the canvas before we reset for the next cycle
clientWindow.canvasTouchMode = 0; window.canvasTouchMode = 0;
clientWindow.canvasPrimaryID = null; window.canvasPrimaryID = null;
} }
} }
canvas.addEventListener("touchend", canvasTouchEnd, false); canvas.addEventListener("touchend", canvasTouchEnd, false);
canvas.addEventListener("touchcancel", canvasTouchEnd, false); // TODO: Find out why this is different than touchend canvas.addEventListener("touchcancel", canvasTouchEnd, false); // TODO: Find out why this is different than touchend
setButtonVisibility(clientWindow.fakelock != null); //Updates our mobile controls when the canvas finally loads setButtonVisibility(window.fakelock != null); //Updates our mobile controls when the canvas finally loads
// All of the touch buttons // All of the touch buttons
let strafeRightButton = createTouchButton("strafeRightButton", "inGame", "div"); let strafeRightButton = createTouchButton("strafeRightButton", "inGame", "div");
strafeRightButton.style.cssText = "left:20vh;bottom:20vh;" strafeRightButton.style.cssText = "left:20vh;bottom:20vh;"
@ -371,13 +360,13 @@ function insertCanvasElements() {
buttonTouchStartX = touch.pageX; buttonTouchStartX = touch.pageX;
} }
let movementX = touch.pageX - buttonTouchStartX; let movementX = touch.pageX - buttonTouchStartX;
if((movementX * 10) > clientWindow.innerHeight) { if((movementX * 10) > window.innerHeight) {
strafeRightButton.classList.add("active"); strafeRightButton.classList.add("active");
strafeLeftButton.classList.remove("active"); strafeLeftButton.classList.remove("active");
keyEvent("d", "keydown"); keyEvent("d", "keydown");
keyEvent("a", "keyup"); keyEvent("a", "keyup");
} else if ((movementX * 10) < (0 - clientWindow.innerHeight)) { } else if ((movementX * 10) < (0 - window.innerHeight)) {
strafeLeftButton.classList.add("active"); strafeLeftButton.classList.add("active");
strafeRightButton.classList.remove("active"); strafeRightButton.classList.remove("active");
keyEvent("a", "keydown"); keyEvent("a", "keydown");
@ -430,20 +419,20 @@ function insertCanvasElements() {
crouchButton.style.cssText = "left:10vh;bottom:10vh;" crouchButton.style.cssText = "left:10vh;bottom:10vh;"
crouchButton.addEventListener("touchstart", function(e){ crouchButton.addEventListener("touchstart", function(e){
keyEvent("shift", "keydown") keyEvent("shift", "keydown")
clientWindow.crouchLock = clientWindow.crouchLock ? null : false window.crouchLock = window.crouchLock ? null : false
clientWindow.crouchTimer = setTimeout(function(e) { // Allows us to lock the button after a long press window.crouchTimer = setTimeout(function(e) { // Allows us to lock the button after a long press
clientWindow.crouchLock = (clientWindow.crouchLock != null); window.crouchLock = (window.crouchLock != null);
crouchButton.classList.toggle('active'); crouchButton.classList.toggle('active');
}, 1000); }, 1000);
}, false); }, false);
crouchButton.addEventListener("touchend", function(e) { crouchButton.addEventListener("touchend", function(e) {
if(!clientWindow.crouchLock) { if(!window.crouchLock) {
keyEvent("shift", "keyup") keyEvent("shift", "keyup")
crouchButton.classList.remove('active'); crouchButton.classList.remove('active');
clientWindow.crouchLock = false window.crouchLock = false
} }
clearTimeout(clientWindow.crouchTimer); clearTimeout(window.crouchTimer);
}, false); }, false);
document.body.appendChild(crouchButton); document.body.appendChild(crouchButton);
let inventoryButton = createTouchButton("inventoryButton", "inGame"); let inventoryButton = createTouchButton("inventoryButton", "inGame");
@ -478,7 +467,7 @@ function insertCanvasElements() {
// Additionally, programmatically setting the input's text contents (BECAUSE ANDROID IGNORES PREVENTDEFAULT AGHHHHH) dispatches a repeat of the previous event // Additionally, programmatically setting the input's text contents (BECAUSE ANDROID IGNORES PREVENTDEFAULT AGHHHHH) dispatches a repeat of the previous event
// Luckily, we can check if this happens when we first create the input, which necessitates the third mode: // Luckily, we can check if this happens when we first create the input, which necessitates the third mode:
// 3) Duplicate mode: // 3) Duplicate mode:
// If we are getting duplicate inputs, this mode ignores every other input if it matches the state saved in clientWindow.previousKey // If we are getting duplicate inputs, this mode ignores every other input if it matches the state saved in window.previousKey
// If users make it to this mode and still are having issues, it may be best just to remove support for their device // If users make it to this mode and still are having issues, it may be best just to remove support for their device
// ---Input Handling--- // ---Input Handling---
let hiddenInput = document.createElement('input', true); let hiddenInput = document.createElement('input', true);
@ -489,20 +478,20 @@ function insertCanvasElements() {
e.stopImmediatePropagation(); // Android ignores this and the prevent default, so this will probably be removed in the future e.stopImmediatePropagation(); // Android ignores this and the prevent default, so this will probably be removed in the future
e.preventDefault(true); // We pass a value because we've hijacked the prevent default function to have a "should bypass" boolean value e.preventDefault(true); // We pass a value because we've hijacked the prevent default function to have a "should bypass" boolean value
let inputData = (e.inputType == "insertLineBreak") ? "return" : (e.data == null ? "delete" : e.data.slice(-1)); // Saves the last key press. let inputData = (e.inputType == "insertLineBreak") ? "return" : (e.data == null ? "delete" : e.data.slice(-1)); // Saves the last key press.
if(!clientWindow.lastKey) { // When we first set hiddenInput's text contents to " " we can use this to check if Duplicate Mode is needed if(!window.lastKey) { // When we first set hiddenInput's text contents to " " we can use this to check if Duplicate Mode is needed
clientWindow.console.warn("Enabling blocking duplicate key events. Some functionality may be lost.") window.console.warn("Enabling blocking duplicate key events. Some functionality may be lost.")
clientWindow.inputFix = true; window.inputFix = true;
} }
if(clientWindow.keyboardFix) { if(window.keyboardFix) {
if(e.inputType == "insertLineBreak") { // Detects return key press if(e.inputType == "insertLineBreak") { // Detects return key press
keyEvent("enter", "keydown"); keyEvent("enter", "keydown");
keyEvent("enter", "keyup"); keyEvent("enter", "keyup");
} else { } else {
const sliceInputType = e.inputType.slice(0,1); // Android doesn't constiently dispatch the correct inputType, but most of them either start with i for insert or d for delete, so this dumb solution should be good enough. const sliceInputType = e.inputType.slice(0,1); // Android doesn't constiently dispatch the correct inputType, but most of them either start with i for insert or d for delete, so this dumb solution should be good enough.
if(sliceInputType== 'i' && e.data) { // Android sometimes always dispatches insertCompositionText inputTypes, so checking that e.data isn't null is necessary if(sliceInputType== 'i' && e.data) { // Android sometimes always dispatches insertCompositionText inputTypes, so checking that e.data isn't null is necessary
const isDuplicate = (clientWindow.lastKey == inputData) && clientWindow.blockNextInput && clientWindow.inputFix; const isDuplicate = (window.lastKey == inputData) && window.blockNextInput && window.inputFix;
if(isDuplicate) { // If our key press matches the last unblocked key press and we are in duplicaye mode, ignore the input if(isDuplicate) { // If our key press matches the last unblocked key press and we are in duplicaye mode, ignore the input
clientWindow.blockNextInput = false; window.blockNextInput = false;
} else { } else {
let isShift = (inputData.toLowerCase() != inputData); let isShift = (inputData.toLowerCase() != inputData);
if(isShift) { // The Eaglerclient only uses e.key, e.keyCode and e.which, so we have to dispatch the shift key event separately if(isShift) { // The Eaglerclient only uses e.key, e.keyCode and e.which, so we have to dispatch the shift key event separately
@ -514,16 +503,16 @@ function insertCanvasElements() {
keyEvent(inputData, "keydown"); keyEvent(inputData, "keydown");
keyEvent(inputData, "keyup"); keyEvent(inputData, "keyup");
} }
clientWindow.blockNextInput = true; window.blockNextInput = true;
} }
} else if (sliceInputType == 'd' || !e.data) { } else if (sliceInputType == 'd' || !e.data) {
keyEvent("backspace", "keydown"); keyEvent("backspace", "keydown");
keyEvent("backspace", "keyup"); keyEvent("backspace", "keyup");
clientWindow.blockNextInput = false; // If we delete a character, there couldn't be a duplicate of the previous key press window.blockNextInput = false; // If we delete a character, there couldn't be a duplicate of the previous key press
} }
} }
} }
clientWindow.lastKey = inputData // Saves the last key pressed window.lastKey = inputData // Saves the last key pressed
hiddenInput.value = " " //This previously allowed us to have a character to delete, but beforeinput doesn't require this. This does allow us to check wether Duplicate Mode is necessary though hiddenInput.value = " " //This previously allowed us to have a character to delete, but beforeinput doesn't require this. This does allow us to check wether Duplicate Mode is necessary though
@ -534,17 +523,17 @@ function insertCanvasElements() {
} }
}, false); }, false);
hiddenInput.addEventListener("keydown", function(e) { // Enables Compatibility Mode if we receive an invalid key press event hiddenInput.addEventListener("keydown", function(e) { // Enables Compatibility Mode if we receive an invalid key press event
if((e.keyCode == 229 || e.which == 229) && !clientWindow.keyboardFix) { if((e.keyCode == 229 || e.which == 229) && !window.keyboardFix) {
clientWindow.console.warn("Switching from keydown to input events due to invalid KeyboardEvent. Some functionality will be lost.") window.console.warn("Switching from keydown to input events due to invalid KeyboardEvent. Some functionality will be lost.")
clientWindow.keyboardFix = true; window.keyboardFix = true;
if(clientWindow.lastKey) { // Resend the last saved key press (which is being tracked by the beforeinput event listener) so the transition to Compatibility Mode isn't noticeable if(window.lastKey) { // Resend the last saved key press (which is being tracked by the beforeinput event listener) so the transition to Compatibility Mode isn't noticeable
keyEvent(clientWindow.lastKey, "keydown"); keyEvent(window.lastKey, "keydown");
keyEvent(clientWindow.lastKey, "keyup"); keyEvent(window.lastKey, "keyup");
} }
} }
}, false); }, false);
hiddenInput.addEventListener("blur", function(e) { // Updates clientWindow.hiddenInputFocused to reflect the actual state of the focus hiddenInput.addEventListener("blur", function(e) { // Updates window.hiddenInputFocused to reflect the actual state of the focus
clientWindow.hiddenInputFocused = false; window.hiddenInputFocused = false;
}); });
document.body.appendChild(hiddenInput); document.body.appendChild(hiddenInput);
let keyboardButton = createTouchButton("keyboardButton", "inMenu"); let keyboardButton = createTouchButton("keyboardButton", "inMenu");
@ -554,11 +543,11 @@ function insertCanvasElements() {
}, false); }, false);
keyboardButton.addEventListener("touchend", function(e){ keyboardButton.addEventListener("touchend", function(e){
e.preventDefault(); e.preventDefault();
if(clientWindow.hiddenInputFocused) { if(window.hiddenInputFocused) {
hiddenInput.blur() hiddenInput.blur()
} else { } else {
hiddenInput.select() hiddenInput.select()
clientWindow.hiddenInputFocused = true; window.hiddenInputFocused = true;
} }
}, false); }, false);
document.body.appendChild(keyboardButton); document.body.appendChild(keyboardButton);
@ -594,20 +583,20 @@ function insertCanvasElements() {
sprintButton.style.cssText = "right:0vh;bottom:10vh;" sprintButton.style.cssText = "right:0vh;bottom:10vh;"
sprintButton.addEventListener("touchstart", function(e) { sprintButton.addEventListener("touchstart", function(e) {
keyEvent("r", "keydown"); keyEvent("r", "keydown");
clientWindow.sprintLock = clientWindow.sprintLock ? null : false window.sprintLock = window.sprintLock ? null : false
clientWindow.sprintTimer = setTimeout(function(e) { window.sprintTimer = setTimeout(function(e) {
clientWindow.sprintLock = (clientWindow.sprintLock != null); window.sprintLock = (window.sprintLock != null);
sprintButton.classList.toggle('active'); sprintButton.classList.toggle('active');
}, 1000); }, 1000);
}, false); }, false);
sprintButton.addEventListener("touchend", function(e) { sprintButton.addEventListener("touchend", function(e) {
if(!clientWindow.sprintLock) { if(!window.sprintLock) {
keyEvent("r", "keyup"); keyEvent("r", "keyup");
sprintButton.classList.remove('active'); sprintButton.classList.remove('active');
clientWindow.sprintLock = false window.sprintLock = false
} }
clearTimeout(clientWindow.sprintTimer); clearTimeout(window.sprintTimer);
}, false); }, false);
document.body.appendChild(sprintButton); document.body.appendChild(sprintButton);
let pauseButton = createTouchButton("pauseButton", "inGame"); let pauseButton = createTouchButton("pauseButton", "inGame");