Skip to content

Commit

Permalink
first steps at adding preonic support to chrysalis. not fully functio…
Browse files Browse the repository at this point in the history
…nal yet
  • Loading branch information
obra committed Nov 25, 2024
1 parent 48cb94a commit 741837d
Show file tree
Hide file tree
Showing 7 changed files with 366 additions and 20 deletions.
120 changes: 120 additions & 0 deletions src/api/hardware-keyboardio-preonic/components/Keymap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// -*- mode: js-jsx -*-
/* chrysalis-hardware-keyboardio-preonic -- Chrysalis Preonic support
* Copyright (C) 2019-2022 Keyboardio, Inc.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import KeymapDB from "@api/focus/keymap/db";
import React from "react";

const db = new KeymapDB();

const Keymap = (props) => {
const keymap =
props.keymap ||
Array(63)
.fill()
.map(() => 0);
const KeySpacingY = 64;
const keySpacingX = 64;

const layer = props.index;
const onKeySelect = props.onKeySelect;

const getKey = (row, col) => {
if (!props.keymap) return null;
return keymap[row === 0 ? col : row * 12 + col];
};

const isActive = (row, col) => {
return props.selectedKey == (row === 0 ? col : row * 12 + col);
};

const Key = (props) => {
const { row, col, x, y } = props;
const active = isActive(row, col);
const key = getKey(row, col);
const onClick = onKeySelect;
const keyIndex = row === 0 ? col : row * 12 + col;
const strokeColor = "#b3b3b3";
const stroke = active ? "#f3b3b3" : strokeColor;
const height = props.height || 44;
const width = props.width || 44;
const bottom = y + height - 5;

let textColor = "#ffffff";
const buttonColor = "#000000";
let legendClass = "";
let mainLegendClass = "";
const legend = key && db.format(key, { layerNames: props.layerNames });
if (key && (legend.main || "").length <= 1 && !legend.hint) legendClass = "short-legend";
if (key && (legend.main || "").length <= 1) mainLegendClass = "short-legend";
if (key && key.code == 0) textColor = "#888888";
return (
<g onClick={onClick} className="key" data-key-index={keyIndex} data-layer={layer}>
<rect x={x} y={y} rx={2} width={width} height={height} stroke={stroke} strokeWidth={1.55} fill={buttonColor} />
<text x={x + 5} y={y + 14} fill={textColor} className={legendClass}>
{legend?.hint}
</text>
<text x={x + 5} y={bottom} fill={textColor} className={mainLegendClass}>
{legend?.main}
</text>
</g>
);
};

const { classes, maxHeight } = props;
return (
<svg
viewBox="0 0 855 362"
xmlns="http://www.w3.org/2000/svg"
preserveAspectRatio="xMinYMin meet"
style={{
maxHeight: maxHeight || "100%",
backgroundRepeat: "no-repeat",
backgroundSize: "100%",
}}
className={props.className || "layer"}
>
<g transform="translate(80,0)">
{/* Row 0: Top 3-key row (indices 0-2) */}
<g>
{[9, 10, 11].map((col) => (
<Key key={`0,${col}`} layerNames={props.layerNames} row={0} col={col} x={col * keySpacingX} y={0} />
))}
</g>

{/* Rows 1-5: Main 5x12 grid (indices 3-62) */}
<g>
{[1, 2, 3, 4, 5].map((row) => (
<g key={row}>
{[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].map((col) => (
<Key
key={`${row},${col}`}
layerNames={props.layerNames}
row={row}
col={col}
x={col * keySpacingX}
y={row * KeySpacingY + KeySpacingY * 0.25}
/>
))}
</g>
))}
</g>
</g>
</svg>
);
};

export default Keymap;
105 changes: 105 additions & 0 deletions src/api/hardware-keyboardio-preonic/components/keymap/Key.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// -*- mode: js-jsx -*-
/* chrysalis-bundle-keyboardio -- Chrysalis Bundle for Keyboard.io
* Copyright (C) 2018-2022 Keyboardio, Inc.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import KeymapDB from "@api/focus/keymap/db";
import useTheme from "@mui/material/styles/useTheme";
import React from "react";

const db = new KeymapDB();

const led_map = [
[3, 4, 11, 12, 19, 20, 26, 27, 36, 37, 43, 44, 51, 52, 59, 60],
[2, 5, 10, 13, 18, 21, 25, 28, 35, 38, 42, 45, 50, 53, 58, 61],
[1, 6, 9, 14, 17, 22, 24, 29, 34, 39, 41, 46, 49, 54, 57, 62],
[0, 7, 8, 15, 16, 23, 31, 30, 33, 32, 40, 47, 48, 55, 56, 63],
];

const getLEDIndex = (row, col) => {
return led_map[parseInt(row)][parseInt(col)];
};

const Key = (props) => {
const theme = useTheme();

let shape;
const keyIndex = parseInt(props.row) * 16 + parseInt(props.col);
let extraLabel;

const key = props.keymap[keyIndex];

const stroke = props.selectedKey === keyIndex ? theme.palette.primary.light : theme.palette.grey[500];

const getColor = () => {
const ledIndex = led_map[parseInt(props.row)][parseInt(props.col)];
const colorIndex = props.colormap[ledIndex];
const color = props.palette[colorIndex].rgb;
return color;
};

if (props.palmKey) {
shape = (
<ellipse
fill={getColor()}
stroke={stroke}
strokeWidth="5.5"
cx="610.765"
cy="953.469"
rx="75.6"
ry="56.001"
transform={props.shape}
/>
);
} else {
shape = <path fill={getColor()} stroke={stroke} strokeWidth="3.5" d={props.shape} />;
}

let legendClass = "";
let mainLegendClass = "";
const legend = key && db.format(key, { layerNames: props.layerNames });
if (key && (legend.main || "").length <= 1 && !legend.hint) legendClass = "short-legend";
if (key && (legend.main || "").length <= 1) mainLegendClass = "short-legend";

if (props.extraLabelTransform && legend?.hint) {
extraLabel = (
<g transform={props.extraLabelTransform}>
<text x={props.x} y={props.y - 3} className={legendClass} fill={theme.palette.getContrastText(getColor())}>
{legend?.hint}
</text>
</g>
);
}

return (
<g
onClick={props.onClick}
className="key"
data-key-index={keyIndex}
data-layer={props.layer}
data-led-index={getLEDIndex(props.row, props.col)}
>
{shape}
<g transform={props.primaryLabelTransform}>
<text x={props.x} y={props.y} fill={theme.palette.getContrastText(getColor())} className={mainLegendClass}>
{legend?.main}
</text>
</g>
{extraLabel}
</g>
);
};

export default Key;
65 changes: 65 additions & 0 deletions src/api/hardware-keyboardio-preonic/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/* Chrysalis -- Kaleidoscope Command Center
* Copyright (C) 2018-2022 Keyboardio, Inc.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { flash, flashers } from "@api/flash";

import Keymap from "./components/Keymap";


const Preonic = {
info: {
vendor: "Keyboardio",
product: "Preonic",
firmwareType: "bin",
displayName: "Keyboardio Preonic",
urls: [
{
name: "Homepage",
url: "https://shop.keyboard.io/",
},
{
name: "Forum",
url: "https://community.keyboard.io/",
},
{
name: "Chat",
url: "https://keyboard.io/discord-invite",
},
],
},
usb: {
vendorId: 0x3496,
productId: 0x00A0,
bootloader: {
vendorId: 0x3496,
productId: 0x00A1,
protocol: "nrfdfu",
},
},
keyboard: {
rows: 5,
columns: 12,
},
components: {
keymap: Keymap,
},

flash: async (port, filename, options) => {
return flash(flashers.dfuUtil, null, port, filename, options);
},
};

export { Preonic };
8 changes: 8 additions & 0 deletions src/api/hardware/devices.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// This file is auto-generated. Do not edit manually.
import { Atreus2 } from "@api/hardware-keyboardio-atreus2";
import { Model01, Model100 } from "@api/hardware-keyboardio-model01";
import { Preonic } from "@api/hardware-keyboardio-preonic";

export const Hardware = {
devices: [Atreus2, Model01, Model100, Preonic],
};
23 changes: 3 additions & 20 deletions src/api/hardware/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { Atreus2 } from "@api/hardware-keyboardio-atreus2";
import { Model01, Model100 } from "@api/hardware-keyboardio-model01";

// We have two arrays here: the `serial` array contains hardware descriptors
// where a serial device is to be used in either application or bootloader mode.
// Similarly, the `nonSerial` array contains hardware descriptors where either
// the application or the bootloader mode is without a serial port.
//
// For example, in the case of the Model01 and the Keyboardio Atreus, both the
// bootloader and the application mode are accessed through a serial port, so
// they only appear in the `serial` array.
//
// In case of the Model100, the bootloader is *not* accessed via a serial port,
// but the application mode is, so it's in both.
//
export const Hardware = {
devices: [Model01, Model100, Atreus2],
serial: [Model01, Model100, Atreus2],
nonSerial: [Model100],
};
import { Hardware } from "./devices";

export function getDeviceProtocol(vid, pid) {
for (const device of Object.values(Hardware.devices)) {
Expand Down Expand Up @@ -117,3 +98,5 @@ export function getDfuDevices() {

return result;
}

export { Hardware };
2 changes: 2 additions & 0 deletions tools/precompile.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const fs = require("fs");
const { loadAllKeymaps} = require("./precompile/cldr_data.js");
const { extractLanguageNames } = require("./precompile/cldr_languages.js");
const { generateI18nIndex } = require("./precompile/i18n.js");
const { generateHardwareIndex } = require("./precompile/hardware.js");

const generateCLDRData = async () => {
if (fs.existsSync("./src/api/focus/keymap/.cldr_data_generated")) {
Expand All @@ -43,3 +44,4 @@ const generateCLDRData = async () => {

generateCLDRData();
generateI18nIndex();
generateHardwareIndex();
Loading

0 comments on commit 741837d

Please sign in to comment.