From 0f8b739705135dfeb2ca23ae611709b963b28521 Mon Sep 17 00:00:00 2001 From: booploops <49113086+booploops@users.noreply.github.com> Date: Wed, 2 Mar 2022 00:33:27 -0800 Subject: [PATCH] virtual cursor --- src/renderer/index.js | 278 ++++++++++++++++-- src/renderer/style.less | 13 + src/renderer/views/components/artist-chip.ejs | 2 +- .../views/components/mediaitem-list-item.ejs | 2 +- .../views/components/mediaitem-square.ejs | 2 +- src/renderer/views/main.ejs | 1 + 6 files changed, 263 insertions(+), 35 deletions(-) diff --git a/src/renderer/index.js b/src/renderer/index.js index eb557878..effa9058 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -233,7 +233,8 @@ const app = new Vue({ topChromeVisible: true, progresshover: false, windowControlPosition: "right", - contentAreaScrolling: true + contentAreaScrolling: true, + showCursor: false }, collectionList: { response: {}, @@ -303,7 +304,19 @@ const app = new Vue({ }, methods: { simulateController() { + this.chrome.showCursor = true + let cursorPos = [0, 0]; let intTabIndex = 0 + let self = this + let cursorSpeed = 4 + let scrollSpeed = 8 + let buttonPressDelay = 500 + let stickDeadZone = 0.2 + let scrollGroup = null + + let lastButtonPress = { + + } var sounds = { Confirm: new Audio("./sounds/confirm.ogg"), @@ -311,6 +324,166 @@ const app = new Vue({ 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) + } + + // RIGHT STICK. + if (gp.axes[3] > stickDeadZone) { + $("#app-content").scrollTop($("#app-content").scrollTop() + (gp.axes[3] * scrollSpeed)) + } else if (gp.axes[3] < -stickDeadZone) { + $("#app-content").scrollTop($("#app-content").scrollTop() + (gp.axes[3] * scrollSpeed)) + } + + + if(scrollGroup) { + if (gp.axes[2] > stickDeadZone) { + console.log('axis 2 up') + $(scrollGroup).scrollLeft($(scrollGroup).scrollLeft() + (gp.axes[2] * scrollSpeed)) + } else if (gp.axes[2] < -stickDeadZone) { + console.log('axis 2 dn') + $(scrollGroup).scrollLeft($(scrollGroup).scrollLeft() + (gp.axes[2] * scrollSpeed)) + } + } + + + $(".cursor").css({ + top: cursorPos[1] + "px", + left: cursorPos[0] + "px" + }) + + // 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 + + element = document.elementFromPoint(cursorPos[0], cursorPos[1]) + + if (element) { + let closest = element.closest("[tabindex], input, button, a") + 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() + } + } + // 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 @@ -319,51 +492,92 @@ const app = new Vue({ console.log(e.key) switch (e.key) { default: - break; + break; case "ArrowLeft": - e.preventDefault() + + cursorPos[0] -= cursorSpeed break; case "ArrowRight": e.preventDefault() + + cursorPos[0] += cursorSpeed break; case "ArrowUp": - sounds.Hover.play() - if(intTabIndex <= 0) { - intTabIndex = 0 - }else{ - intTabIndex-- - } - $(tabbable[intTabIndex]).focus() - // $("#app-content").scrollTop($(document.activeElement).offset().top) 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": - sounds.Hover.play() - if(intTabIndex < tabbable.length) { - intTabIndex++ - }else{ - intTabIndex = tabbable.length - } - $(tabbable[intTabIndex]).focus() - // $("#app-content").scrollTop($(document.activeElement).offset().top) 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": - sounds.Menu.play() - document.activeElement.dispatchEvent(new Event("contextmenu")) + 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; + break; case "z": sounds.Confirm.play() - document.activeElement.dispatchEvent(new Event("click")) - document.activeElement.dispatchEvent(new Event("controller-click")) + 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) }); }, songLinkShare(amUrl) { @@ -854,7 +1068,7 @@ const app = new Vue({ let numbers = [] for (item of soundcheck) { numbers.push(parseInt(item, 16)) - + } numbers.shift() let peak = Math.max(numbers[6], numbers[7]) / 32768.0 @@ -978,7 +1192,7 @@ const app = new Vue({ }, 500) ipcRenderer.invoke("renderer-ready", true) document.querySelector("#LOADER").remove() - if(this.cfg.general.themeUpdateNotification) { + if (this.cfg.general.themeUpdateNotification) { this.checkForThemeUpdates() } }, @@ -992,7 +1206,7 @@ const app = new Vue({ .then(res => { if (res[0].sha != theme.commit) { const notify = notyf.open({ className: "notyf-info", type: "info", message: `[Themes] ${theme.name} has an update available.` }) - notify.on("click", ()=>{ + notify.on("click", () => { app.appRoute("themes-github") notyf.dismiss(notify) }) @@ -1038,9 +1252,9 @@ const app = new Vue({ } if (directives[directive]) { return this.chrome.appliedTheme.info.directives[directive].value - } else if(this.cfg.visual.directives[directive]) { + } else if (this.cfg.visual.directives[directive]) { return this.cfg.visual.directives.windowLayout - }else{ + } else { return "" } }, @@ -3470,7 +3684,7 @@ const app = new Vue({ let artworkSize = 50 if (app.getThemeDirective("lcdArtworkSize") != "") { artworkSize = app.getThemeDirective("lcdArtworkSize") - }else if(this.cfg.visual.directives.windowLayout == "twopanel") { + } else if (this.cfg.visual.directives.windowLayout == "twopanel") { artworkSize = 70 } this.currentArtUrl = ''; diff --git a/src/renderer/style.less b/src/renderer/style.less index ead9279b..495c0585 100644 --- a/src/renderer/style.less +++ b/src/renderer/style.less @@ -3152,6 +3152,19 @@ body[platform='darwin'] { flex-direction: column; } +.cursor { + background: rgb(255 255 255 / 50%); + width: 16px; + height: 16px; + position: fixed; + z-index: 9999999999; + pointer-events: none; + border-radius: 100%; + box-shadow: 0px 0px 0px 2px rgb(200 200 200 / 100%); + top: 0; + left: 0; +} + @import url("less/macos.less"); @import url("less/linux.less"); @import url("less/compact.less"); diff --git a/src/renderer/views/components/artist-chip.ejs b/src/renderer/views/components/artist-chip.ejs index 6d2734e4..d0be7f95 100644 --- a/src/renderer/views/components/artist-chip.ejs +++ b/src/renderer/views/components/artist-chip.ejs @@ -1,5 +1,5 @@