Updated from userscript

This commit is contained in:
FlamedDogo99 2024-06-06 09:49:08 -06:00
parent 5a179285e5
commit 2ed6365c42

View File

@ -1,20 +1,14 @@
// ==UserScript== // ==UserScript==
// @name Eagler Mobile // @name Eagler Mobile
// @description Allows eaglercraft to run on mobile, adds touch controls, and fixes a few mobile-related crashes // @description Allows eaglercraft to run on mobile, adds touch controls, and fixes a few mobile-related crashes
//
// @author FlamedDogo99 // @author FlamedDogo99
// @namespace http://github.com/FlamedDogo99 // @namespace http://github.com/FlamedDogo99
// @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 2.12
// @version 2.1
// @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
// @unwrap
// ==/UserScript== // ==/UserScript==
@ -29,26 +23,56 @@ function isMobile() {
if(!isMobile()) { 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!");
} }
window.keyboardEnabled = false;
window.crouchLock = false; window.crouchLock = false;
window.sprintLock = false; window.sprintLock = 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;
var startTouchX = null; var startTouchX = null;
// Key and mouse events // better charCodeAt function
function keyEvent(name, state) { String.prototype.toKeyCode = function() {
const keyName = name.toUpperCase().charCodeAt(0) const keyCodeList = {"0": 48, "1": 49, "2": 50, "3": 51, "4": 52, "5": 53, "6": 54, "7": 55, "8": 56, "9": 57, "backspace": 8, "tab": 9, "enter": 13, "shift": 16, "ctrl": 17, "alt": 18, "pause_break": 19, "caps_lock": 20, "escape": 27, " ": 32, "page_up": 33, "page_down": 34, "end": 35, "home": 36, "left_arrow": 37, "up_arrow": 38, "right_arrow": 39, "down_arrow": 40, "insert": 45, "delete": 46, "a": 65, "b": 66, "c": 67, "d": 68, "e": 69, "f": 70, "g": 71, "h": 72, "i": 73, "j": 74, "k": 75, "l": 76, "m": 77, "n": 78, "o": 79, "p": 80, "q": 81, "r": 82, "s": 83, "t": 84, "u": 85, "v": 86, "w": 87, "x": 88, "y": 89, "z": 90, "left_window_key": 91, "right_window_key": 92, "select_key": 93, "numpad_0": 96, "numpad_1": 97, "numpad_2": 98, "numpad_3": 99, "numpad_4": 100, "numpad_5": 101, "numpad_6": 102, "numpad_7": 103, "numpad_8": 104, "numpad_9": 105, "*": 106, "+": 107, "-": 109, ".": 110, "/": 111, "f1": 112, "f2": 113, "f3": 114, "f4": 115, "f5": 116, "f6": 117, "f7": 118, "f8": 119, "f9": 120, "f10": 121, "f11": 122, "f12": 123, "num_lock": 144, "scroll_lock": 145, ";": 186, "=": 187, ",": 188, "-": 189, ".": 190, "/": 191, "`": 192, "[": 219, "\\": 220, "]": 221, "\"": 222};
window.dispatchEvent(new KeyboardEvent(state, { return keyCodeList[this];
key: name,
keyCode: keyName,
which: keyName
}));
} }
function shiftKeyEvent(state) { // Ignores keydown events that don't have the isValid parameter set to true
window.dispatchEvent(new KeyboardEvent(state, { const _addEventListener = EventTarget.prototype.addEventListener;
keyCode: 16, Object.defineProperty(EventTarget.prototype, "addEventListener", {
which: 16 value: function (type, fn, ...rest) {
})); if(type == 'keydown') {
_addEventListener.call(this, type, function(...args) {
if(!args[0].isValid) {
return;
}
return fn.apply(this, args);
}, ...rest);
} else {
_addEventListener.call(this, type, fn, ...rest);
}
}
});
// Allows typing in #hiddenInput
const _preventDefault = Event.prototype.preventDefault;
Event.prototype.preventDefault = function() {
if(document.activeElement.id != "hiddenInput") {
this._preventDefault = _preventDefault;
this._preventDefault();
}
}
// Key and mouse events
// Note: the client must have the key, keyCode, and which parameters defined or it will crash
// Note: for text inputs, the client only reads from the "key" paramater
// * an exception to this appears to be the shift and backspace key
// Note: for inGame inputs, the client only reads from the "keyCode character"
function keyEvent(name, state) {
const charCode = name.toKeyCode();
let evt = new KeyboardEvent(state, {
key: name,
keyCode: charCode,
which: charCode
});
evt.isValid = true; // Disables fix for bad keyboard input
window.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}))
@ -68,55 +92,62 @@ function setButtonVisibility(pointerLocked) {
// 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 window.fakelock, and unhides the touch controls
window.fakelock = null; window.fakelock = null;
Element.prototype.requestPointerLock = function() { Object.defineProperty(Element.prototype, "requestPointerLock", {
value: function() {
window.fakelock = this window.fakelock = this
document.dispatchEvent(new Event('pointerlockchange')); document.dispatchEvent(new Event('pointerlockchange'));
console.log("requested pointerlock")
setButtonVisibility(true); setButtonVisibility(true);
return true return true
} }
});
// Makes pointerLockElement return window.fakelock // Makes pointerLockElement return window.fakelock
Object.defineProperty(document, "pointerLockElement", { Object.defineProperty(Document.prototype, "pointerLockElement", {
get: function() { get: function() {
return window.fakelock; return window.fakelock;
} }
}); });
// When exitPointerLock is called, this dispatches an event, clears the // When exitPointerLock is called, this dispatches an event, clears the
document.exitPointerLock = function() { Object.defineProperty(Document.prototype, "exitPointerLock", {
value: function() {
window.fakelock = null window.fakelock = null
document.dispatchEvent(new Event('pointerlockchange')); document.dispatchEvent(new Event('pointerlockchange'));
setButtonVisibility(false); setButtonVisibility(false);
return true return true
} }
});
// FULLSCREEN // FULLSCREEN
window.fakefull = null; window.fakefull = null;
// Stops the client from crashing when fullscreen is requested // Stops the client from crashing when fullscreen is requested
Element.prototype.requestFullscreen = function() { Object.defineProperty(Element.prototype, "requestFullscreen", {
value: function() {
window.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 window.fakefull; return window.fakefull;
} }
}); });
document.exitFullscreen = function() { Object.defineProperty(Document.prototype, "exitFullscreen", {
value: function() {
window.fakefull = null window.fakefull = null
document.dispatchEvent(new Event('fullscreenchange')); document.dispatchEvent(new Event('fullscreenchange'));
return true return true
} }
});
// FILE UPLOADING // FILE UPLOADING
// Safari doesn't recognize the element.click() used to display the file uplaoder as an action performed by the user, so it ignores it. // Safari doesn't recognize the element.click() used to display the file uploader as an action performed by the user, so it ignores it.
// This hijacks the element.createElement() function to add the file upload to the DOM, so the user can manually press the button again. // This hijacks the element.createElement() function to add the file upload to the DOM, so the user can manually press the button again.
var oldCreate = document.createElement; const _createElement = document.createElement;
document.createElement = function(type, ignore) { document.createElement = function(type, ignore) {
this.oldCreate = oldCreate; this._createElement = _createElement;
let element = this.oldCreate(type); let element = this._createElement(type);
if(type == "input" && !ignore) { if(type == "input" && !ignore) {
let newElement = document.querySelector('input'); let newElement = document.querySelector('input');
if(!newElement) { if(!newElement) {
@ -131,7 +162,7 @@ document.createElement = function(type, ignore) {
newElement.hidden = false; newElement.hidden = false;
return newElement; return newElement;
} }
return this.oldCreate(type); return this._createElement(type);
} }
// Lazy way to hide touch controls through CSS. // Lazy way to hide touch controls through CSS.
@ -179,6 +210,17 @@ function createTouchButton(buttonClass, buttonDisplay, elementName) {
return touchButton; return touchButton;
} }
function toggleKeyboard() {
const keyboardInput = document.getElementById('hiddenInput');
if (window.keyboardEnabled) {
window.keyboardEnabled = false;
keyboardInput.blur();
} else {
window.keyboardEnabled = true;
keyboardInput.select();
}
}
waitForElm('canvas').then(() => {insertCanvasElements()}); waitForElm('canvas').then(() => {insertCanvasElements()});
function insertCanvasElements() { 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
@ -288,7 +330,7 @@ function insertCanvasElements() {
let crouchButton = createTouchButton("crouchButton", "inGame"); let crouchButton = createTouchButton("crouchButton", "inGame");
crouchButton.style.cssText = "left:10vh;bottom:10vh;" crouchButton.style.cssText = "left:10vh;bottom:10vh;"
crouchButton.addEventListener("touchstart", function(e){ crouchButton.addEventListener("touchstart", function(e){
shiftKeyEvent("keydown"); keyEvent("shift", "keydown")
window.crouchLock = window.crouchLock ? null : false window.crouchLock = window.crouchLock ? null : false
crouchTimer = setTimeout(function(e) { crouchTimer = setTimeout(function(e) {
window.crouchLock = (window.crouchLock != null); window.crouchLock = (window.crouchLock != null);
@ -298,7 +340,7 @@ function insertCanvasElements() {
crouchButton.addEventListener("touchend", function(e) { crouchButton.addEventListener("touchend", function(e) {
if(!window.crouchLock) { if(!window.crouchLock) {
shiftKeyEvent("keyup"); keyEvent("shift", "keyup")
crouchButton.classList.remove('active'); crouchButton.classList.remove('active');
window.crouchLock = false window.crouchLock = false
} }
@ -312,18 +354,40 @@ function insertCanvasElements() {
document.body.appendChild(inventoryButton); document.body.appendChild(inventoryButton);
let exitButton = createTouchButton("exitButton", "inMenu"); let exitButton = createTouchButton("exitButton", "inMenu");
exitButton.style.cssText = "top: 0vh; margin: auto; left: 0vh; right:8vh; width: 8vh; height: 8vh;" exitButton.style.cssText = "top: 0vh; margin: auto; left: 0vh; right:8vh; width: 8vh; height: 8vh;"
exitButton.addEventListener("touchstart", function(e){keyEvent("À", "keydown")}, false); exitButton.addEventListener("touchstart", function(e){keyEvent("`", "keyup")}, false);
exitButton.addEventListener("touchend", function(e){keyEvent("À", "keyup")}, false); exitButton.addEventListener("touchend", function(e){keyEvent("`", "keyup")}, false);
document.body.appendChild(exitButton); document.body.appendChild(exitButton);
// input for keyboard button // input for keyboard button
let hiddenInput = document.createElement('input', true); let hiddenInput = document.createElement('input', true);
hiddenInput.id = "hiddenInput" hiddenInput.id = "hiddenInput"
hiddenInput.style.cssText = "opacity:0;z-index:-99999"; hiddenInput.classList.add("inMenu")
// We are hiding the text input behind button because opacity was causing problems.
hiddenInput.style.cssText = "position:absolute;top: 0vh; margin: auto; left: 8vh; right:0vh; width: 8vh; height: 8vh;font-size:20px;z-index:-10;color: transparent;text-shadow: 0 0 0 black;";
hiddenInput.value = " " //Allows delete to be detected before input is changed
hiddenInput.addEventListener("input", function(e) {
hiddenInput.value = " "; // We need a character to detect deleting
if(e.inputType == 'insertText') {
let inputData = e.data.charAt(0);
let isShift = (inputData.toLowerCase() != inputData);
if(isShift) {
keyEvent("shift", "keydown")
keyEvent(inputData, "keydown");
keyEvent(inputData, "keyup");
keyEvent("shift", "keyup")
} else {
keyEvent(inputData, "keydown");
keyEvent(inputData, "keyup");
}
} else if (e.inputType == 'deleteContentForward' || e.inputType == 'deleteContentBackward') {
keyEvent("backspace", "keydown")
keyEvent("backspace", "keyup")
}
}, false);
document.body.appendChild(hiddenInput); document.body.appendChild(hiddenInput);
let keyboardButton = createTouchButton("keyboardButton", "inMenu"); let keyboardButton = createTouchButton("keyboardButton", "inMenu");
keyboardButton.style.cssText = "top: 0vh; margin: auto; left: 8vh; right:0vh; width: 8vh; height: 8vh;" keyboardButton.style.cssText = "top: 0vh; margin: auto; left: 8vh; right:0vh; width: 8vh; height: 8vh;"
keyboardButton.addEventListener("touchstart", function(e){e.preventDefault();hiddenInput.blur()}, false); keyboardButton.addEventListener("touchstart", function(e){e.preventDefault();hiddenInput.blur()}, false);
keyboardButton.addEventListener("touchend", function(e){hiddenInput.select()}, false); keyboardButton.addEventListener("touchend", function(e){e.preventDefault();toggleKeyboard()}, false);
document.body.appendChild(keyboardButton); document.body.appendChild(keyboardButton);
let placeButton = createTouchButton("placeButton", "inGame"); let placeButton = createTouchButton("placeButton", "inGame");
placeButton.style.cssText = "right:0vh;bottom:20vh;" placeButton.style.cssText = "right:0vh;bottom:20vh;"
@ -375,8 +439,8 @@ function insertCanvasElements() {
document.body.appendChild(sprintButton); document.body.appendChild(sprintButton);
let pauseButton = createTouchButton("pauseButton", "inGame"); let pauseButton = createTouchButton("pauseButton", "inGame");
pauseButton.style.cssText = "top: 0vh; margin: auto; left: 0vh; right: 32vh; width: 8vh; height: 8vh;" pauseButton.style.cssText = "top: 0vh; margin: auto; left: 0vh; right: 32vh; width: 8vh; height: 8vh;"
pauseButton.addEventListener("touchstart", function(e){keyEvent("À", "keydown")}, false); pauseButton.addEventListener("touchstart", function(e){keyEvent("`", "keydown")}, false);
pauseButton.addEventListener("touchend", function(e){keyEvent("À", "keyup")}, false); pauseButton.addEventListener("touchend", function(e){keyEvent("`", "keyup")}, false);
document.body.appendChild(pauseButton); document.body.appendChild(pauseButton);
let chatButton = createTouchButton("chatButton", "inGame"); let chatButton = createTouchButton("chatButton", "inGame");
chatButton.style.cssText = "top: 0vh; margin: auto; left: 0vh; right: 16vh; width: 8vh; height: 8vh;" chatButton.style.cssText = "top: 0vh; margin: auto; left: 0vh; right: 16vh; width: 8vh; height: 8vh;"
@ -389,8 +453,8 @@ function insertCanvasElements() {
keyEvent("5", "keydown"); keyEvent("5", "keydown");
}, false); }, false);
perspectiveButton.addEventListener("touchend", function(e) { perspectiveButton.addEventListener("touchend", function(e) {
keyEvent("5", "keyup");
keyEvent("f", "keyup"); keyEvent("f", "keyup");
keyEvent("5", "keyup");
}, false); }, false);
document.body.appendChild(perspectiveButton); document.body.appendChild(perspectiveButton);
let screenshotButton = createTouchButton("screenshotButton", "inGame"); let screenshotButton = createTouchButton("screenshotButton", "inGame");