virtual cursor
This commit is contained in:
parent
e308160bec
commit
0f8b739705
6 changed files with 263 additions and 35 deletions
|
@ -233,7 +233,8 @@ const app = new Vue({
|
||||||
topChromeVisible: true,
|
topChromeVisible: true,
|
||||||
progresshover: false,
|
progresshover: false,
|
||||||
windowControlPosition: "right",
|
windowControlPosition: "right",
|
||||||
contentAreaScrolling: true
|
contentAreaScrolling: true,
|
||||||
|
showCursor: false
|
||||||
},
|
},
|
||||||
collectionList: {
|
collectionList: {
|
||||||
response: {},
|
response: {},
|
||||||
|
@ -303,7 +304,19 @@ const app = new Vue({
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
simulateController() {
|
simulateController() {
|
||||||
|
this.chrome.showCursor = true
|
||||||
|
let cursorPos = [0, 0];
|
||||||
let intTabIndex = 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 = {
|
var sounds = {
|
||||||
Confirm: new Audio("./sounds/confirm.ogg"),
|
Confirm: new Audio("./sounds/confirm.ogg"),
|
||||||
|
@ -311,6 +324,166 @@ const app = new Vue({
|
||||||
Hover: new Audio("./sounds/hover.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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) => {
|
document.addEventListener("keydown", (e) => {
|
||||||
sounds.Confirm.currentTime = 0
|
sounds.Confirm.currentTime = 0
|
||||||
sounds.Menu.currentTime = 0
|
sounds.Menu.currentTime = 0
|
||||||
|
@ -319,51 +492,92 @@ const app = new Vue({
|
||||||
console.log(e.key)
|
console.log(e.key)
|
||||||
switch (e.key) {
|
switch (e.key) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
case "ArrowLeft":
|
case "ArrowLeft":
|
||||||
|
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
|
cursorPos[0] -= cursorSpeed
|
||||||
break;
|
break;
|
||||||
case "ArrowRight":
|
case "ArrowRight":
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
|
cursorPos[0] += cursorSpeed
|
||||||
break;
|
break;
|
||||||
case "ArrowUp":
|
case "ArrowUp":
|
||||||
sounds.Hover.play()
|
|
||||||
if(intTabIndex <= 0) {
|
|
||||||
intTabIndex = 0
|
|
||||||
}else{
|
|
||||||
intTabIndex--
|
|
||||||
}
|
|
||||||
$(tabbable[intTabIndex]).focus()
|
|
||||||
// $("#app-content").scrollTop($(document.activeElement).offset().top)
|
|
||||||
e.preventDefault()
|
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;
|
break;
|
||||||
case "ArrowDown":
|
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()
|
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;
|
break;
|
||||||
case "c":
|
case "c":
|
||||||
app.resetState()
|
app.resetState()
|
||||||
break;
|
break;
|
||||||
case "x":
|
case "x":
|
||||||
sounds.Menu.play()
|
// set cursorPos to the top right of the screen
|
||||||
document.activeElement.dispatchEvent(new Event("contextmenu"))
|
// sounds.Menu.play()
|
||||||
|
if (elementType == 0) {
|
||||||
|
document.activeElement.dispatchEvent(new Event("contextmenu"))
|
||||||
|
} else {
|
||||||
|
element.dispatchEvent(new Event("contextmenu"))
|
||||||
|
}
|
||||||
|
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
break;
|
break;
|
||||||
case "z":
|
case "z":
|
||||||
sounds.Confirm.play()
|
sounds.Confirm.play()
|
||||||
document.activeElement.dispatchEvent(new Event("click"))
|
if (elementType == 0) {
|
||||||
document.activeElement.dispatchEvent(new Event("controller-click"))
|
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()
|
e.preventDefault()
|
||||||
break;
|
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) {
|
songLinkShare(amUrl) {
|
||||||
|
@ -854,7 +1068,7 @@ const app = new Vue({
|
||||||
let numbers = []
|
let numbers = []
|
||||||
for (item of soundcheck) {
|
for (item of soundcheck) {
|
||||||
numbers.push(parseInt(item, 16))
|
numbers.push(parseInt(item, 16))
|
||||||
|
|
||||||
}
|
}
|
||||||
numbers.shift()
|
numbers.shift()
|
||||||
let peak = Math.max(numbers[6], numbers[7]) / 32768.0
|
let peak = Math.max(numbers[6], numbers[7]) / 32768.0
|
||||||
|
@ -978,7 +1192,7 @@ const app = new Vue({
|
||||||
}, 500)
|
}, 500)
|
||||||
ipcRenderer.invoke("renderer-ready", true)
|
ipcRenderer.invoke("renderer-ready", true)
|
||||||
document.querySelector("#LOADER").remove()
|
document.querySelector("#LOADER").remove()
|
||||||
if(this.cfg.general.themeUpdateNotification) {
|
if (this.cfg.general.themeUpdateNotification) {
|
||||||
this.checkForThemeUpdates()
|
this.checkForThemeUpdates()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -992,7 +1206,7 @@ const app = new Vue({
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (res[0].sha != theme.commit) {
|
if (res[0].sha != theme.commit) {
|
||||||
const notify = notyf.open({ className: "notyf-info", type: "info", message: `[Themes] ${theme.name} has an update available.` })
|
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")
|
app.appRoute("themes-github")
|
||||||
notyf.dismiss(notify)
|
notyf.dismiss(notify)
|
||||||
})
|
})
|
||||||
|
@ -1038,9 +1252,9 @@ const app = new Vue({
|
||||||
}
|
}
|
||||||
if (directives[directive]) {
|
if (directives[directive]) {
|
||||||
return this.chrome.appliedTheme.info.directives[directive].value
|
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
|
return this.cfg.visual.directives.windowLayout
|
||||||
}else{
|
} else {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -3470,7 +3684,7 @@ const app = new Vue({
|
||||||
let artworkSize = 50
|
let artworkSize = 50
|
||||||
if (app.getThemeDirective("lcdArtworkSize") != "") {
|
if (app.getThemeDirective("lcdArtworkSize") != "") {
|
||||||
artworkSize = 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
|
artworkSize = 70
|
||||||
}
|
}
|
||||||
this.currentArtUrl = '';
|
this.currentArtUrl = '';
|
||||||
|
|
|
@ -3152,6 +3152,19 @@ body[platform='darwin'] {
|
||||||
flex-direction: column;
|
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/macos.less");
|
||||||
@import url("less/linux.less");
|
@import url("less/linux.less");
|
||||||
@import url("less/compact.less");
|
@import url("less/compact.less");
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script type="text/x-template" id="artist-chip">
|
<script type="text/x-template" id="artist-chip">
|
||||||
<div class="artist-chip" @click.self="route">
|
<div class="artist-chip" @click.self="route" tabindex="0">
|
||||||
<div class="artist-chip__image">
|
<div class="artist-chip__image">
|
||||||
<mediaitem-artwork v-if="artist.id != null" :url="artist.attributes.artwork.url" :size="32"></mediaitem-artwork>
|
<mediaitem-artwork v-if="artist.id != null" :url="artist.attributes.artwork.url" :size="32"></mediaitem-artwork>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
@mouseover="showInLibrary = true"
|
@mouseover="showInLibrary = true"
|
||||||
@mouseleave="showInLibrary = false"
|
@mouseleave="showInLibrary = false"
|
||||||
@dblclick="route()"
|
@dblclick="route()"
|
||||||
@controller-click.self="route()"
|
@controller-click="route()"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
:class="[{'mediaitem-selected': app.select_hasMediaItem(guid)}, addClasses]">
|
:class="[{'mediaitem-selected': app.select_hasMediaItem(guid)}, addClasses]">
|
||||||
<template v-if="isVisible">
|
<template v-if="isVisible">
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<div
|
<div
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@click.self="app.routeView(item)"
|
@click.self="app.routeView(item)"
|
||||||
@controller-click.self="app.routeView(item)"
|
@controller-click="app.routeView(item)"
|
||||||
@contextmenu.self="contextMenu"
|
@contextmenu.self="contextMenu"
|
||||||
class="cd-mediaitem-square" :class="getClasses()" @contextmenu="contextMenu"
|
class="cd-mediaitem-square" :class="getClasses()" @contextmenu="contextMenu"
|
||||||
v-observe-visibility="{callback: visibilityChanged}"
|
v-observe-visibility="{callback: visibilityChanged}"
|
||||||
|
|
|
@ -80,6 +80,7 @@
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
<%- include('app/panels'); %>
|
<%- include('app/panels'); %>
|
||||||
|
<div class="cursor" v-if="chrome.showCursor"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<% for(var i=0; i < Object.keys(env.components).length ; i++) {%>
|
<% for(var i=0; i < Object.keys(env.components).length ; i++) {%>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue