function simulateGamepad () { const app = window.app app.chrome.showCursor = true let cursorPos = [0, 0]; let intTabIndex = 0 const cursorSpeedPvt = 8 const cursorSize = 16 let scrollSpeed = 8 let buttonPressDelay = 500 let stickDeadZone = 0.2 let scrollGroup = null let scrollGroupY = null let elementFocusEnabled = true let start; let cursorSpeed = cursorSpeedPvt let lastButtonPress = { } var sounds = { Confirm: new Audio("./sounds/confirm.ogg"), Menu: new Audio("./sounds/btn1.ogg"), Hover: new Audio("./sounds/hover.ogg") } let element = document.elementFromPoint(0, 0) let elementType = 0 function appLoop() { var gamepads = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads() : []); if (!gamepads) { return; } var gp = gamepads[0]; // LEFT STICK if (gp.axes[0] > stickDeadZone) { cursorPos[0] += (gp.axes[0] * cursorSpeed) } else if (gp.axes[0] < -stickDeadZone) { cursorPos[0] += (gp.axes[0] * cursorSpeed) } if (gp.axes[1] > stickDeadZone) { cursorPos[1] += (gp.axes[1] * cursorSpeed) } else if (gp.axes[1] < -stickDeadZone) { cursorPos[1] += (gp.axes[1] * cursorSpeed) } if (cursorPos[0] < cursorSize) { cursorPos[0] = cursorSize } if (cursorPos[1] < cursorSize) { cursorPos[1] = cursorSize } if (cursorPos[0] > window.innerWidth - cursorSize) { cursorPos[0] = window.innerWidth - cursorSize } if (cursorPos[1] > window.innerHeight - cursorSize) { cursorPos[1] = window.innerHeight - cursorSize } // RIGHT STICK. if (scrollGroupY) { if (gp.axes[3] > stickDeadZone) { $(scrollGroupY).scrollTop($(scrollGroupY).scrollTop() + (gp.axes[3] * scrollSpeed)) elementFocusEnabled = false } else if (gp.axes[3] < -stickDeadZone) { $(scrollGroupY).scrollTop($(scrollGroupY).scrollTop() + (gp.axes[3] * scrollSpeed)) elementFocusEnabled = false } else { elementFocusEnabled = true } } if (scrollGroup) { if (gp.axes[2] > stickDeadZone) { $(scrollGroup).scrollLeft($(scrollGroup).scrollLeft() + (gp.axes[2] * scrollSpeed)) elementFocusEnabled = false } else if (gp.axes[2] < -stickDeadZone) { $(scrollGroup).scrollLeft($(scrollGroup).scrollLeft() + (gp.axes[2] * scrollSpeed)) elementFocusEnabled = false } else { elementFocusEnabled = true } } $(".cursor").css({ top: cursorPos[1] + "px", left: cursorPos[0] + "px", display: "block" }) // A BUTTON if (gp.buttons[0].pressed) { if (!lastButtonPress["A"]) { lastButtonPress["A"] = 0 } if (Date.now() - lastButtonPress["A"] > buttonPressDelay) { lastButtonPress["A"] = Date.now() sounds.Confirm.play() if (elementType == 0) { document.activeElement.dispatchEvent(new Event("click")) document.activeElement.dispatchEvent(new Event("controller-click")) } else { element.dispatchEvent(new Event("click")) element.dispatchEvent(new Event("controller-click")) } } } // B BUTTON if (gp.buttons[1].pressed) { if (!lastButtonPress["B"]) { lastButtonPress["B"] = 0 } if (Date.now() - lastButtonPress["B"] > buttonPressDelay) { lastButtonPress["B"] = Date.now() if (elementType == 0) { document.activeElement.dispatchEvent(new Event("contextmenu")) setTimeout(() => { if ($(".menu-option").length > 0) { let bounds = $(".menu-option")[0].getBoundingClientRect() cursorPos[0] = bounds.left + (bounds.width / 2) cursorPos[1] = bounds.top + (bounds.height / 2) } }, 100) } else { element.dispatchEvent(new Event("contextmenu")) } } } // right bumper if (gp.buttons[5].pressed) { if (!lastButtonPress["RB"]) { lastButtonPress["RB"] = 0 } if (Date.now() - lastButtonPress["RB"] > buttonPressDelay) { lastButtonPress["RB"] = Date.now() app.navigateForward() } } // left bumper if (gp.buttons[4].pressed) { if (!lastButtonPress["LB"]) { lastButtonPress["LB"] = 0 } if (Date.now() - lastButtonPress["LB"] > buttonPressDelay) { lastButtonPress["LB"] = Date.now() app.navigateBack() } } // cursor hover if (elementFocusEnabled) { element = document.elementFromPoint(cursorPos[0], cursorPos[1]) } if (element) { let closest = element.closest("[tabindex], input, button, a") // VERT SCROLL let scrollGroupCloY = element.closest(`[scrollaxis="y"]`) if (scrollGroupCloY) { scrollGroupY = scrollGroupCloY } // HOZ SCROLL let scrollGroupClo = element.closest(".v-hl-container") if (scrollGroupClo) { if (scrollGroupClo.classList.contains("v-hl-container")) { scrollGroup = scrollGroupClo scrollGroup.style["scroll-snap-type"] = "unset" } else { scrollGroup.style["scroll-snap-type"] = "" scrollGroup = null } } if (closest) { elementType = 0 closest.focus() } else { if (closest) { closest.blur() } elementType = 1 element.focus() } cursorSpeed = cursorSpeedPvt if (!element.classList.contains("app-chrome") && !element.classList.contains("app-content")) { cursorSpeed = cursorSpeedPvt } // console.log($._data($(element), "events")) } else { cursorSpeed = 12 } // console.log(gp.axes[0], gp.axes[1]) start = requestAnimationFrame(appLoop); } // controller pairing notyf.error("Press the button on your controller to pair it to Cider.") window.addEventListener("gamepadconnected", function (e) { console.log("Gamepad connected at index %d: %s. %d buttons, %d axes.", e.gamepad.index, e.gamepad.id, e.gamepad.buttons.length, e.gamepad.axes.length); notyf.success("Pairing successful!") appLoop() }, { once: true }); document.addEventListener("keydown", (e) => { sounds.Confirm.currentTime = 0 sounds.Menu.currentTime = 0 sounds.Hover.currentTime = 0 let tabbable = $("[tabindex]") console.log(e.key) switch (e.key) { default: break; case "ArrowLeft": e.preventDefault() cursorPos[0] -= cursorSpeed break; case "ArrowRight": e.preventDefault() cursorPos[0] += cursorSpeed break; case "ArrowUp": e.preventDefault() cursorPos[1] -= cursorSpeed // sounds.Hover.play() // if(intTabIndex <= 0) { // intTabIndex = 0 // }else{ // intTabIndex-- // } // $(tabbable[intTabIndex]).focus() // $("#app-content").scrollTop($(document.activeElement).offset().top) break; case "ArrowDown": e.preventDefault() cursorPos[1] += cursorSpeed // if(intTabIndex < tabbable.length) { // intTabIndex++ // }else{ // intTabIndex = tabbable.length // } // $(tabbable[intTabIndex]).focus() // $("#app-content").scrollTop($(document.activeElement).offset().top) break; case "c": app.resetState() break; case "x": // set cursorPos to the top right of the screen // sounds.Menu.play() if (elementType == 0) { document.activeElement.dispatchEvent(new Event("contextmenu")) } else { element.dispatchEvent(new Event("contextmenu")) } e.preventDefault() break; case "z": sounds.Confirm.play() if (elementType == 0) { document.activeElement.dispatchEvent(new Event("click")) document.activeElement.dispatchEvent(new Event("controller-click")) } else { element.dispatchEvent(new Event("click")) element.dispatchEvent(new Event("controller-click")) } e.preventDefault() break; } $(".cursor").css({ top: cursorPos[1] + "px", left: cursorPos[0] + "px" }) function lerp(a, b, n) { return (1 - n) * a + n * b } element = document.elementFromPoint(cursorPos[0], cursorPos[1]) if (element) { let closest = element.closest("[tabindex], input, button, a") if (closest) { elementType = 0 closest.focus() } else { elementType = 1 element.focus() } } console.log(element) }); } export {simulateGamepad}