aaa
This commit is contained in:
parent
e1e2e77f39
commit
ce010c1270
3 changed files with 178 additions and 1 deletions
|
@ -38,4 +38,16 @@ button, .button {
|
||||||
|
|
||||||
background: black;
|
background: black;
|
||||||
color: white;
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
background: black;
|
||||||
|
color: white;
|
||||||
|
padding: 0.25em 0.5em;
|
||||||
|
border-radius: 0.25em;
|
||||||
|
border: 1px solid white;
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -83,9 +83,11 @@
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<label>
|
<label>
|
||||||
Device
|
Device
|
||||||
<select bind:value={currentDevice} id="device">
|
<select bind:value={currentDevice} disabled={!devices.length}>
|
||||||
{#each devices as device}
|
{#each devices as device}
|
||||||
<option value={device.deviceId}>{device.label || '???'}</option>
|
<option value={device.deviceId}>{device.label || '???'}</option>
|
||||||
|
{:else}
|
||||||
|
<option>No camera found</option>
|
||||||
{/each}
|
{/each}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
<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>
|
Loading…
Reference in a new issue