mirror of
https://github.com/CharaChorder/DeviceManager.git
synced 2026-06-04 04:48:55 +00:00
feat: ccos emulator
This commit is contained in:
@@ -46,15 +46,6 @@
|
||||
element?.closest<HTMLElement>("[popover]")?.hidePopover();
|
||||
}
|
||||
|
||||
async function connectCC0(event: MouseEvent) {
|
||||
const { fetchCCOS } = await import("$lib/ccos/ccos");
|
||||
closePopover();
|
||||
const ccos = await fetchCCOS();
|
||||
if (ccos) {
|
||||
connect(ccos, !event.shiftKey);
|
||||
}
|
||||
}
|
||||
|
||||
async function connectDevice(event: MouseEvent) {
|
||||
const port = await navigator.serial.requestPort({
|
||||
filters: event.shiftKey ? [] : [...PORT_FILTERS.values()],
|
||||
|
||||
@@ -116,6 +116,25 @@
|
||||
{/if}
|
||||
</div>
|
||||
<ul>
|
||||
<li>
|
||||
<a
|
||||
href={import.meta.env.VITE_DISCORD_URL}
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<svg
|
||||
class="discord-icon"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 126.64 96"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="m81 0-3 7Q63 4 49 7l-4-7-26 8Q-4 45 1 80q14 10 32 16l6-11-10-5 2-2q33 13 64 0l3 2-11 5 7 11q17-5 32-16 4-40-19-72-12-5-26-8M42 65q-10-1-11-12 0-15 11-13c11 2 12 6 12 13q-1 11-12 12m42 0q-10-1-11-12 0-15 11-13c11 2 12 6 12 13q-1 11-12 12"
|
||||
/></svg
|
||||
>
|
||||
Discord</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href={import.meta.env.VITE_BUGS_URL} rel="noreferrer" target="_blank"
|
||||
><span class="icon">bug_report</span> Bugs</a
|
||||
@@ -168,6 +187,11 @@
|
||||
|
||||
$sync-border-radius: 16px;
|
||||
|
||||
.discord-icon {
|
||||
margin: 5px;
|
||||
inline-size: 14px;
|
||||
}
|
||||
|
||||
.sync-box {
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
: []),
|
||||
],
|
||||
[
|
||||
{
|
||||
href: "/editor/",
|
||||
icon: "playground_2",
|
||||
title: "Emulator",
|
||||
},
|
||||
{
|
||||
href: import.meta.env.VITE_LEARN_URL,
|
||||
icon: "school",
|
||||
|
||||
@@ -5,18 +5,17 @@
|
||||
import TrackChords from "$lib/charrecorder/TrackChords.svelte";
|
||||
import TrackRollingWpm from "$lib/charrecorder/TrackRollingWpm.svelte";
|
||||
import { fade } from "svelte/transition";
|
||||
import { initSerial, serialPort } from "$lib/serial/connection";
|
||||
import { tick } from "svelte";
|
||||
import { ccosKeyInterceptor } from "$lib/ccos/attachment";
|
||||
|
||||
let recorder: ReplayRecorder = $state(new ReplayRecorder());
|
||||
let replay: Replay | undefined = $state();
|
||||
|
||||
let wpm = $state(0);
|
||||
let cc0Loading = $state(false);
|
||||
let chords: InferredChord[] = $state([]);
|
||||
|
||||
function handleRawKey(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
keyEvent(event);
|
||||
}
|
||||
|
||||
function keyEvent(event: KeyboardEvent) {
|
||||
if (event.key === "Tab") {
|
||||
clear();
|
||||
@@ -47,15 +46,60 @@
|
||||
a.download = "replay.json";
|
||||
a.click();
|
||||
}
|
||||
|
||||
async function connectCC0(event: MouseEvent) {
|
||||
cc0Loading = true;
|
||||
try {
|
||||
await tick();
|
||||
if ($serialPort) {
|
||||
$serialPort?.close();
|
||||
$serialPort = undefined;
|
||||
}
|
||||
const { fetchCCOS } = await import("$lib/ccos/ccos");
|
||||
const ccos = await fetchCCOS();
|
||||
if (ccos) {
|
||||
try {
|
||||
await initSerial(ccos, !event.shiftKey);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
cc0Loading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Editor</title>
|
||||
</svelte:head>
|
||||
<svelte:window onkeydown={handleRawKey} onkeyup={handleRawKey} />
|
||||
|
||||
<section>
|
||||
<h2>Editor</h2>
|
||||
<h2>
|
||||
CCOS Emulator
|
||||
{#if $serialPort?.chipset === "WASM"}
|
||||
<small>(Emulator Active)</small>
|
||||
{:else}
|
||||
<button class="primary" disabled={cc0Loading} onclick={connectCC0}>
|
||||
<span class="icon">play_arrow</span>
|
||||
Boot CCOS Emulator</button
|
||||
>
|
||||
{/if}
|
||||
</h2>
|
||||
|
||||
<p style:max-width="600px">
|
||||
Try a (limited) demo of CCOS running directly in your browser.<br /><span
|
||||
style:color="var(--md-sys-color-primary)"
|
||||
>Chording requires an <b>NKRO Keyboard</b> to work properly.</span
|
||||
>
|
||||
<br />Browsers usually report key timings with limited accuracy to revent
|
||||
fingerprinting, which can impact chording.
|
||||
<br /><i>Results may vary.</i>
|
||||
<br />
|
||||
Use sidebar tabs to configure <a href="/config/chords/">Chords</a>,
|
||||
<a href="/config/layout/">Layout</a>
|
||||
and <a href="/config/settings/">Settings</a>.
|
||||
</p>
|
||||
|
||||
{#if replay}
|
||||
<div class="replay" transition:fade={{ duration: 100 }}>
|
||||
@@ -66,7 +110,9 @@
|
||||
{#key recorder}
|
||||
<div
|
||||
class="editor"
|
||||
tabindex="-1"
|
||||
out:fade={{ duration: 100 }}
|
||||
{@attach ccosKeyInterceptor($serialPort, recorder)}
|
||||
style:opacity={replay ? 0 : undefined}
|
||||
>
|
||||
<CharRecorder replay={recorder.player} cursor={true} keys={true}>
|
||||
@@ -95,15 +141,38 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
a {
|
||||
display: inline;
|
||||
padding: 0;
|
||||
color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
small {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
color: var(--md-sys-color-primary);
|
||||
font-weight: 500;
|
||||
font-size: 0.6em;
|
||||
}
|
||||
|
||||
button.primary {
|
||||
display: inline-flex;
|
||||
background: none;
|
||||
color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
.replay,
|
||||
.editor {
|
||||
position: absolute;
|
||||
top: 3em;
|
||||
left: 0;
|
||||
transition: opacity 0.1s;
|
||||
margin: 4px;
|
||||
outline: 1px solid var(--md-sys-color-outline);
|
||||
padding: 16px;
|
||||
padding-bottom: 5em;
|
||||
padding-left: 0;
|
||||
|
||||
&:focus-within {
|
||||
outline: 2px solid var(--md-sys-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
|
||||
Reference in New Issue
Block a user