feat(control): bind arrow keys to arrow buttons

This commit is contained in:
E44
2026-06-13 22:00:09 +02:00
parent a3d444df20
commit a49b842a4c
2 changed files with 87 additions and 22 deletions
@@ -36,7 +36,7 @@
{#if content.open}
<div
class="absolute inset-0 backdrop-blur flex justify-center items-center z-50 {className}"
class="popup absolute inset-0 backdrop-blur flex justify-center items-center z-50 {className}"
transition:fade={{ duration: 100 }}
>
<div
+86 -21
View File
@@ -34,6 +34,7 @@
import { liveQuery, type Observable } from 'dexie';
import TextInput from '$lib/components/TextInput.svelte';
import { add_to_keyboard_queue } from '$lib/ts/utils';
import { onMount } from 'svelte';
let all_display_states: Observable<'on' | 'off' | 'mixed'> | undefined = $state();
$effect(() => {
@@ -44,11 +45,16 @@
let popup_content: PopupContent = $state({
open: false,
snippet: null,
title: '',
title: ''
});
let current_text = $state('');
const key_pressed = $state({
ArrowRight: false,
ArrowLeft: false
});
function popup_close_function() {
popup_content.open = false;
}
@@ -79,7 +85,7 @@
snippet: website_popup,
title: 'Webseite Anzeigen',
window_class: 'w-xl',
title_icon: Globe,
title_icon: Globe
};
};
@@ -102,7 +108,7 @@
open: true,
snippet: ask_shutdown_popup,
title: 'Bildschirm Herunterfahren',
title_icon: PowerOff,
title_icon: PowerOff
};
}
@@ -110,7 +116,10 @@
popup_content.open = false;
await run_on_all_selected_displays((d) => {
shutdown(d.ip); // no await here because we want to be fast
db.displays.update(d.id, { status: 'app_offline', preview: { currently_updating: false, url: null} });
db.displays.update(d.id, {
status: 'app_offline',
preview: { currently_updating: false, url: null }
});
}, false);
}
@@ -143,10 +152,58 @@
async function send_website() {
popup_content.open = false;
await run_on_all_selected_displays((d) =>
open_website(d.ip, website_url)
);
await run_on_all_selected_displays((d) => open_website(d.ip, website_url));
}
function has_open_popup(): boolean {
return document.querySelector('.popup') !== null;
}
function handle_key(
event: KeyboardEvent,
key: 'ArrowRight' | 'ArrowLeft',
action: 'press' | 'release'
) {
if (event.key === key) {
const current_press_state: boolean = key_pressed[key];
if (
(action === 'press' && (current_press_state === true || has_open_popup())) ||
(action === 'release' && current_press_state === false)
)
return;
key_pressed[key] = !current_press_state;
add_to_keyboard_queue(async () => {
await run_on_all_selected_displays(
(d) => send_keyboard_input(d.ip, [{ key, action }]),
true
);
});
}
}
function add_remove_event_listeners(
add_remove_function: (type: string, listener: (e: KeyboardEvent) => void) => void
) {
const actions = {
keydown: 'press',
keyup: 'release'
} as const;
const keys = ['ArrowRight', 'ArrowLeft'] as const;
for (const [action_type, action_value] of Object.entries(actions)) {
for (const key of keys) {
add_remove_function(action_type, (e: KeyboardEvent) => handle_key(e, key, action_value));
}
}
}
onMount(() => {
add_remove_event_listeners(window.addEventListener);
return () => {
add_remove_event_listeners(window.removeEventListener);
};
});
</script>
{#snippet website_popup()}
@@ -185,11 +242,11 @@
{/snippet}
{#snippet send_keys_popup()}
<KeyInput {popup_close_function}/>
<KeyInput {popup_close_function} />
{/snippet}
{#snippet text_popup()}
<TipTapInput bind:text={current_text}/>
<TipTapInput bind:text={current_text} />
{/snippet}
<div class="grid grid-rows-[2.5rem_auto] bg-stone-800 rounded-2xl min-w-0">
@@ -202,15 +259,19 @@
<div class="flex flex-row gap-2 w-75 justify-normal">
<button
title="Vorherige Folie (Pfeil nach Links) [gedrückt halten möglich]"
class="px-9 bg-stone-700 {$selected_online_display_ids.length === 0
class="px-9 {key_pressed.ArrowLeft
? 'bg-stone-500'
: 'bg-stone-700'} {$selected_online_display_ids.length === 0
? 'text-stone-500 cursor-not-allowed'
: 'hover:bg-stone-600 active:bg-stone-500 cursor-pointer'} py-2 rounded-xl flex justify-center items-center transition-colors duration-200"
disabled={$selected_online_display_ids.length === 0}
disabled={$selected_online_display_ids.length === 0 || key_pressed.ArrowLeft}
onmousedown={() => {
add_to_keyboard_queue(async () => await send_single_key_press('ArrowLeft', 'press'));
}}
onmouseup={() => {
add_to_keyboard_queue(async () => await send_single_key_press('ArrowLeft', 'release'));
add_to_keyboard_queue(
async () => await send_single_key_press('ArrowLeft', 'release')
);
}}
>
<ArrowBigLeft />
@@ -218,15 +279,21 @@
<button
title="Nächste Folie (Pfeil nach Rechts) [gedrückt halten möglich]"
class="px-9 bg-stone-700 {$selected_online_display_ids.length === 0
? 'text-stone-500 cursor-not-allowed'
: 'hover:bg-stone-600 active:bg-stone-500 cursor-pointer'} py-2 rounded-xl flex justify-center items-center transition-colors duration-200"
disabled={$selected_online_display_ids.length === 0}
class="px-9 {key_pressed.ArrowRight
? 'bg-stone-500 cursor-not-allowed'
: `bg-stone-700 ${
$selected_online_display_ids.length === 0
? 'text-stone-500 cursor-not-allowed'
: 'hover:bg-stone-600 active:bg-stone-500 cursor-pointer'
}`} py-2 rounded-xl flex justify-center items-center transition-colors duration-200"
disabled={$selected_online_display_ids.length === 0 || key_pressed.ArrowRight}
onmousedown={() => {
add_to_keyboard_queue(async () => await send_single_key_press('ArrowRight', 'press'));
}}
onmouseup={() => {
add_to_keyboard_queue(async () => await send_single_key_press('ArrowRight', 'release'));
add_to_keyboard_queue(
async () => await send_single_key_press('ArrowRight', 'release')
);
}}
>
<ArrowBigRight />
@@ -271,8 +338,7 @@
<div class="flex flex-col gap-2">
<Button
className="px-3 flex gap-3 w-full xl:w-75 justify-normal"
disabled={$all_display_states === 'on' ||
$selected_display_ids.length === 0}
disabled={$all_display_states === 'on' || $selected_display_ids.length === 0}
click_function={startup_action}
>
<Power /> Bildschirm Hochfahren
@@ -280,8 +346,7 @@
<Button
className="px-3 flex gap-3 w-full xl:w-75 justify-normal"
disabled={$all_display_states === 'off' ||
$selected_online_display_ids.length === 0}
disabled={$all_display_states === 'off' || $selected_online_display_ids.length === 0}
click_function={ask_shutdown}
>
<PowerOff /> Bildschirm Herunterfahren</Button