3 Commits

Author SHA1 Message Date
3dd91a1cea 1.5.1 2024-04-29 11:19:37 +02:00
cbcf705f71 feat: massively improved chord search
fixes #119
2024-04-29 11:18:23 +02:00
4007810c7b fix: can't edit blank actions
fixes #110
2024-04-29 09:35:22 +02:00
9 changed files with 99 additions and 26 deletions

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "charachorder-device-manager",
"version": "1.5.0",
"version": "1.5.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "charachorder-device-manager",
"version": "1.5.0",
"version": "1.5.1",
"license": "AGPL-3.0-or-later",
"devDependencies": {
"@codemirror/autocomplete": "^6.15.0",

View File

@@ -1,6 +1,6 @@
{
"name": "charachorder-device-manager",
"version": "1.5.0",
"version": "1.5.1",
"license": "AGPL-3.0-or-later",
"private": true,
"repository": {

View File

@@ -1,6 +1,6 @@
[package]
name = "app"
version = "1.5.0"
version = "1.5.1"
description = "A Tauri App"
authors = ["Thea Schöbl <dev@theaninova.de>"]
license = "AGPL-3"

View File

@@ -6,7 +6,7 @@
"devPath": "http://localhost:5173",
"distDir": "../build"
},
"package": { "productName": "amacc1ng", "version": "1.5.0" },
"package": { "productName": "amacc1ng", "version": "1.5.1" },
"tauri": {
"allowlist": { "all": false },
"bundle": {

View File

@@ -1,6 +1,9 @@
name: CharaChorder
description: CharaChorder specific actions
actions:
0:
id: "NO_ACTION"
display: "No Action"
528:
id: "RESTART"
title: Restart Device
@@ -58,6 +61,7 @@ actions:
544:
variantOf: 36
id: "SPACERIGHT"
display: " "
title: Right Spacebar (eg CC Lite)
icon: space_bar
variant: right

View File

@@ -32,5 +32,7 @@
"You can use Nexus to track words you might want to add to your chord library",
"The CC1 default layout was 80% science, 20% art",
"There is little to no reason to use hjkl in VIM on a CC1 since the arrows keys are so close already",
"The device manager automatically creates a backup for you when you reboot your device into the bootloader"
"The device manager automatically creates a backup for you when you reboot your device into the bootloader",
"You can use \"compound\", \"macro\", \"suffix\" and \"cursor warp\" in the chord search to find specific types of chords",
"You can search for chord inputs by using a leading \"+\", for example \"+a +DUP\" will show all chords with inputs that contain both a and DUP"
]

View File

@@ -15,7 +15,8 @@
$: dynamicMapping = info.keyCode && $osLayout.get(info.keyCode);
$: tooltip =
(info.title ?? info.id ?? `0x${info.code.toString(16)}`) +
`&lt;${info.id ?? `0x${info.code.toString(16)}`}&gt; ` +
(info.title ?? "") +
(info.variant === "left"
? " (left)"
: info.variant === "right"

View File

@@ -127,12 +127,11 @@
const clickedGroup = groupParent.children.item(index) as SVGGElement;
const nextAction = get(layout)[get(activeLayer)]?.[keyInfo.id];
const currentAction = get(deviceLayout)[get(activeLayer)]?.[keyInfo.id];
if (!nextAction || !currentAction) return;
const component = new ActionSelector({
target: document.body,
props: {
currentAction,
nextAction: nextAction.isApplied ? undefined : nextAction.action,
nextAction: nextAction?.isApplied ? undefined : nextAction?.action,
},
});
const dialog = document.querySelector("dialog > div") as HTMLDivElement;

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { KEYMAP_CODES } from "$lib/serial/keymap-codes";
import { KEYMAP_CATEGORIES, KEYMAP_CODES } from "$lib/serial/keymap-codes";
import FlexSearch from "flexsearch";
import LL from "../../../i18n/i18n-svelte";
import { action } from "$lib/title";
@@ -35,7 +35,7 @@
resizeObserver?.disconnect();
});
let index = new FlexSearch.Index({ tokenize: "full" });
let index = new FlexSearch.Index();
let searchIndex = writable<FlexSearch.Index | undefined>(undefined);
$: {
abortIndexing?.();
@@ -43,22 +43,72 @@
buildIndex($chords, $osLayout).then(searchIndex.set);
}
function plainPhrase(phrase: number[], osLayout: Map<string, string>) {
return phrase
function encodeChord(chord: ChordInfo, osLayout: Map<string, string>) {
const plainPhrase: string[] = [""];
const extraActions: string[] = [];
const extraCodes: string[] = [];
for (const actionCode of chord.phrase ?? []) {
const action = KEYMAP_CODES.get(actionCode);
if (!action) {
extraCodes.push(`0x${actionCode.toString(16)}`);
continue;
}
const osCode = action.keyCode && osLayout.get(action.keyCode);
const token = osCode?.length === 1 ? osCode : action.display || action.id;
if (!token) {
extraCodes.push(`0x${action.code.toString(16)}`);
continue;
}
if (/^\s$/.test(token) && plainPhrase.at(-1) !== "") {
plainPhrase.push("");
} else if (token.length === 1) {
plainPhrase[plainPhrase.length - 1] =
plainPhrase[plainPhrase.length - 1] + token;
} else {
extraActions.push(token);
}
}
if (chord.phrase?.[0] === 298) {
plainPhrase.push("suffix");
}
if (
["ARROW_LT", "ARROW_RT", "ARROW_UP", "ARROW_DN"].some((it) =>
extraActions.includes(it),
)
) {
plainPhrase.push("cursor warp");
}
if (
["CTRL", "ALT", "GUI", "ENTER", "TAB"].some((it) =>
extraActions.includes(it),
)
) {
plainPhrase.push("macro");
}
if (chord.actions[0] !== 0) {
plainPhrase.push("compound");
}
const input = chord.actions
.slice(chord.actions.lastIndexOf(0) + 1)
.map((it) => {
const info = KEYMAP_CODES.get(it);
if (!info) return "";
if (!info) return `0x${it.toString(16)}`;
const osCode = info.keyCode && osLayout.get(info.keyCode);
const result = osCode?.length === 1 ? osCode : info.id;
return result ?? `0x${it.toString(16)}`;
});
const bestGuess =
(info.keyCode && osLayout.get(info.keyCode)) ||
info.display ||
info.id ||
"";
return bestGuess.length === 1 ? bestGuess : "";
})
.filter((it) => !!it)
.join("");
return [
...plainPhrase,
`+${input.join("+")}`,
...new Set(extraActions),
...new Set(extraCodes),
].join(" ");
}
async function buildIndex(
@@ -66,7 +116,23 @@
osLayout: Map<string, string>,
): Promise<FlexSearch.Index> {
if (chords.length === 0 || !browser) return index;
index = new FlexSearch.Index({ tokenize: "full" });
index = new FlexSearch.Index({
tokenize: "full",
encode(phrase: string) {
return phrase.split(/\s+/).flatMap((it) => {
if (/^[A-Z_]+$/.test(it)) {
return it;
}
if (it.startsWith("+")) {
return it
.slice(1)
.split("+")
.map((it) => `+${it}`);
}
return it.toLowerCase();
});
},
});
let abort = false;
abortIndexing = () => {
abort = true;
@@ -78,7 +144,8 @@
progress = i;
if ("phrase" in chord) {
await index.addAsync(i, plainPhrase(chord.phrase, osLayout));
console.log(encodeChord(chord, osLayout));
await index.addAsync(i, encodeChord(chord, osLayout));
}
}
return index;