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
lib/assignRowColByPosition.ts
/**
* Assigns logical row/col coordinates to keys based on their physical positions
* for the ergodox keyboard layout
*/
export function assignRowColByPosition(keys: Array<{
name: string
x: number
y: number
width: number
height: number
rotation: number
rotationX: number
rotationY: number
row: number
col: number
}>) {
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: typeof leftMainKeys, 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;
}