163 lines
2.9 KiB
Svelte
163 lines
2.9 KiB
Svelte
<script lang="ts">
|
|
import { onMount } from 'svelte';
|
|
import { browser } from '$app/environment';
|
|
import debug from 'debug';
|
|
const dbg = debug('app:camera');
|
|
|
|
let gamepads: Gamepad[] = [];
|
|
let currentGamepad: Gamepad | undefined;
|
|
let buttons: GamepadButton[] = [];
|
|
let axes: number[] = [];
|
|
|
|
$: {
|
|
if (currentGamepad) {
|
|
function update() {
|
|
buttons = currentGamepad?.buttons.concat() || [];
|
|
axes = currentGamepad?.axes.concat() || [];
|
|
requestAnimationFrame(update);
|
|
}
|
|
update();
|
|
}
|
|
}
|
|
|
|
$: dbg('Gamepads %O', gamepads);
|
|
$: dbg('Current gamepad %s', currentGamepad);
|
|
|
|
$: currentGamepad?.vibrationActuator?.playEffect('dual-rumble', {
|
|
duration: 1000
|
|
});
|
|
|
|
onMount(() => {
|
|
refreshGamepads();
|
|
});
|
|
|
|
async function refreshGamepads() {
|
|
gamepads = browser ? (navigator.getGamepads().filter(Boolean) as Gamepad[]) : [];
|
|
currentGamepad = gamepads[0];
|
|
}
|
|
|
|
onMount(() => {
|
|
window.addEventListener('gamepadconnected', (e) => {
|
|
dbg('Gamepad connected', e);
|
|
refreshGamepads();
|
|
});
|
|
|
|
window.addEventListener('gamepaddisconnected', (e) => {
|
|
dbg('Gamepad disconnected', e);
|
|
refreshGamepads();
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<h2><i class="ti ti-device-gamepad"></i> Gamepad & Joystick Tests</h2>
|
|
<div class="controls">
|
|
<label>
|
|
Device
|
|
<select disabled={!gamepads.length}>
|
|
{#each gamepads as gamepad}
|
|
<option value={gamepad.index}>{gamepad.id}</option>
|
|
{:else}
|
|
<option>No gamepads detected. (Try pressing a button)</option>
|
|
{/each}
|
|
</select>
|
|
</label>
|
|
<button on:click={refreshGamepads}>
|
|
<i class="ti ti-refresh"></i>
|
|
Refresh
|
|
</button>
|
|
</div>
|
|
|
|
{#if currentGamepad}
|
|
<section>
|
|
<h3>Buttons</h3>
|
|
<ul class="buttons">
|
|
{#each buttons as button, i}
|
|
<li class:pressed={button.pressed}>{i}</li>
|
|
{/each}
|
|
</ul>
|
|
</section>
|
|
<section>
|
|
<h3>Axes</h3>
|
|
<div class="axes">
|
|
{#each axes as axis, i (i)}
|
|
<div class="axis">
|
|
<div>
|
|
<span>{i}</span>
|
|
<progress value={axis + 1} max="2"></progress>
|
|
<span>{axis.toFixed(2)}</span>
|
|
</div>
|
|
</div>
|
|
{/each}
|
|
</div>
|
|
</section>
|
|
{/if}
|
|
|
|
<style>
|
|
.controls {
|
|
display: flex;
|
|
align-items: end;
|
|
justify-content: stretch;
|
|
gap: 1em;
|
|
|
|
& label:first-child {
|
|
flex-grow: 1;
|
|
min-width: 0;
|
|
}
|
|
}
|
|
|
|
label {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.2em;
|
|
|
|
font-size: 0.8em;
|
|
& select {
|
|
font-size: initial;
|
|
}
|
|
}
|
|
|
|
h3 {
|
|
margin-top: 2em;
|
|
text-align: center;
|
|
}
|
|
|
|
.buttons {
|
|
list-style: none;
|
|
margin: 0;
|
|
padding: 0;
|
|
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: space-evenly;
|
|
|
|
& li {
|
|
display: block;
|
|
width: 2em;
|
|
height: 2em;
|
|
border: 1px solid white;
|
|
border-radius: 0.75em;
|
|
text-align: center;
|
|
line-height: 2em;
|
|
|
|
&.pressed {
|
|
background-color: darkred;
|
|
color: white;
|
|
}
|
|
}
|
|
}
|
|
|
|
.axes {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, 1fr);
|
|
gap: 0.5em 2em;
|
|
|
|
& .axis div {
|
|
display: flex;
|
|
gap: 0.25em;
|
|
|
|
& progress {
|
|
flex-grow: 1;
|
|
}
|
|
}
|
|
}
|
|
</style>
|