Testing duplicate input blocking

This commit is contained in:
FlamedDogo99 2024-06-15 16:38:50 -06:00
parent 693b37b7ef
commit 5c6b049c39

View File

@ -12,13 +12,14 @@
// @grant unsafeWindow // @grant unsafeWindow
// ==/UserScript== // ==/UserScript==
// THIS IS LAZY AND DANGEROUS AND CAN EXPOSE USERSCRIPT INTERNALS SO PLEASE REMOVE // 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, the use of unsafeWindow should be safe to use.
// IN THE FUTURE, JUST INJECT A SCRIPT TAG
try { try {
unsafeWindow.console.log("UNSAFE WINDOW RAGGHHH") 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!")
alert("DANGER: This userscript is temporarily using unsafeWindow for testing purposes. 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
});
} catch { } catch {
Object.defineProperty(window, "unsafeWindow", { Object.defineProperty(window, "clientWindow", {
value: window value: window
}); });
} }
@ -35,10 +36,12 @@ 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!");
} }
unsafeWindow.keyboardEnabled = false; clientWindow.keyboardEnabled = false;
unsafeWindow.crouchLock = false; clientWindow.crouchLock = false;
unsafeWindow.sprintLock = false; clientWindow.sprintLock = false;
unsafeWindow.keyboardFix = false; // temporarily set to true until I can figure out whats going wrong with the event listener in charge of switching it clientWindow.keyboardFix = false;
clientWindow.inputFix = false;
clientWindow.blockNextInput = false;
// Used for changing touchmove events to mousemove events // Used for changing touchmove events to mousemove events
var previousTouchX = null; var previousTouchX = null;
var previousTouchY = null; var previousTouchY = null;
@ -48,10 +51,10 @@ function logManager() {
var self = this; var self = this;
self.init = function () { self.init = function () {
unsafeWindow.console.log('logmanager initialized'); clientWindow.console.log('logmanager initialized');
var old = unsafeWindow.console.log; var old = clientWindow.console.log;
self.logger = document.getElementById('log'); self.logger = document.getElementById('log');
unsafeWindow.console.log = function (message, options) { clientWindow.console.log = function (message, options) {
if (typeof message == 'object') { if (typeof message == 'object') {
self.logger.innerHTML = (JSON && JSON.stringify ? JSON.stringify(message) : message) + '<br />' + self.logger.innerHTML; self.logger.innerHTML = (JSON && JSON.stringify ? JSON.stringify(message) : message) + '<br />' + self.logger.innerHTML;
} else { } else {
@ -77,7 +80,7 @@ Object.defineProperty(EventTarget.prototype, "addEventListener", {
value: function (type, fn, ...rest) { value: function (type, fn, ...rest) {
if(type == 'keydown') { if(type == 'keydown') {
_addEventListener.call(this, type, function(...args) { _addEventListener.call(this, type, function(...args) {
if(!args[0].isValid && unsafeWindow.keyboardFix) { if(!args[0].isValid && clientWindow.keyboardFix) {
return; return;
} }
return fn.apply(this, args); return fn.apply(this, args);
@ -108,7 +111,7 @@ function keyEvent(name, state) {
which: charCode which: charCode
}); });
evt.isValid = true; // Disables fix for bad keyboard input evt.isValid = true; // Disables fix for bad keyboard input
unsafeWindow.dispatchEvent(evt); clientWindow.dispatchEvent(evt);
} }
function mouseEvent(number, state, canvas) { function mouseEvent(number, state, canvas) {
canvas.dispatchEvent(new PointerEvent(state, {"button": number})) canvas.dispatchEvent(new PointerEvent(state, {"button": number}))
@ -125,12 +128,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 window.fakelock, and unhides the touch controls // When requestpointerlock is called, this dispatches an event, saves the requested element to clientWindow.fakelock, and unhides the touch controls
unsafeWindow.fakelock = null; clientWindow.fakelock = null;
Object.defineProperty(Element.prototype, "requestPointerLock", { Object.defineProperty(Element.prototype, "requestPointerLock", {
value: function() { value: function() {
unsafeWindow.fakelock = this clientWindow.fakelock = this
document.dispatchEvent(new Event('pointerlockchange')); document.dispatchEvent(new Event('pointerlockchange'));
setButtonVisibility(true); setButtonVisibility(true);
return true return true
@ -138,16 +141,16 @@ Object.defineProperty(Element.prototype, "requestPointerLock", {
}); });
// Makes pointerLockElement return window.fakelock // Makes pointerLockElement return clientWindow.fakelock
Object.defineProperty(Document.prototype, "pointerLockElement", { Object.defineProperty(Document.prototype, "pointerLockElement", {
get: function() { get: function() {
return unsafeWindow.fakelock; return clientWindow.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() {
unsafeWindow.fakelock = null clientWindow.fakelock = null
document.dispatchEvent(new Event('pointerlockchange')); document.dispatchEvent(new Event('pointerlockchange'));
setButtonVisibility(false); setButtonVisibility(false);
return true return true
@ -155,23 +158,23 @@ Object.defineProperty(Document.prototype, "exitPointerLock", {
}); });
// FULLSCREEN // FULLSCREEN
unsafeWindow.fakefull = null; clientWindow.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() {
unsafeWindow.fakefull = this clientWindow.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 unsafeWindow.fakefull; return clientWindow.fakefull;
} }
}); });
Object.defineProperty(Document.prototype, "exitFullscreen", { Object.defineProperty(Document.prototype, "exitFullscreen", {
value: function() { value: function() {
unsafeWindow.fakefull = null clientWindow.fakefull = null
document.dispatchEvent(new Event('fullscreenchange')); document.dispatchEvent(new Event('fullscreenchange'));
return true return true
} }
@ -191,7 +194,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});
unsafeWindow.addEventListener('focus', function(e) { clientWindow.addEventListener('focus', function(e) {
setTimeout(() => { setTimeout(() => {
element.hidden = true; element.hidden = true;
element.style.display = "none"; element.style.display = "none";
@ -249,11 +252,11 @@ function createTouchButton(buttonClass, buttonDisplay, elementName) {
function toggleKeyboard() { function toggleKeyboard() {
const keyboardInput = document.getElementById('hiddenInput'); const keyboardInput = document.getElementById('hiddenInput');
if (unsafeWindow.keyboardEnabled) { if (clientWindow.keyboardEnabled) {
unsafeWindow.keyboardEnabled = false; clientWindow.keyboardEnabled = false;
keyboardInput.blur(); keyboardInput.blur();
} else { } else {
unsafeWindow.keyboardEnabled = true; clientWindow.keyboardEnabled = true;
keyboardInput.select(); keyboardInput.select();
} }
} }
@ -272,7 +275,7 @@ function insertCanvasElements() {
} }
e.movementX = touch.pageX - previousTouchX; e.movementX = touch.pageX - previousTouchX;
e.movementY = touch.pageY - previousTouchY; e.movementY = touch.pageY - previousTouchY;
var evt = unsafeWindow.fakelock ? new MouseEvent("mousemove", {movementX: e.movementX, movementY: e.movementY}) : new WheelEvent("wheel", {"wheelDeltaY": e.movementY}); var evt = clientWindow.fakelock ? new MouseEvent("mousemove", {movementX: e.movementX, movementY: e.movementY}) : new WheelEvent("wheel", {"wheelDeltaY": e.movementY});
canvas.dispatchEvent(evt); canvas.dispatchEvent(evt);
previousTouchX = touch.pageX; previousTouchX = touch.pageX;
previousTouchY = touch.pageY; previousTouchY = touch.pageY;
@ -283,7 +286,7 @@ function insertCanvasElements() {
previousTouchY = null; previousTouchY = null;
}, false) }, false)
//Updates button visibility on load //Updates button visibility on load
setButtonVisibility(unsafeWindow.fakelock != null); setButtonVisibility(clientWindow.fakelock != null);
// Adds all of the touch screen controls // Adds all of the touch screen controls
// Theres probably a better way to do this but this works for now // Theres probably a better way to do this but this works for now
let strafeRightButton = createTouchButton("strafeRightButton", "inGame", "div"); let strafeRightButton = createTouchButton("strafeRightButton", "inGame", "div");
@ -309,13 +312,13 @@ function insertCanvasElements() {
startTouchX = touch.pageX; startTouchX = touch.pageX;
} }
let movementX = touch.pageX - startTouchX; let movementX = touch.pageX - startTouchX;
if((movementX * 10) > unsafeWindow.innerHeight) { if((movementX * 10) > clientWindow.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 - unsafeWindow.innerHeight)) { } else if ((movementX * 10) < (0 - clientWindow.innerHeight)) {
strafeLeftButton.classList.add("active"); strafeLeftButton.classList.add("active");
strafeRightButton.classList.remove("active"); strafeRightButton.classList.remove("active");
keyEvent("a", "keydown"); keyEvent("a", "keydown");
@ -368,18 +371,18 @@ 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")
unsafeWindow.crouchLock = unsafeWindow.crouchLock ? null : false clientWindow.crouchLock = clientWindow.crouchLock ? null : false
crouchTimer = setTimeout(function(e) { crouchTimer = setTimeout(function(e) {
unsafeWindow.crouchLock = (unsafeWindow.crouchLock != null); clientWindow.crouchLock = (clientWindow.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(!unsafeWindow.crouchLock) { if(!clientWindow.crouchLock) {
keyEvent("shift", "keyup") keyEvent("shift", "keyup")
crouchButton.classList.remove('active'); crouchButton.classList.remove('active');
unsafeWindow.crouchLock = false clientWindow.crouchLock = false
} }
clearTimeout(crouchTimer); clearTimeout(crouchTimer);
}, false); }, false);
@ -408,13 +411,23 @@ function insertCanvasElements() {
e.stopImmediatePropagation(); e.stopImmediatePropagation();
e.preventDefault(true); e.preventDefault(true);
let inputData = e.data == null ? "delete" : e.data.slice(-1); let inputData = e.data == null ? "delete" : e.data.slice(-1);
unsafeWindow.console.log(`Received input by ${e.inputType}: ${e.data} -> ${inputData}`); if(!clientWindow.lastKey) { // If we get an event before any keys have been pressed, we know that setting the hiddenInput creates duplicate input events, so we can apply the fix
clientWindow.console.warn("Enabling blocking duplicate key events. Some functionality may be lost.")
// TEMP REMOVE
clientWindow.console.log("Enabling blocking duplicate key events. Some functionality may be lost.")
// TEMP
clientWindow.inputFix = true;
}
clientWindow.console.log(`Received input by ${e.inputType}: ${e.data} -> ${inputData}`);
unsafeWindow.lastKey = inputData hiddenInput.value = " ";
//hiddenInput.value = " "; if(clientWindow.keyboardFix) {
if(unsafeWindow.keyboardFix) { const sliceInputType = e.inputType.slice(0,1); // This is a really dumb way to do this because it's not future-proof, but its the easiest way to deal with Android
const sliceInputType = e.inputType.slice(0,1); // This is a really dumb way to do this because it's not future-proof
if(sliceInputType== 'i') { if(sliceInputType== 'i') {
const isDuplicate = (clientWindow.lastKey == inputData) && clientWindow.blockNextInput && clientWindow.inputFix;
if(isDuplicate) {
clientWindow.blockNextInput = false;
} else {
let isShift = (inputData.toLowerCase() != inputData); let isShift = (inputData.toLowerCase() != inputData);
if(isShift) { if(isShift) {
keyEvent("shift", "keydown") keyEvent("shift", "keydown")
@ -425,19 +438,27 @@ function insertCanvasElements() {
keyEvent(inputData, "keydown"); keyEvent(inputData, "keydown");
keyEvent(inputData, "keyup"); keyEvent(inputData, "keyup");
} }
clientWindow.blockNextInput = true;
}
} else if (sliceInputType == 'd') { } else if (sliceInputType == 'd') {
keyEvent("backspace", "keydown"); keyEvent("backspace", "keydown");
keyEvent("backspace", "keyup"); keyEvent("backspace", "keyup");
clientWindow.blockNextInput = false;
} }
} }
clientWindow.lastKey = inputData
}, false); }, false);
hiddenInput.addEventListener("keydown", function(e) { hiddenInput.addEventListener("keydown", function(e) {
if((e.keyCode == 229 || e.which == 229) && !unsafeWindow.keyboardFix) { if((e.keyCode == 229 || e.which == 229) && !clientWindow.keyboardFix) {
unsafeWindow.console.warn("Switching from keydown to input events due to invalid KeyboardEvent. Some functionality will be lost.") // TEMP REMOVE
unsafeWindow.keyboardFix = true; clientWindow.console.log("Switching from keydown to input events due to invalid KeyboardEvent. Some functionality will be lost.")
if(unsafeWindow.lastKey) { // TEMP
keyEvent(unsafeWindow.lastKey, "keydown"); clientWindow.console.warn("Switching from keydown to input events due to invalid KeyboardEvent. Some functionality will be lost.")
keyEvent(unsafeWindow.lastKey, "keyup"); clientWindow.keyboardFix = true;
if(clientWindow.lastKey) {
keyEvent(clientWindow.lastKey, "keydown");
keyEvent(clientWindow.lastKey, "keyup");
} }
} }
}, false); }, false);
@ -479,18 +500,18 @@ 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");
unsafeWindow.sprintLock = unsafeWindow.sprintLock ? null : false clientWindow.sprintLock = clientWindow.sprintLock ? null : false
sprintTimer = setTimeout(function(e) { sprintTimer = setTimeout(function(e) {
unsafeWindow.sprintLock = (unsafeWindow.sprintLock != null); clientWindow.sprintLock = (clientWindow.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(!unsafeWindow.sprintLock) { if(!clientWindow.sprintLock) {
keyEvent("r", "keyup"); keyEvent("r", "keyup");
sprintButton.classList.remove('active'); sprintButton.classList.remove('active');
unsafeWindow.sprintLock = false clientWindow.sprintLock = false
} }
clearTimeout(sprintTimer); clearTimeout(sprintTimer);
}, false); }, false);