seveibar/keyboard-utils
Based on the code provided, here's a concise summary of the electronic component: A keyboard utility library for parsing and generating keyboard layouts using the Keyboard Layout Editor (KLE) JSON format, with support for generating key matrices, reference designators, and diode routing for keyboard PCBs. Key features: - Parses KLE JSON layouts into key coordinate and metadata objects - Supports various keyboard layouts (60%, ANSI, ISO, Ergodox, etc.) - Generates unique reference designators for keys - Provides utility for adding diode routing in key matrices - TypeScript-based with React and tscircuit integration The library allows keyboard designers to easily convert layout designs into structured, machine-readable keyboard specifications.
- Version
- 0.0.19
- License
- unset
- Stars
- 3
dist/index.cjs
PCB
Schematic
'use strict';
var jsxRuntime = require('react/jsx-runtime');
require('react');
var core = require('@tscircuit/core');
const refDesMap = {
"~": "K_TILDE",
"~`": "K_TILDE",
"!": "K_EXCLAMATION",
"@": "K_AT",
"#": "K_HASH",
$: "K_DOLLAR",
"%": "K_PERCENT",
"^": "K_CARET",
"&": "K_AMPERSAND",
"*": "K_ASTERISK",
"(": "K_LPAREN",
")": "K_RPAREN",
"{": "K_LBRACE",
"}": "K_RBRACE",
"|": "K_PIPE",
"[": "K_LSQBRAK",
"]": "K_RSQBRAK",
'"': "K_QUOTE",
"'": "K_SINGLEQUOTE",
"<": "K_LT",
">": "K_GT",
"?": "K_QUESTION",
"/": "K_SLASH",
windows: "K_WINDOWS",
win: "K_WINDOWS",
menu: "K_MENU",
"caps lock": "K_CAPSLOCK",
":": "K_COLON",
";": "K_SEMICOLON",
"1": "K_N1",
"2": "K_N2",
"3": "K_N3",
"4": "K_N4",
"5": "K_N5",
"6": "K_N6",
"7": "K_N7",
"8": "K_N8",
"9": "K_N9",
"0": "K_N0",
"-": "K_MINUS",
"+": "K_PLUS",
backspace: "K_BACKSPACE",
tab: "K_TAB",
" ": "K_SPACE",
enter: "K_ENTER",
shift: "K_SHIFT",
ctrl: "K_CTRL",
alt: "K_ALT",
escape: "K_ESCAPE",
arrowleft: "K_ARROW_LEFT",
arrowright: "K_ARROW_RIGHT",
arrowup: "K_ARROW_UP",
arrowdown: "K_ARROW_DOWN",
backquote: "K_BACKQUOTE",
quote: "K_QUOTE",
semicolon: "K_SEMICOLON",
comma: "K_COMMA",
period: "K_PERIOD",
slash: "K_SLASH",
backslash: "K_BACKSLASH",
bracketleft: "K_BRACKET_LEFT",
bracketright: "K_BRACKET_RIGHT",
a: "K_A",
b: "K_B",
c: "K_C",
d: "K_D",
e: "K_E",
f: "K_F",
g: "K_G",
h: "K_H",
i: "K_I",
j: "K_J",
k: "K_K",
l: "K_L",
m: "K_M",
n: "K_N",
o: "K_O",
p: "K_P",
q: "K_Q",
r: "K_R",
s: "K_S",
t: "K_T",
u: "K_U",
v: "K_V",
w: "K_W",
x: "K_X",
y: "K_Y",
z: "K_Z",
};
const getRefDesForKey = (key) => {
const normKeyLabels = key.toLowerCase().split("\n");
for (const normKeyLabel of normKeyLabels) {
if (normKeyLabel in refDesMap) {
return refDesMap[normKeyLabel];
}
}
if (key === "") {
return "K_SPACE";
}
if (key.match(/^[a-zA-Z0-9]+$/)) {
return `K_${key.toUpperCase()}`;
}
throw new Error(`No defined refDes for key "${key}"`);
};
/**
* Assigns logical row/col coordinates to keys based on their physical positions
* for the ergodox keyboard layout
*/
function assignRowColByPosition(keys) {
const keysWithNewRowCol = keys.map(key => ({ ...key }));
// Separate keys by section
const leftMainKeys = keysWithNewRowCol.filter(key => key.rotation === 0 && key.x < 150);
const rightMainKeys = keysWithNewRowCol.filter(key => key.rotation === 0 && key.x > 150);
const thumbClusterKeys = keysWithNewRowCol.filter(key => key.rotation !== 0);
// Function to assign row/col based on position grid
function assignRowColByPosition(keys, isRightSide = false) {
// Create a position-based grid
const GRID_SIZE = 19.05; // Standard key unit size
keys.forEach(key => {
// Calculate grid position based on physical coordinates
const gridRow = Math.round(-key.y / GRID_SIZE); // Negative y because y increases downward
const gridCol = Math.round(key.x / GRID_SIZE);
key.row = gridRow;
key.col = isRightSide ? gridCol : gridCol; // Keep original columns for now
});
}
// Assign positions for main keys
assignRowColByPosition(leftMainKeys, false);
assignRowColByPosition(rightMainKeys, true);
// Normalize row numbers to start from 0
const allMainKeys = [...leftMainKeys, ...rightMainKeys];
const minRow = Math.min(...allMainKeys.map(k => k.row));
allMainKeys.forEach(key => {
key.row = key.row - minRow;
});
// For ergodox specifically, we want to organize columns better
// Left side: find the actual column positions
const leftCols = [...new Set(leftMainKeys.map(k => k.col))].sort((a, b) => a - b);
const rightCols = [...new Set(rightMainKeys.map(k => k.col))].sort((a, b) => a - b);
// Remap left side columns to 0-based indexing
leftMainKeys.forEach(key => {
key.col = leftCols.indexOf(key.col);
});
// Remap right side columns to continue after left side
const maxLeftCol = Math.max(...leftMainKeys.map(k => k.col));
rightMainKeys.forEach(key => {
const rightIndex = rightCols.indexOf(key.col);
key.col = maxLeftCol + 1 + rightIndex;
});
// Handle thumb clusters
const leftThumbKeys = thumbClusterKeys.filter(key => key.rotation < 0);
const rightThumbKeys = thumbClusterKeys.filter(key => key.rotation > 0);
// Sort thumb keys by Y position first, then X
leftThumbKeys.sort((a, b) => a.y - b.y || a.x - b.x);
rightThumbKeys.sort((a, b) => a.y - b.y || a.x - b.x);
// Assign thumb cluster rows (starting after main key rows)
const maxMainRow = Math.max(...allMainKeys.map(k => k.row));
leftThumbKeys.forEach((key, index) => {
key.row = maxMainRow + 1 + Math.floor(index / 3);
key.col = index % 3;
});
const maxLeftThumbCol = Math.max(...leftMainKeys.map(k => k.col));
rightThumbKeys.forEach((key, index) => {
key.row = maxMainRow + 1 + Math.floor(index / 3);
key.col = maxLeftThumbCol + 1 + (index % 3);
});
return keysWithNewRowCol;
}
// Define the types for keyboard-layout-editor.com JSON format
// Helper function to parse keyboard-layout-editor JSON
const parseKLELayout = (layout) => {
// Default key size in millimeters
const KEY_SIZE = 19.05; // Standard keycap size (19.05mm or 0.75 inches)
const keys = [];
let current = {
x: 0, y: 0, x2: 0, y2: 0,
width: 1, height: 1, width2: 1, height2: 1,
rotation_angle: 0, rotation_x: 0, rotation_y: 0,
nub: false,
stepped: false, decal: false};
let cluster = { x: 0, y: 0 };
const nameCounters = new Map();
// Process each row
for (let r = 0; r < layout.length; r++) {
if (layout[r] instanceof Array) {
let colIndex = 0;
// Process each item in the row
for (let k = 0; k < layout[r].length; k++) {
const item = layout[r][k];
if (typeof item === 'string') {
// This is a key
let refDes = getRefDesForKey(item);
if (nameCounters.has(refDes)) {
// Edit the original item to include the counter (if it doesn't have it)
const ogKey = keys.find((k) => k.name === refDes);
if (ogKey) {
ogKey.name = `${refDes}${nameCounters.get(refDes)}`;
}
nameCounters.set(refDes, nameCounters.get(refDes) + 1);
refDes = `${refDes}${nameCounters.get(refDes)}`;
}
else {
nameCounters.set(refDes, 1);
}
const newKey = {
name: refDes,
x: (current.x + current.width / 2) * KEY_SIZE,
y: -(current.y + current.height / 2) * KEY_SIZE,
width: current.width * KEY_SIZE,
height: current.height * KEY_SIZE,
rotation: current.rotation_angle,
rotationX: current.rotation_x * KEY_SIZE,
rotationY: -current.rotation_y * KEY_SIZE,
row: r,
col: colIndex,
};
keys.push(newKey);
// Set up for the next key (from KLE logic)
current.x += current.width;
current.width = current.height = 1;
current.x2 = current.y2 = current.width2 = current.height2 = 0;
current.nub = current.stepped = current.decal = false;
colIndex++;
}
else {
// This is a property object
if (item.r != null) {
if (k != 0)
throw new Error("'r' can only be used on the first key in a row");
current.rotation_angle = item.r;
}
if (item.rx != null) {
if (k != 0)
throw new Error("'rx' can only be used on the first key in a row");
current.rotation_x = cluster.x = item.rx;
// Extend current with cluster (reset position to rotation center)
current.x = cluster.x;
current.y = cluster.y;
}
if (item.ry != null) {
if (k != 0)
throw new Error("'ry' can only be used on the first key in a row");
current.rotation_y = cluster.y = item.ry;
// Extend current with cluster (reset position to rotation center)
current.x = cluster.x;
current.y = cluster.y;
}
if (item.a != null) {
item.a;
}
if (item.x) {
current.x += item.x;
}
if (item.y) {
current.y += item.y;
}
if (item.w) {
current.width = current.width2 = item.w;
}
if (item.h) {
current.height = current.height2 = item.h;
}
// ... other properties would go here
}
}
// End of the row (from KLE logic)
current.y++;
}
// Reset x to rotation_x at end of row (from KLE logic)
current.x = current.rotation_x;
}
// Apply logical row/col assignment based on physical positions
return assignRowColByPosition(keys);
};
const pinLabels$2 = {
pin1: ["C"],
pin2: ["A"],
};
const A_1N4148WS = (props) => {
return (jsxRuntime.jsx("chip", { pinLabels: pinLabels$2, symbolName: "diode", supplierPartNumbers: {
jlcpcb: ["C57759"],
}, manufacturerPartNumber: "A_1N4148WS", footprint: jsxRuntime.jsxs("footprint", { children: [jsxRuntime.jsx("smtpad", { portHints: ["pin1"], pcbX: "-1.1725910000000113mm", pcbY: "0mm", width: "0.9999979999999999mm", height: "0.7500112mm", shape: "rect" }), jsxRuntime.jsx("smtpad", { portHints: ["pin2"], pcbX: "1.1725910000000113mm", pcbY: "0mm", width: "0.9999979999999999mm", height: "0.7500112mm", shape: "rect" }), jsxRuntime.jsx("silkscreenpath", { route: [
{ x: 0.9012427999999773, y: -0.726211400000011 },
{ x: 0.9012427999999773, y: -0.5199887999999646 },
] }), jsxRuntime.jsx("silkscreenpath", { route: [
{ x: 0.9012427999999773, y: 0.726211400000011 },
{ x: 0.9012427999999773, y: 0.5299964000000728 },
] }), jsxRuntime.jsx("silkscreenpath", { route: [
{ x: -0.8512047999998913, y: 0.726211400000011 },
{ x: 0.9012427999999773, y: 0.726211400000011 },
] }), jsxRuntime.jsx("silkscreenpath", { route: [
{ x: -0.8512047999998913, y: -0.726211400000011 },
{ x: 0.9012427999999773, y: -0.726211400000011 },
] }), jsxRuntime.jsx("silkscreenpath", { route: [
{ x: -0.44676059999994777, y: 0.726211400000011 },
{ x: -0.44676059999994777, y: -0.726211400000011 },
] })] }), cadModel: {
objUrl: "https://modelcdn.tscircuit.com/easyeda_models/download?uuid=973acf8a660c48b1975f1ba1c890421a&pn=C57759",
rotationOffset: { x: 0, y: 0, z: 0 },
positionOffset: { x: 0, y: 0, z: 0 },
}, ...props }));
};
const pinLabels$1 = {
"1": "pin1",
"2": "pin2",
};
const pinNames$1 = Object.values(pinLabels$1);
const KeyHotSocket = (props) => {
return (jsxRuntime.jsx("pushbutton", { layer: "bottom", ...props, footprint: jsxRuntime.jsxs("footprint", { children: [jsxRuntime.jsx("hole", { pcbX: "3.1749999999999545mm", pcbY: "-1.2699999999999818mm", diameter: "2.9999939999999996mm" }), jsxRuntime.jsx("hole", { pcbX: "-3.1749999999999545mm", pcbY: "1.2700000000000955mm", diameter: "2.9999939999999996mm" }), jsxRuntime.jsx("smtpad", { portHints: ["2"], pcbX: "6.724904000000038mm", pcbY: "-1.2699999999999818mm", width: "2.8999941999999996mm", height: "2.4999949999999997mm", shape: "rect" }), jsxRuntime.jsx("smtpad", { portHints: ["1"], pcbX: "-6.724904000000038mm", pcbY: "1.2699999999999818mm", width: "2.8999941999999996mm", height: "2.4999949999999997mm", shape: "rect" }), jsxRuntime.jsx("silkscreenpath", { route: [
{ x: -5.461000000000013, y: -0.4611370000000079 },
{ x: -5.461000000000013, y: -2.9209999999999354 },
{ x: -5.461000000000013, y: -2.9209999999999354 },
] }), jsxRuntime.jsx("silkscreenpath", { route: [
{ x: 5.4500017999999955, y: -2.950006799999869 },
{ x: -5.461000000000013, y: -2.950006799999869 },
] }), jsxRuntime.jsx("silkscreenpath", { route: [
{ x: 0.18298159999994823, y: 1.0549889999999778 },
{ x: 5.450027199999909, y: 1.0549889999999778 },
] }), jsxRuntime.jsx("silkscreenpath", { route: [
{ x: 5.450027199999909, y: 1.0549889999999778 },
{ x: 5.450027199999909, y: 0.4611370000000079 },
] }), jsxRuntime.jsx("silkscreenpath", { route: [
{ x: -2.944114000000127, y: 2.9450030000000424 },
{ x: -5.461000000000013, y: 2.9450030000000424 },
] }), jsxRuntime.jsx("silkscreenpath", { route: [
{ x: -1.707006999999976, y: 2.9450030000000424 },
{ x: -2.944114000000127, y: 2.9450030000000424 },
] }), jsxRuntime.jsx("silkscreenpath", { route: [
{ x: -1.707006999999976, y: 2.9450030000000424 },
{ x: -1.460311886129034, y: 2.9288336092640748 },
{ x: -1.2178378661753868, y: 2.8806021044970294 },
{ x: -0.9837338087377248, y: 2.801133754218995 },
{ x: -0.762005367588813, y: 2.6917883071702136 },
{ x: -0.5564464426572613, y: 2.5544367262343712 },
{ x: -0.37057426423848483, y: 2.3914291751993915 },
{ x: -0.20756921118118044, y: 2.2055548061152876 },
{ x: -0.07022039279377168, y: 1.9999940353145576 },
{ x: 0.03912207440475868, y: 1.7782641246765252 },
{ x: 0.11858727851722506, y: 1.5441589992735771 },
{ x: 0.1668155246366041, y: 1.301684331151364 },
{ x: 0.18298159999994823, y: 1.0549889999999778 },
] })] }), supplierPartNumbers: {
jlcpcb: ["C41430893"],
}, cadModel: {
objUrl: "https://modelcdn.tscircuit.com/easyeda_models/download?uuid=c886ec2b42464573a88fc1f647577a49&pn=C5184526",
rotationOffset: { x: 0, y: 0, z: 0 },
positionOffset: { x: 0, y: 0, z: 0 },
}, pinLabels: pinLabels$1, schPortArrangement: {
leftSide: {
direction: "top-to-bottom",
pins: [1],
},
rightSide: {
direction: "bottom-to-top",
pins: [2],
},
} }));
};
core.createUseComponent(KeyHotSocket, pinNames$1);
const pinLabels = {
"1": "pin1",
"2": "pin2",
};
const pinNames = Object.values(pinLabels);
const KeyShaftForHotSocket = (props) => {
return (jsxRuntime.jsx("chip", { ...props, noSchematicRepresentation: true, schWidth: 0.1, schHeight: 0.1, supplierPartNumbers: {
jlcpcb: ["C400227"],
}, footprint: jsxRuntime.jsxs("footprint", { children: [jsxRuntime.jsx("hole", { pcbX: "0.6349999999999909mm", pcbY: "-3.1149987999999666mm", diameter: "4.1999916mm" }), jsxRuntime.jsx("silkscreenpath", { route: [
{ x: -7.165009800000007, y: 4.685011000000031 },
{ x: 8.435009799999989, y: 4.685011000000031 },
] }), jsxRuntime.jsx("silkscreenpath", { route: [
{ x: -7.165009800000007, y: -10.915008600000078 },
{ x: 8.435009799999989, y: -10.915008600000078 },
] }), jsxRuntime.jsx("silkscreenpath", { route: [
{ x: -7.165009800000007, y: 4.685011000000031 },
{ x: -7.165009800000007, y: -10.915008600000078 },
] }), jsxRuntime.jsx("silkscreenpath", { route: [
{ x: 8.435009799999989, y: 4.685011000000031 },
{ x: 8.435009799999989, y: -10.915008600000078 },
] })] }), cadModel: {
objUrl: "https://modelcdn.tscircuit.com/easyeda_models/download?uuid=c00f29e7afb64c29bc388e168980ded2&pn=C400227",
rotationOffset: { x: 0, y: 0, z: 90 },
positionOffset: { x: 0, y: 0, z: 0 },
}, pinLabels: pinLabels, schPinSpacing: 0.75, schPortArrangement: {} }));
};
core.createUseComponent(KeyShaftForHotSocket, pinNames);
const Key = (props) => {
return (jsxRuntime.jsxs("group", { pcbX: props.pcbX, pcbY: props.pcbY, schX: props.schX, schY: props.schY, children: [jsxRuntime.jsx(KeyHotSocket, { name: props.name, connections: props.connections, pcbRotation: props.pcbRotation }), jsxRuntime.jsx(KeyShaftForHotSocket, { name: `${props.name}_shaft`, pcbX: 0, pcbY: -0.52, pcbRotation: props.pcbRotation }), jsxRuntime.jsx("footprint", { children: jsxRuntime.jsx("silkscreentext", { text: props.name, pcbY: 5 }) })] }));
};
const KeyMatrix = ({ layout, rowToMicroPin, colToMicroPin, name = "KB", pcbX = 0, pcbY = 0, schX = 0, schY = 0, }) => {
const keys = parseKLELayout(layout);
const minX = Math.min(...keys.map((k) => k.x));
const maxX = Math.max(...keys.map((k) => k.x + k.width));
const minY = Math.min(...keys.map((k) => k.y));
const maxY = Math.max(...keys.map((k) => k.y + k.height));
// Group keys by rotation and rotation center
const keyGroups = new Map();
keys.forEach(key => {
const groupKey = `${key.rotation}_${key.rotationX}_${key.rotationY}`;
if (!keyGroups.has(groupKey)) {
keyGroups.set(groupKey, []);
}
keyGroups.get(groupKey).push(key);
});
return (jsxRuntime.jsx("group", { pcbX: pcbX, pcbY: pcbY, schX: schX, schY: schY, children: Array.from(keyGroups.entries()).map(([groupKey, groupKeys]) => {
const firstKey = groupKeys[0];
const hasRotation = firstKey.rotation !== 0;
if (hasRotation) {
// For rotated key groups (thumb clusters), position at absolute rotation center
const keyboardCenterX = (minX + maxX) / 2;
const keyboardCenterY = (minY + maxY) / 2;
const rotationCenterX = firstKey.rotationX - keyboardCenterX;
const rotationCenterY = firstKey.rotationY - keyboardCenterY;
return (jsxRuntime.jsx("group", { pcbX: rotationCenterX, pcbY: rotationCenterY, pcbRotation: firstKey.rotation, children: groupKeys.map((key) => {
// Position keys relative to their rotation center
const relX = key.x - key.rotationX;
const relY = key.y - key.rotationY;
return (jsxRuntime.jsxs("group", { pcbX: relX, pcbY: relY, schX: relX / 5, schY: relY / 7, children: [jsxRuntime.jsx(Key, { name: key.name }), rowToMicroPin?.[key.row] !== undefined && (jsxRuntime.jsx(A_1N4148WS, { name: `${key.name}_DIO`, connections: {
A: `.${key.name} .pin1`,
C: rowToMicroPin[key.row],
}, pcbX: 0.5, pcbY: -13.5, schY: -1, layer: "bottom" })), colToMicroPin?.[key.col] !== undefined && (jsxRuntime.jsx("trace", { from: `.${key.name} .pin2`, to: colToMicroPin[key.col] }))] }, key.name));
}) }, groupKey));
}
else {
// For non-rotated key groups, position relative to keyboard center
return (jsxRuntime.jsx("group", { children: groupKeys.map((key) => {
const relX = key.x - (minX + maxX) / 2;
const relY = key.y - (minY + maxY) / 2;
return (jsxRuntime.jsxs("group", { pcbX: relX, pcbY: relY, schX: relX / 5, schY: relY / 7, children: [jsxRuntime.jsx(Key, { name: key.name }), rowToMicroPin?.[key.row] !== undefined && (jsxRuntime.jsx(A_1N4148WS, { name: `${key.name}_DIO`, connections: {
A: `.${key.name} .pin1`,
C: rowToMicroPin[key.row],
}, pcbX: 0.5, pcbY: -13.5, schY: -1, layer: "bottom" })), colToMicroPin?.[key.col] !== undefined && (jsxRuntime.jsx("trace", { from: `.${key.name} .pin2`, to: colToMicroPin[key.col] }))] }, key.name));
}) }, groupKey));
}
}) }));
};
// biome-ignore lint: This file contains keyboard layout data
// From: https://www.keyboard-layout-editor.com/#/
const layouts = {
default60: [
["~\n`", "!\n1", "@\n2", "#\n3", "$\n4", "%\n5", "^\n6", "&\n7", "*\n8", "(\n9", ")\n0", "_\n-", "+\n=", { w: 2 }, "Backspace"],
[{ w: 1.5 }, "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "{\n[", "}\n]", { w: 1.5 }, "|\n\\"],
[{ w: 1.75 }, "Caps Lock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ":\n;", "\"\n'", { w: 2.25 }, "Enter"],
[{ w: 2.25 }, "Shift", "Z", "X", "C", "V", "B", "N", "M", "<\n,", ">\n.", "?\n/", { w: 2.75 }, "Shift"],
[{ w: 1.25 }, "Ctrl", { w: 1.25 }, "Win", { w: 1.25 }, "Alt", { a: 7, w: 6.25 }, "", { a: 4, w: 1.25 }, "Alt", { w: 1.25 }, "Win", { w: 1.25 }, "Menu", { w: 1.25 }, "Ctrl"]
],
ansi104: [
["Esc", { x: 1 }, "F1", "F2", "F3", "F4", { x: 0.5 }, "F5", "F6", "F7", "F8", { x: 0.5 }, "F9", "F10", "F11", "F12", { x: 0.25 }, "PrtSc", "Scroll Lock", "Pause\nBreak"],
[{ y: 0.5 }, "~\n`", "!\n1", "@\n2", "#\n3", "$\n4", "%\n5", "^\n6", "&\n7", "*\n8", "(\n9", ")\n0", "_\n-", "+\n=", { w: 2 }, "Backspace", { x: 0.25 }, "Insert", "Home", "PgUp", { x: 0.25 }, "Num Lock", "/", "*", "-"],
[{ w: 1.5 }, "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "{\n[", "}\n]", { w: 1.5 }, "|\n\\", { x: 0.25 }, "Delete", "End", "PgDn", { x: 0.25 }, "7\nHome", "8\n↑", "9\nPgUp", { h: 2 }, "+"],
[{ w: 1.75 }, "Caps Lock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ":\n;", "\"\n'", { w: 2.25 }, "Enter", { x: 3.5 }, "4\n←", "5", "6\n→"],
[{ w: 2.25 }, "Shift", "Z", "X", "C", "V", "B", "N", "M", "<\n,", ">\n.", "?\n/", { w: 2.75 }, "Shift", { x: 1.25 }, "↑", { x: 1.25 }, "1\nEnd", "2\n↓", "3\nPgDn", { h: 2 }, "Enter"],
[{ w: 1.25 }, "Ctrl", { w: 1.25 }, "Win", { w: 1.25 }, "Alt", { a: 7, w: 6.25 }, "", { a: 4, w: 1.25 }, "Alt", { w: 1.25 }, "Win", { w: 1.25 }, "Menu", { w: 1.25 }, "Ctrl", { x: 0.25 }, "←", "↓", "→", { x: 0.25, w: 2 }, "0\nIns", ".\nDel"]
],
iso105: [
["Esc", { x: 1 }, "F1", "F2", "F3", "F4", { x: 0.5 }, "F5", "F6", "F7", "F8", { x: 0.5 }, "F9", "F10", "F11", "F12", { x: 0.25 }, "PrtSc", "Scroll Lock", "Pause\nBreak"],
[{ y: 0.5 }, "¬\n`", "!\n1", "\"\n2", "£\n3", "$\n4", "%\n5", "^\n6", "&\n7", "*\n8", "(\n9", ")\n0", "_\n-", "+\n=", { w: 2 }, "Backspace", { x: 0.25 }, "Insert", "Home", "PgUp", { x: 0.25 }, "Num Lock", "/", "*", "-"],
[{ w: 1.5 }, "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "{\n[", "}\n]", { x: 0.25, w: 1.25, h: 2, w2: 1.5, h2: 1, x2: -0.25 }, "Enter", { x: 0.25 }, "Delete", "End", "PgDn", { x: 0.25 }, "7\nHome", "8\n↑", "9\nPgUp", { h: 2 }, "+"],
[{ w: 1.75 }, "Caps Lock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ":\n;", "@\n'", "~\n#", { x: 4.75 }, "4\n←", "5", "6\n→"],
[{ w: 1.25 }, "Shift", "|\n\\", "Z", "X", "C", "V", "B", "N", "M", "<\n,", ">\n.", "?\n/", { w: 2.75 }, "Shift", { x: 1.25 }, "↑", { x: 1.25 }, "1\nEnd", "2\n↓", "3\nPgDn", { h: 2 }, "Enter"],
[{ w: 1.25 }, "Ctrl", { w: 1.25 }, "Win", { w: 1.25 }, "Alt", { a: 7, w: 6.25 }, "", { a: 4, w: 1.25 }, "AltGr", { w: 1.25 }, "Win", { w: 1.25 }, "Menu", { w: 1.25 }, "Ctrl", { x: 0.25 }, "←", "↓", "→", { x: 0.25, w: 2 }, "0\nIns", ".\nDel"]
],
iso60: [
["¬\n`", "!\n1", "\"\n2", "£\n3", "$\n4", "%\n5", "^\n6", "&\n7", "*\n8", "(\n9", ")\n0", "_\n-", "+\n=", { w: 2 }, "Backspace"],
[{ w: 1.5 }, "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "{\n[", "}\n]", { x: 0.25, w: 1.25, h: 2, w2: 1.5, h2: 1, x2: -0.25 }, "Enter"],
[{ w: 1.75 }, "Caps Lock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ":\n;", "@\n'", "~\n#"],
[{ w: 1.25 }, "Shift", "|\n\\", "Z", "X", "C", "V", "B", "N", "M", "<\n,", ">\n.", "?\n/", { w: 2.75 }, "Shift"],
[{ w: 1.25 }, "Ctrl", { w: 1.25 }, "Win", { w: 1.25 }, "Alt", { a: 7, w: 6.25 }, "", { a: 4, w: 1.25 }, "AltGr", { w: 1.25 }, "Win", { w: 1.25 }, "Menu", { w: 1.25 }, "Ctrl"]
],
jd40: [
["Esc", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "Back<br>Space"],
[{ w: 1.25 }, "Tab", "A", "S", "D", "F", "G", "H", "J", "K", "L", { w: 1.75 }, "Enter"],
[{ w: 1.75 }, "Shift", "Z", "X", "C", "V", "B", "N", "M", "<\n.", { w: 1.25 }, "Shift", "Fn"],
[{ w: 1.25 }, "Hyper", "Super", "Meta", { a: 7, w: 6.25 }, "", { a: 4, w: 1.25 }, "Meta", { w: 1.25 }, "Super"]
],
ergodox: [
[{ x: 3.5 }, "#\n3", { x: 10.5 }, "*\n8"],
[{ y: -0.875, x: 2.5 }, "@\n2", { x: 1 }, "$\n4", { x: 8.5 }, "&\n7", { x: 1 }, "(\n9"],
[{ y: -0.875, x: 5.5 }, "%\n5", { a: 7 }, "", { x: 4.5 }, "", { a: 4 }, "^\n6"],
[{ y: -0.875, a: 7, w: 1.5 }, "", { a: 4 }, "!\n1", { x: 14.5 }, ")\n0", { a: 7, w: 1.5 }, ""],
[{ y: -0.375, x: 3.5, a: 4 }, "E", { x: 10.5 }, "I"],
[{ y: -0.875, x: 2.5 }, "W", { x: 1 }, "R", { x: 8.5 }, "U", { x: 1 }, "O"],
[{ y: -0.875, x: 5.5 }, "T", { a: 7, h: 1.5 }, "", { x: 4.5, h: 1.5 }, "", { a: 4 }, "Y"],
[{ y: -0.875, a: 7, w: 1.5 }, "", { a: 4 }, "Q", { x: 14.5 }, "P", { a: 7, w: 1.5 }, ""],
[{ y: -0.375, x: 3.5, a: 4 }, "D", { x: 10.5 }, "K"],
[{ y: -0.875, x: 2.5 }, "S", { x: 1 }, "F", { x: 8.5 }, "J", { x: 1 }, "L"],
[{ y: -0.875, x: 5.5 }, "G", { x: 6.5 }, "H"],
[{ y: -0.875, a: 7, w: 1.5 }, "", { a: 4 }, "A", { x: 14.5 }, ":\n;", { a: 7, w: 1.5 }, ""],
[{ y: -0.625, x: 6.5, h: 1.5 }, "", { x: 4.5, h: 1.5 }, ""],
[{ y: -0.75, x: 3.5, a: 4 }, "C", { x: 10.5 }, "<\n,"],
[{ y: -0.875, x: 2.5 }, "X", { x: 1 }, "V", { x: 8.5 }, "M", { x: 1 }, ">\n."],
[{ y: -0.875, x: 5.5 }, "B", { x: 6.5 }, "N"],
[{ y: -0.875, a: 7, w: 1.5 }, "", { a: 4 }, "Z", { x: 14.5 }, "?\n/", { a: 7, w: 1.5 }, ""],
[{ y: -0.375, x: 3.5 }, "", { x: 10.5 }, ""],
[{ y: -0.875, x: 2.5 }, "", { x: 1 }, "", { x: 8.5 }, "", { x: 1 }, ""],
[{ y: -0.75, x: 0.5 }, "", "", { x: 14.5 }, "", ""],
[{ r: -45, rx: 6.5, ry: 4.25, y: -1, x: 1 }, "", ""],
[{ h: 2 }, "", { h: 2 }, "", ""],
[{ x: 2 }, ""],
[{ r: 45, rx: 13, y: -1, x: -3 }, "", ""],
[{ x: -3 }, "", { h: 2 }, "", { h: 2 }, ""],
[{ x: -3 }, ""]
],
atreus: [
[{ r: 10, rx: 1, y: -0.1, x: 2 }, "E"],
[{ y: -0.65, x: 1 }, "W", { x: 1 }, "R"],
[{ y: -0.75 }, "Q"],
[{ y: -0.9, x: 4 }, "T"],
[{ y: -0.7, x: 2 }, "D"],
[{ y: -0.65, x: 1 }, "S", { x: 1 }, "F"],
[{ y: -0.75 }, "A"],
[{ y: -0.9, x: 4 }, "G"],
[{ y: -0.7, x: 2 }, "C"],
[{ y: -0.65, x: 1 }, "X", { x: 1 }, "V"],
[{ y: -0.75 }, "Z"],
[{ y: -0.9, x: 4 }, "B"],
[{ y: -0.75, x: 5, h: 1.5 }, "Ctrl"],
[{ y: -0.95, x: 2 }, "super"],
[{ y: -0.65, x: 1 }, "Tab", { x: 1 }, "Shift"],
[{ y: -0.75 }, "Esc"],
[{ y: -0.9, x: 4 }, "Bksp"],
[{ r: -10, rx: 7, ry: 0.965, y: -0.2, x: 2 }, "I"],
[{ y: -0.65, x: 1 }, "U", { x: 1 }, "O"],
[{ y: -0.75, x: 4 }, "P"],
[{ y: -0.9 }, "Y"],
[{ y: -0.7, x: 2 }, "K"],
[{ y: -0.65, x: 1 }, "J", { x: 1 }, "L"],
[{ y: -0.75, x: 4 }, ":\n;"],
[{ y: -0.9 }, "H"],
[{ y: -0.7, x: 2 }, "<\n,"],
[{ y: -0.65, x: 1 }, "M", { x: 1 }, ">\n."],
[{ y: -0.75, x: 4 }, "?\n/"],
[{ y: -0.9 }, "N"],
[{ y: -0.75, x: -1, h: 1.5 }, "Alt"],
[{ y: -0.95, x: 2 }, "_\n-"],
[{ y: -0.65, x: 1 }, "fn", { x: 1 }, "\"\n'"],
[{ y: -0.75, x: 4 }, "Enter"],
[{ y: -0.9 }, "Space"]
],
planck: [
[{ a: 7 }, "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "Back Space"],
["Esc", "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'"],
["Shift", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "/", "Return"],
["", "Ctrl", "Alt", "Super", "⇓", { w: 2 }, "", "⇑", "←", "↓", "↑", "→"]
],
keycool84: [
[{ a: 6 }, "Esc", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", { a: 5 }, "PrtSc\nNmLk", "Pause\nScrLk", "Delete\nInsert"],
[{ a: 4 }, "~\n`", "!\n1", "@\n2", "#\n3", "$\n4", "%\n5", "^\n6", "&\n7", "*\n8", "(\n9", ")\n0", "_\n-", "+\n=", { a: 6, w: 2 }, "Backspace", "Home"],
[{ a: 4, w: 1.5 }, "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "{\n[", "}\n]", { w: 1.5 }, "|\n\\", { a: 6 }, "Page Up"],
[{ a: 4, w: 1.75 }, "Caps Lock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ":\n;", "\"\n'", { a: 6, w: 2.25 }, "Enter", "Page Down"],
[{ w: 2.25 }, "Shift", { a: 4 }, "Z", "X", "C", "V", "B", "N", "M", "<\n,", ">\n.", "?\n/", { a: 6, w: 1.75 }, "Shift", { a: 7 }, "↑", { a: 6 }, "End"],
[{ w: 1.25 }, "Ctrl", { w: 1.25 }, "Win", { w: 1.25 }, "Alt", { a: 7, w: 6.25 }, "", { a: 6 }, "Alt", "Fn", "Ctrl", { a: 7 }, "←", "↓", "→"]
],
leopold_fc660m: [
["~\n`", "!\n1", "@\n2", "#\n3", "$\n4", "%\n5", "^\n6", "&\n7", "*\n8", "(\n9", ")\n0", "_\n-", "+\n=", { w: 2 }, "Backspace", { x: 0.5 }, "Insert"],
[{ w: 1.5 }, "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "{\n[", "}\n]", { w: 1.5 }, "|\n\\", { x: 0.5 }, "Delete"],
[{ w: 1.75 }, "Caps Lock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ":\n;", "\"\n'", { w: 2.25 }, "Enter"],
[{ w: 2.25 }, "Shift", "Z", "X", "C", "V", "B", "N", "M", "<\n,", ">\n.", "?\n/", { w: 2.25 }, "Shift", "↑"],
[{ w: 1.25 }, "Ctrl", "Win", { w: 1.25 }, "Alt", { a: 7, w: 6.25 }, "", { a: 4, w: 1.25 }, "Alt", { w: 1.25 }, "Ctrl", { w: 1.25 }, "Menu", "←", "↓", "→"]
],
apple_wireless: [
[{ y: 0.75, t: "#666666", p: "CHICKLET", a: 7, f: 2, w: 1.0357, h: 0.75 }, "esc", { a: 4, fa: [0, 0, 0, 1], w: 1.0357, h: 0.75 }, "\n\n\nF1", { w: 1.0357, h: 0.75 }, "\n\n\nF2", { w: 1.0357, h: 0.75 }, "\n\n\nF3", { w: 1.0357, h: 0.75 }, "\n\n\nF4", { w: 1.0357, h: 0.75 }, "\n\n\nF5", { w: 1.0357, h: 0.75 }, "\n\n\nF6", { w: 1.0357, h: 0.75 }, "\n\n\nF7\n\n\n\n\n\n<i class='fa fa-backward'></i>", { fa: [0, 0, 0, 1, 0, 0, 0, 0, 0, 1], w: 1.0357, h: 0.75 }, "\n\n\nF8\n\n\n\n\n\n<i class='fa fa-play'></i><i class='fa fa-pause'></i>", { fa: [0, 0, 0, 1], w: 1.0357, h: 0.75 }, "\n\n\nF9\n\n\n\n\n\n<i class='fa fa-forward'></i>", { w: 1.0357, h: 0.75 }, "\n\n\nF10\n\n\n\n\n\n<i class='fa fa-volume-off'></i>", { w: 1.0357, h: 0.75 }, "\n\n\nF11\n\n\n\n\n\n<i class='fa fa-volume-down'></i>", { w: 1.0357, h: 0.75 }, "\n\n\nF12\n\n\n\n\n\n<i class='fa fa-volume-up'></i>", { a: 7, w: 1.0357, h: 0.75 }, "<i class='fa fa-eject'></i>"],
[{ y: -0.25, a: 5, f: 5 }, "<i class=\"varela varela-tilde\"></i>\n`", "!\n1", "@\n2", "#\n3", "$\n4", "%\n5", "^\n6", "&\n7", "*\n8", "(\n9", ")\n0", "_\n-", "+\n=", { a: 4, f: 2, w: 1.5 }, "\n\n\ndelete"],
[{ w: 1.5 }, "\ntab", { a: 7, f: 5 }, "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", { a: 5 }, "{\n[", "}\n]", "|\n\\"],
[{ a: 4, f: 2, fa: [1], w: 1.75 }, "<i class='kb kb-Multimedia-Record'></i>\ncaps lock", { a: 7, f: 5 }, "A", "S", "D", { n: true }, "F", "G", "H", { n: true }, "J", "K", "L", { a: 5 }, ":\n;", "\"\n'", { a: 4, f: 2, fa: [0, 0, 1], w: 1.75 }, "\n\nenter\nreturn"],
[{ w: 2.25 }, "\nshift", { a: 7, f: 5 }, "Z", "X", "C", "V", "B", "N", "M", { a: 5 }, "<\n,", ">\n.", "?\n/", { a: 4, f: 2, w: 2.25 }, "\n\n\nshift"],
[{ h: 1.111 }, "\nfn", { h: 1.111 }, "\ncontrol", { fa: [1], h: 1.111 }, "alt\noption", { fa: [1, 0, 5], w: 1.25, h: 1.111 }, "\n\n⌘\ncommand", { a: 7, w: 5, h: 1.111 }, "", { a: 4, fa: [5], w: 1.25, h: 1.111 }, "⌘\ncommand", { fa: [5, 0, 1], h: 1.111 }, "\n\nalt\noption", { x: 1, a: 7, f: 5, h: 0.611 }, "↑"],
[{ y: -0.5, x: 11.5, h: 0.6111 }, "←", { h: 0.6111 }, "↓", { h: 0.6111 }, "→"]
],
};
exports.A_1N4148WS = A_1N4148WS;
exports.KeyMatrix = KeyMatrix;
exports.getRefDesForKey = getRefDesForKey;
exports.layouts = layouts;
exports.parseKLELayout = parseKLELayout;