added heatmap
This commit is contained in:
parent
413eb916e4
commit
b6faa0bd2d
7
Makefile
7
Makefile
@ -4,14 +4,17 @@ LDFLAGS=-lm -lusb-1.0
|
||||
TEX=xelatex
|
||||
TEXFLAGS=-file-line-error -interaction nonstopmode
|
||||
|
||||
all: doc build/sniffer build/skillerctl
|
||||
all: build/sniffer build/skillerctl build/heatmap
|
||||
|
||||
-include $(wildcard build/*.d)
|
||||
|
||||
build/sniffer: build/sniffer.o build/utils.o build/usb.o build/skiller.o
|
||||
$(CC) $^ -o $@ $(LDFLAGS)
|
||||
|
||||
build/skillerctl: build/skillerctl.o build/utils.o build/usb.o build/skiller.o
|
||||
build/skillerctl: build/skillerctl.o build/utils.o build/usb.o build/skiller.o build/keys.o
|
||||
$(CC) $^ -o $@ $(LDFLAGS)
|
||||
|
||||
build/heatmap: build/heatmap.o build/utils.o build/usb.o build/skiller.o build/keys.o
|
||||
$(CC) $^ -o $@ $(LDFLAGS)
|
||||
|
||||
doc: doc/skiller-sgk3.pdf
|
||||
|
Binary file not shown.
@ -32,94 +32,85 @@
|
||||
\node[key] at (12,\row) {00\\63};
|
||||
\node[key, text width=14.5mm] at (13,\row) {00\\66};
|
||||
|
||||
\node[key] at (15.25,\row) {F12};
|
||||
\node[key] at (16.25,\row) {F12};
|
||||
\node[key] at (17.25,\row) {F12};
|
||||
|
||||
\node[key] at (18.5,\row) {F12};
|
||||
\node[key] at (19.5,\row) {F12};
|
||||
\node[key] at (20.5,\row) {F12};
|
||||
\node[key] at (21.5,\row) {F12};
|
||||
\node[key] at (15.25,\row) {00\\69};
|
||||
\node[key] at (16.25,\row) {00\\6c};
|
||||
\node[key] at (17.25,\row) {00\\6f};
|
||||
\node[key] at (18.5,\row) {00\\72};
|
||||
\node[key] at (19.5,\row) {00\\75};
|
||||
\node[key] at (20.5,\row) {00\\78};
|
||||
\node[key] at (21.5,\row) {00\\7A};
|
||||
|
||||
\def\row{2.5}
|
||||
\node[key, text width=10.75mm] at (0,\row) {0000};
|
||||
\node[key] at (1.5,\row) {0000};
|
||||
\node[key] at (2.5,\row) {0003};
|
||||
\node[key] at (3.5,\row) {0006};
|
||||
\node[key] at (4.5,\row) {0009};
|
||||
\node[key] at (5.5,\row) {000C};
|
||||
\node[key] at (6.5,\row) {000F};
|
||||
\node[key] at (7.5,\row) {F6};
|
||||
\node[key] at (8.5,\row) {F7};
|
||||
\node[key] at (9.5,\row) {F8};
|
||||
\node[key] at (10.5,\row) {F9};
|
||||
\node[key] at (11.5,\row) {F10};
|
||||
\node[key] at (12.5,\row) {F11};
|
||||
\node[key, text width=10.75mm] at (13.5,\row) {F12};
|
||||
|
||||
\node[key] at (15.25,\row) {F12};
|
||||
\node[key] at (16.25,\row) {F12};
|
||||
\node[key] at (17.25,\row) {F12};
|
||||
|
||||
\node[key] at (18.5,\row) {F12};
|
||||
\node[key] at (19.5,\row) {F12};
|
||||
\node[key] at (20.5,\row) {F12};
|
||||
\node[key, minimum height=12.5mm] at (21.5,\row) {F12};
|
||||
\node[key, text width=10.75mm] at (0,\row) {00\\7E};
|
||||
\node[key] at (1.5,\row) {00\\81};
|
||||
\node[key] at (2.5,\row) {00\\84};
|
||||
\node[key] at (3.5,\row) {00\\87};
|
||||
\node[key] at (4.5,\row) {00\\8A};
|
||||
\node[key] at (5.5,\row) {00\\8D};
|
||||
\node[key] at (6.5,\row) {00\\90};
|
||||
\node[key] at (7.5,\row) {00\\93};
|
||||
\node[key] at (8.5,\row) {00\\96};
|
||||
\node[key] at (9.5,\row) {00\\99};
|
||||
\node[key] at (10.5,\row) {00\\9C};
|
||||
\node[key] at (11.5,\row) {00\\9F};
|
||||
\node[key] at (12.5,\row) {00\\A2};
|
||||
\node[key, text width=10.75mm] at (13.5,\row) {00\\A5};
|
||||
\node[key] at (15.25,\row) {00\\A8};
|
||||
\node[key] at (16.25,\row) {00\\AB};
|
||||
\node[key] at (17.25,\row) {00\\AE};
|
||||
\node[key] at (18.5,\row) {00\\B1};
|
||||
\node[key] at (19.5,\row) {00\\B4};
|
||||
\node[key] at (20.5,\row) {00\\B7};
|
||||
\node[key, minimum height=12.5mm] at (21.5,\row) {00\\BA};
|
||||
|
||||
\def\row{3.5}
|
||||
\node[key, text width=13.0mm] at (0,\row) {0000};
|
||||
\node[key] at (1.8,\row) {0000};
|
||||
\node[key] at (2.8,\row) {0003};
|
||||
\node[key] at (3.8,\row) {0006};
|
||||
\node[key] at (4.8,\row) {0009};
|
||||
\node[key] at (5.8,\row) {000C};
|
||||
\node[key] at (6.8,\row) {000F};
|
||||
\node[key] at (7.8,\row) {F6};
|
||||
\node[key] at (8.8,\row) {F7};
|
||||
\node[key] at (9.8,\row) {F8};
|
||||
\node[key] at (10.8,\row) {F9};
|
||||
\node[key] at (11.8,\row) {F10};
|
||||
\node[key, text width=16mm] at (12.8,\row) {F12};
|
||||
|
||||
\node[key] at (18.5,\row) {F12};
|
||||
\node[key] at (19.5,\row) {F12};
|
||||
\node[key] at (20.5,\row) {F12};
|
||||
\node[key, text width=13.0mm] at (0,\row) {00\\BD};
|
||||
\node[key] at (1.8,\row) {00\\C0};
|
||||
\node[key] at (2.8,\row) {00\\C3};
|
||||
\node[key] at (3.8,\row) {00\\C6};
|
||||
\node[key] at (4.8,\row) {00\\C9};
|
||||
\node[key] at (5.8,\row) {00\\CC};
|
||||
\node[key] at (6.8,\row) {00\\CF};
|
||||
\node[key] at (7.8,\row) {00\\D2};
|
||||
\node[key] at (8.8,\row) {00\\D5};
|
||||
\node[key] at (9.8,\row) {00\\D8};
|
||||
\node[key] at (10.8,\row) {00\\DB};
|
||||
\node[key] at (11.8,\row) {00\\DE};
|
||||
\node[key, text width=16mm] at (12.8,\row) {00\\E4};
|
||||
\node[key] at (18.5,\row) {00\\F0};
|
||||
\node[key] at (19.5,\row) {00\\F3};
|
||||
\node[key] at (20.5,\row) {00\\F6};
|
||||
|
||||
\def\row{4.5}
|
||||
\node[key, text width=16.75mm] at (0,\row) {0000};
|
||||
\node[key] at (2.3,\row) {0000};
|
||||
\node[key] at (3.3,\row) {0003};
|
||||
\node[key] at (4.3,\row) {0006};
|
||||
\node[key] at (5.3,\row) {0009};
|
||||
\node[key] at (6.3,\row) {000C};
|
||||
\node[key] at (7.3,\row) {000F};
|
||||
\node[key] at (8.3,\row) {F6};
|
||||
\node[key] at (9.3,\row) {F7};
|
||||
\node[key] at (10.3,\row) {F8};
|
||||
\node[key] at (11.3,\row) {F9};
|
||||
\node[key, text width=19.75mm] at (12.3,\row) {F12};
|
||||
|
||||
\node[key] at (16.25,\row) {F12};
|
||||
|
||||
\node[key] at (18.5,\row) {F12};
|
||||
\node[key] at (19.5,\row) {F12};
|
||||
\node[key] at (20.5,\row) {F12};
|
||||
\node[key, minimum height=12.5mm] at (21.5,\row) {F12};
|
||||
\node[key, text width=16.75mm] at (0,\row) {00\\FC};
|
||||
\node[key] at (2.3,\row) {01\\02};
|
||||
\node[key] at (3.3,\row) {01\\05};
|
||||
\node[key] at (4.3,\row) {01\\08};
|
||||
\node[key] at (5.3,\row) {01\\0b};
|
||||
\node[key] at (6.3,\row) {01\\0e};
|
||||
\node[key] at (7.3,\row) {01\\11};
|
||||
\node[key] at (8.3,\row) {01\\14};
|
||||
\node[key] at (9.3,\row) {01\\17};
|
||||
\node[key] at (10.3,\row) {01\\1a};
|
||||
\node[key] at (11.3,\row) {01\\1d};
|
||||
\node[key, text width=19.75mm] at (12.3,\row) {01\\23};
|
||||
\node[key] at (16.25,\row) {01\\29};
|
||||
\node[key] at (18.5,\row) {01\\2f};
|
||||
\node[key] at (19.5,\row) {01\\32};
|
||||
\node[key] at (20.5,\row) {01\\35};
|
||||
\node[key, minimum height=12.5mm] at (21.5,\row) {01\\38};
|
||||
|
||||
\def\row{5.5}
|
||||
\node[key, text width=8.875mm] at (0,\row) {0000};
|
||||
\node[key, text width=8.875mm] at (1.25,\row) {0000};
|
||||
\node[key, text width=8.875mm] at (2.5,\row) {0003};
|
||||
\node[key, text width=46.375mm] at (3.75,\row) {0006};
|
||||
\node[key, text width=8.875mm] at (10,\row) {F12};
|
||||
\node[key, text width=8.875mm] at (11.25,\row) {F12};
|
||||
\node[key, text width=8.875mm] at (12.5,\row) {F12};
|
||||
\node[key, text width=8.875mm] at (13.75,\row) {F12};
|
||||
|
||||
\node[key] at (15.25,\row) {F12};
|
||||
\node[key] at (16.25,\row) {F12};
|
||||
\node[key] at (17.25,\row) {F12};
|
||||
|
||||
\node[key] at (18.5,\row) {F12};
|
||||
\node[key] at (19.5,\row) {F12};
|
||||
\node[key] at (20.5,\row) {F12};
|
||||
\node[key, text width=8.875mm] at (0,\row) {01\\3b};
|
||||
\node[key, text width=8.875mm] at (1.25,\row) {01\\3e};
|
||||
\node[key, text width=8.875mm] at (2.5,\row) {01\\41};
|
||||
\node[key, text width=46.375mm] at (3.75,\row) {01\\44};
|
||||
\node[key, text width=8.875mm] at (10,\row) {01\\47};
|
||||
\node[key, text width=8.875mm] at (11.25,\row) {01\\4a};
|
||||
\node[key, text width=8.875mm] at (12.5,\row) {01\\4d};
|
||||
\node[key, text width=8.875mm] at (13.75,\row) {01\\53};
|
||||
\node[key] at (15.25,\row) {01\\65};
|
||||
\node[key] at (16.25,\row) {01\\68};
|
||||
\node[key] at (17.25,\row) {01\\6b};
|
||||
\node[key, text width=14.5mm] at (18.5,\row) {01\\71};
|
||||
\node[key] at (20.5,\row) {01\\74};
|
||||
|
@ -11,9 +11,11 @@
|
||||
\usepackage{verbatim}
|
||||
\usepackage{amstext}
|
||||
\usepackage{tikz}
|
||||
\usepackage{siunitx}
|
||||
\usepackage{pgfplots}
|
||||
\usepackage{bytefield}
|
||||
|
||||
\sisetup{group-separator={,}}
|
||||
\usetikzlibrary{intersections,calc,positioning,arrows}
|
||||
|
||||
%opening
|
||||
@ -50,7 +52,7 @@
|
||||
\begin{bytefield}[bitwidth=4em]{8}
|
||||
\bitheader{0-7} \\
|
||||
\bitbox{1}{04h} & \bitbox{2}{checksum} & \bitbox{1}{cmd} & \bitbox{1}{len} & \bitbox{2}{addr} & \bitbox{1}{00h} \\
|
||||
\wordbox{3}{payload \\ up to len bytes}
|
||||
\wordbox{3}{payload \\ up to 56 bytes}
|
||||
\end{bytefield}
|
||||
\end{figure}
|
||||
|
||||
@ -78,7 +80,7 @@
|
||||
\texttt{SK\_CMD\_ENABLE\_LED} & \texttt{02h} & Enables key backlight, takes some time. \\
|
||||
\texttt{SK\_CMD\_READ\_???} & \texttt{03h} & Reads some state. \\
|
||||
\texttt{SK\_CMD\_READ\_???} & \texttt{05h} & Reads some state. \\
|
||||
\texttt{SK\_CMD\_SET\_MODE} & \texttt{06h} & Changes keyboard mode or mode settings. \\
|
||||
\texttt{SK\_CMD\_SET\_PROP} & \texttt{06h} & Changes keyboard mode or mode settings. \\
|
||||
\texttt{SK\_CMD\_MAP\_KEYS} & \texttt{08h} & Writes key mapping to controller. \\
|
||||
\texttt{SK\_CMD\_WRITE\_MACRO} & \texttt{0Ah} & Saves macros in controller memory. \\
|
||||
\texttt{SK\_CMD\_SET\_COLOR} & \texttt{11h} & Changes LED RGB values in key given keys, or key range. \\
|
||||
@ -101,10 +103,88 @@
|
||||
\subsection{\texttt{SK\_CMD\_ENABLE\_LED} (\texttt{02h})}
|
||||
This command re-enables all LEDs on keyboard. It's useful when we need to change few values and don't want to
|
||||
constantly blink diodes. Both operations are quite long to execute, they can took about 1s.
|
||||
|
||||
\subsection{\texttt{SK\_CMD\_SET\_PROP} (\texttt{06h})}
|
||||
This command is used to change color mode and other settings like brighteness, pulsation direction, polling rate
|
||||
etc.
|
||||
|
||||
\subsubsection{Addressing}
|
||||
Changed property is referenced via \texttt{addr}.
|
||||
\begin{table}[H]
|
||||
\begin{tabular}{l|r|l}
|
||||
\textbf{Property} & \textbf{Address} & \textbf{Description} \\ \hline
|
||||
\texttt{SK\_PROP\_MODE} & \texttt{00h} & Changes backlight program (pulsing, permamant, custom, etc.) \\
|
||||
\texttt{SK\_PROP\_BRIGHTNESS} & \texttt{01h} & Sets brihgtness level \\
|
||||
\texttt{SK\_PROP\_SPEED} & \texttt{02h} & Sets animation speed \\
|
||||
\texttt{SK\_PROP\_DIRECTION} & \texttt{03h} & Sets animation direction \\
|
||||
\texttt{SK\_PROP\_RGB} & \texttt{04h} & LGBT promotion \\
|
||||
\texttt{SK\_PROP\_COLOR} & \texttt{05h} & Base color \\
|
||||
\texttt{SK\_PROP\_POLLING} & \texttt{0Fh} & Polling rate \\
|
||||
\end{tabular}
|
||||
\end{table}
|
||||
|
||||
\subsubsection{Payload}
|
||||
\paragraph{\texttt{SK\_PROP\_MODE} (\texttt{00h})}
|
||||
Payload is 1-byte long mode identifier, possible modes are listed in table below.
|
||||
\begin{table}[H]
|
||||
\centering
|
||||
\begin{tabular}{l|r|l}
|
||||
\textbf{Identifier} & \textbf{Value} & \textbf{Name} \\ \hline
|
||||
\texttt{SK\_MODE\_WAVE} & \texttt{01h} & Wave \\
|
||||
\texttt{SK\_MODE\_DRIFT} & \texttt{02h} & Drift \\
|
||||
\texttt{SK\_MODE\_SWIRL} & \texttt{03h} & Swirl \\
|
||||
\texttt{SK\_MODE\_CHANGE} & \texttt{04h} & color change \\
|
||||
\texttt{SK\_MODE\_PULSATING} & \texttt{05h} & pulsating \\
|
||||
\texttt{SK\_MODE\_PERMAMENT} & \texttt{06h} & permament \\
|
||||
\texttt{SK\_MODE\_EXPLOSION} & \texttt{07h} & Explosion \\
|
||||
\texttt{SK\_MODE\_TRIGGER} & \texttt{08h} & Trigger \\
|
||||
\texttt{SK\_MODE\_BURST} & \texttt{09h} & Gamma Ray Burst \\
|
||||
\texttt{SK\_MODE\_CHAOS} & \texttt{0Ah} & Chaos \\
|
||||
\texttt{SK\_MODE\_COSMIC} & \texttt{0Bh} & Cosmic \\
|
||||
\texttt{SK\_MODE\_GRADIENT} & \texttt{0Ch} & Gradient \\
|
||||
\texttt{SK\_MODE\_TIDE} & \texttt{0Dh} & Tide \\
|
||||
\texttt{SK\_MODE\_LIGHTING} & \texttt{0Eh} & Ball Lighting \\
|
||||
\texttt{SK\_MODE\_MATRIX} & \texttt{0Fh} & Matrix \\
|
||||
\texttt{SK\_MODE\_RICOCHET} & \texttt{10h} & Ricochet \\
|
||||
\texttt{SK\_MODE\_RIPPLE} & \texttt{12h} & Ripple \\
|
||||
\texttt{SK\_MODE\_CUSTOM} & \texttt{14h} & Custom
|
||||
\end{tabular}
|
||||
\end{table}
|
||||
|
||||
\paragraph{\texttt{SK\_PROP\_BRIGHTNESS} (\texttt{01h})}
|
||||
Payload is 1-byte from range \texttt{00h-05h}, where \texttt{00h} means no light at all and \texttt{05h} is the
|
||||
brightest value.
|
||||
|
||||
\paragraph{\texttt{SK\_PROP\_SPEED} (\texttt{02h})}
|
||||
Payload is 1-byte from range \texttt{00h-05h}, where \texttt{00h} is the slowest setting and \texttt{05h} is the
|
||||
fastest one.
|
||||
|
||||
\paragraph{\texttt{SK\_PROP\_DIRECTION} (\texttt{03h})}
|
||||
Payload 1-byte value desciring direction, \texttt{00} for left to right/top to bottom and \texttt{ffh} for reverse.
|
||||
|
||||
\paragraph{\texttt{SK\_PROP\_RGB} (\texttt{04h})}
|
||||
Payload is 1-byte long flag, which defines if we should see rainbow (\texttt{01h}) or not (\texttt{00h})
|
||||
|
||||
\paragraph{\texttt{SK\_PROP\_COLOR} (\texttt{05h})}
|
||||
Payload is 3-byte RGB value describing color used by mode, detailed structure is exactly the same as in
|
||||
\ref{cmd:color:payload}.
|
||||
|
||||
\paragraph{\texttt{SK\_PROP\_POLLING} (\texttt{0Fh})}
|
||||
Payload is 1-byte long value identifing used polling rate.
|
||||
\begin{table}[H]
|
||||
\centering
|
||||
\begin{tabular}{l|r|l}
|
||||
\textbf{Identifier} & \textbf{Value} & \textbf{Polling rate} \\ \hline
|
||||
\texttt{SK\_POLL\_125HZ} & \texttt{00h} & \SI{125}{\hertz} \\
|
||||
\texttt{SK\_POLL\_250HZ} & \texttt{01h} & \SI{250}{\hertz} \\
|
||||
\texttt{SK\_POLL\_500HZ} & \texttt{02h} & \SI{500}{\hertz} \\
|
||||
\texttt{SK\_POLL\_1000HZ} & \texttt{03h} & \SI{1000}{\hertz} \\
|
||||
\end{tabular}
|
||||
\end{table}
|
||||
|
||||
\subsection{\texttt{SK\_CMD\_SET\_COLOR} (\texttt{11h})}
|
||||
This command can be used to change color of 1 or few LEDs at once. This operation takes less than 100ms, and
|
||||
refreshes all diodes (in simpler words - they blink).
|
||||
refreshes all diodes (in simpler words - they blink). This command only makes sens weh in \texttt{SK\_MODE\_CUSTOM}.
|
||||
|
||||
\subsubsection{Addressing}
|
||||
The \texttt{addr} header value identifies starting address of specific LED in keyboard. Rule of thumb is that keys
|
||||
@ -129,7 +209,7 @@
|
||||
}
|
||||
\end{figure}
|
||||
|
||||
\subsubsection{Payload}
|
||||
\subsubsection{Payload} \label{cmd:color:payload}
|
||||
Payload of this command consist of consecutive RGB values, 1-byte per channel, we could describe this struct like that:
|
||||
\begin{verbatim}
|
||||
typedef struct {
|
||||
@ -160,5 +240,5 @@ typedef struct {
|
||||
\end{verbatim}
|
||||
\caption{setting color of \key{Esc}, \key{F1}, \key{F2} to white (\texttt{ffffffh})}
|
||||
\end{figure}
|
||||
|
||||
|
||||
\end{document}
|
||||
|
246
src/heatmap.c
Normal file
246
src/heatmap.c
Normal file
@ -0,0 +1,246 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include "skiller.h"
|
||||
#include "usb.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define PACKETS_MAX 255
|
||||
|
||||
skillerctl_packet_t packets[255] = {};
|
||||
size_t count = 0;
|
||||
|
||||
struct color_stop {
|
||||
double value;
|
||||
int16_t r;
|
||||
int16_t g;
|
||||
int16_t b;
|
||||
} stops[] = {
|
||||
-INFINITY, 0x00, 0x00, 0x00,
|
||||
0/6., 0x00, 0x00, 0x00,
|
||||
1/6., 0x00, 0x00, 0xFF,
|
||||
2/6., 0x00, 0xFF, 0xFF,
|
||||
3/6., 0x00, 0xFF, 0x00,
|
||||
4/6., 0xFF, 0xFF, 0x00,
|
||||
5/6., 0xFF, 0x00, 0x00,
|
||||
6/6., 0xFF, 0xFF, 0xFF,
|
||||
INFINITY, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
int clamp(int min, int value, int max) {
|
||||
return value > max ? max : (value < min ? min : value);
|
||||
}
|
||||
|
||||
uint32_t interpolate(double color) {
|
||||
struct color_stop *top = stops;
|
||||
struct color_stop *bottom;
|
||||
|
||||
while (top->value < color) top++;
|
||||
|
||||
bottom = top - 1;
|
||||
|
||||
double d = (color - bottom->value) / (top->value - bottom->value);
|
||||
|
||||
return (clamp(0x00, bottom->r + (top->r - bottom->r) * d, 0xFF) & 0xFF)
|
||||
+ ((clamp(0x00, bottom->g + (top->g - bottom->g) * d, 0xFF) & 0xFF) << 8)
|
||||
+ ((clamp(0x00, bottom->b + (top->b - bottom->b) * d, 0xFF) & 0xFF) << 16)
|
||||
;
|
||||
}
|
||||
|
||||
uint16_t mapping[] = {
|
||||
['`'] = SK_KEY_TILDE,
|
||||
['~'] = SK_KEY_TILDE,
|
||||
['1'] = SK_KEY_1,
|
||||
['!'] = SK_KEY_1,
|
||||
['2'] = SK_KEY_2,
|
||||
['@'] = SK_KEY_2,
|
||||
['3'] = SK_KEY_3,
|
||||
['#'] = SK_KEY_3,
|
||||
['4'] = SK_KEY_4,
|
||||
['$'] = SK_KEY_4,
|
||||
['5'] = SK_KEY_5,
|
||||
['%'] = SK_KEY_5,
|
||||
['6'] = SK_KEY_6,
|
||||
['^'] = SK_KEY_6,
|
||||
['7'] = SK_KEY_7,
|
||||
['&'] = SK_KEY_7,
|
||||
['8'] = SK_KEY_8,
|
||||
['*'] = SK_KEY_8,
|
||||
['9'] = SK_KEY_9,
|
||||
['('] = SK_KEY_9,
|
||||
['0'] = SK_KEY_0,
|
||||
[')'] = SK_KEY_0,
|
||||
['-'] = SK_KEY_MINUS,
|
||||
['_'] = SK_KEY_MINUS,
|
||||
['='] = SK_KEY_EQUALS,
|
||||
['+'] = SK_KEY_EQUALS,
|
||||
['q'] = SK_KEY_Q,
|
||||
['Q'] = SK_KEY_Q,
|
||||
['w'] = SK_KEY_W,
|
||||
['W'] = SK_KEY_W,
|
||||
['e'] = SK_KEY_E,
|
||||
['E'] = SK_KEY_E,
|
||||
['r'] = SK_KEY_R,
|
||||
['R'] = SK_KEY_R,
|
||||
['t'] = SK_KEY_T,
|
||||
['T'] = SK_KEY_T,
|
||||
['y'] = SK_KEY_Y,
|
||||
['Y'] = SK_KEY_Y,
|
||||
['u'] = SK_KEY_U,
|
||||
['U'] = SK_KEY_U,
|
||||
['i'] = SK_KEY_I,
|
||||
['I'] = SK_KEY_I,
|
||||
['o'] = SK_KEY_O,
|
||||
['O'] = SK_KEY_O,
|
||||
['p'] = SK_KEY_P,
|
||||
['P'] = SK_KEY_P,
|
||||
['['] = SK_KEY_OPEN_BRACKET,
|
||||
['{'] = SK_KEY_OPEN_BRACKET,
|
||||
[']'] = SK_KEY_CLOSE_BRACKET,
|
||||
['}'] = SK_KEY_CLOSE_BRACKET,
|
||||
['\\'] = SK_KEY_BACKSLASH,
|
||||
['|'] = SK_KEY_BACKSLASH,
|
||||
['a'] = SK_KEY_A,
|
||||
['A'] = SK_KEY_A,
|
||||
['s'] = SK_KEY_S,
|
||||
['S'] = SK_KEY_S,
|
||||
['d'] = SK_KEY_D,
|
||||
['D'] = SK_KEY_D,
|
||||
['f'] = SK_KEY_F,
|
||||
['F'] = SK_KEY_F,
|
||||
['g'] = SK_KEY_G,
|
||||
['G'] = SK_KEY_G,
|
||||
['h'] = SK_KEY_H,
|
||||
['H'] = SK_KEY_H,
|
||||
['j'] = SK_KEY_J,
|
||||
['J'] = SK_KEY_J,
|
||||
['k'] = SK_KEY_K,
|
||||
['K'] = SK_KEY_K,
|
||||
['l'] = SK_KEY_L,
|
||||
['L'] = SK_KEY_L,
|
||||
[';'] = SK_KEY_COLON,
|
||||
[':'] = SK_KEY_COLON,
|
||||
['\''] = SK_KEY_QUOTE,
|
||||
['"'] = SK_KEY_QUOTE,
|
||||
['\n'] = SK_KEY_ENTER,
|
||||
[' '] = SK_KEY_SPACE,
|
||||
['z'] = SK_KEY_Z,
|
||||
['Z'] = SK_KEY_Z,
|
||||
['x'] = SK_KEY_X,
|
||||
['X'] = SK_KEY_X,
|
||||
['c'] = SK_KEY_C,
|
||||
['C'] = SK_KEY_C,
|
||||
['v'] = SK_KEY_V,
|
||||
['V'] = SK_KEY_V,
|
||||
['b'] = SK_KEY_B,
|
||||
['B'] = SK_KEY_B,
|
||||
['n'] = SK_KEY_N,
|
||||
['N'] = SK_KEY_N,
|
||||
['m'] = SK_KEY_M,
|
||||
['M'] = SK_KEY_M,
|
||||
[','] = SK_KEY_COMMA,
|
||||
['<'] = SK_KEY_COMMA,
|
||||
['.'] = SK_KEY_DOT,
|
||||
['>'] = SK_KEY_DOT,
|
||||
['/'] = SK_KEY_SLASH,
|
||||
['?'] = SK_KEY_SLASH,
|
||||
};
|
||||
|
||||
double heatmap[SK_LIMIT_KEY] = {};
|
||||
|
||||
void normalize_heatmap()
|
||||
{
|
||||
double max = 1.0, min = 0.0;
|
||||
for (int i = 0; i < SK_LIMIT_KEY; i += 3) {
|
||||
max = max > heatmap[i] ? max : heatmap[i];
|
||||
min = min >= 1.0 && min < heatmap[i] ? min : heatmap[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < SK_LIMIT_KEY; i += 3) {
|
||||
heatmap[i] /= (max - min);
|
||||
}
|
||||
}
|
||||
|
||||
void make_row(skillerctl_keyaddr_t low, skillerctl_keyaddr_t high) {
|
||||
uint32_t colors[18] = {};
|
||||
|
||||
unsigned j = 0;
|
||||
for (skillerctl_keyaddr_t i = low; i <= high; i += 3, j++) {
|
||||
printf("Key: %s heat: %lf color: #%06x\n", skillerctl_keystr(i), heatmap[i], interpolate(heatmap[i]));
|
||||
colors[j] = interpolate(heatmap[i]);
|
||||
}
|
||||
|
||||
skillerctl_color_batch_command(packets + count++, low, colors, (high - low) / 3 + 1);
|
||||
}
|
||||
|
||||
void make_packets()
|
||||
{
|
||||
count = 0;
|
||||
skillerctl_disable_led_command(packets + count++);
|
||||
make_row(SK_KEY_TILDE, SK_KEY_EQUALS);
|
||||
make_row(SK_KEY_Q, SK_KEY_BACKSLASH);
|
||||
make_row(SK_KEY_A, SK_KEY_ENTER);
|
||||
make_row(SK_KEY_Z, SK_KEY_SLASH);
|
||||
skillerctl_color_command(packets + count++, SK_KEY_SPACE, interpolate(heatmap[SK_KEY_SPACE]));
|
||||
skillerctl_enable_led_command(packets + count++);
|
||||
}
|
||||
|
||||
void handle_input(int argc, char **argv)
|
||||
{
|
||||
char c = getc(stdin);
|
||||
skillerctl_keyaddr_t key;
|
||||
|
||||
while (c != EOF) {
|
||||
if ((key = mapping[c])) {
|
||||
heatmap[key] += 1.;
|
||||
}
|
||||
|
||||
c = getc(stdin);
|
||||
}
|
||||
|
||||
normalize_heatmap();
|
||||
make_packets();
|
||||
}
|
||||
|
||||
void handle_logic(libusb_device *skiller)
|
||||
{
|
||||
libusb_device_handle *handle;
|
||||
skillerctl_packet_t packet;
|
||||
|
||||
if (skiller == NULL) {
|
||||
printf("Cannot found compatibile keyboard, is it connected?\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (libusb_open(skiller, &handle) != LIBUSB_SUCCESS) {
|
||||
printf("Cannot open device, try with sudo.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
libusb_detach_kernel_driver(handle, 1);
|
||||
libusb_claim_interface(handle, 1);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
skillerctl_send_command(handle, packets + i);
|
||||
}
|
||||
|
||||
libusb_release_interface(handle, 1);
|
||||
libusb_attach_kernel_driver(handle, 1);
|
||||
libusb_close(handle);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
libusb_device **list;
|
||||
|
||||
libusb_init(NULL);
|
||||
size_t count = libusb_get_device_list(NULL, &list);
|
||||
libusb_device *skiller = skillerctl_find_device(list, count);
|
||||
|
||||
handle_input(argc, argv);
|
||||
handle_logic(skiller);
|
||||
|
||||
libusb_free_device_list(list, 1);
|
||||
libusb_exit(NULL);
|
||||
}
|
249
src/keys.c
249
src/keys.c
@ -1,30 +1,241 @@
|
||||
#include "keys.h"
|
||||
#include "utils.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
skillerctl_keyaddr_t addr;
|
||||
char* name;
|
||||
} keyaddr_name_pair;
|
||||
|
||||
keyaddr_name_pair keycodeLUT[] = {
|
||||
SK_KEY_ESC, "esc",
|
||||
SK_KEY_F1, "f1",
|
||||
SK_KEY_F2, "f2",
|
||||
skillerctl_name_value_pair_t keycodeLUT[] = {
|
||||
SK_KEY_ESC, "esc",
|
||||
SK_KEY_F1, "f1",
|
||||
SK_KEY_F2, "f2",
|
||||
SK_KEY_F3, "f3",
|
||||
SK_KEY_F4, "f4",
|
||||
SK_KEY_F5, "f5",
|
||||
SK_KEY_F6, "f6",
|
||||
SK_KEY_F7, "f7",
|
||||
SK_KEY_F8, "f8",
|
||||
SK_KEY_F9, "f9",
|
||||
SK_KEY_F10, "f10",
|
||||
SK_KEY_F11, "f11",
|
||||
SK_KEY_F12, "f12",
|
||||
SK_KEY_PRTSC, "prtsc",
|
||||
SK_KEY_PRTSC, "printscreen",
|
||||
SK_KEY_PRTSC, "prtscr",
|
||||
SK_KEY_SCROLL_LOCK, "scrollock",
|
||||
SK_KEY_BREAK, "pause",
|
||||
SK_KEY_BREAK, "break",
|
||||
SK_KEY_TILDE, "~",
|
||||
SK_KEY_TILDE, "tilde",
|
||||
SK_KEY_1, "1",
|
||||
SK_KEY_2, "2",
|
||||
SK_KEY_3, "3",
|
||||
SK_KEY_4, "4",
|
||||
SK_KEY_5, "5",
|
||||
SK_KEY_6, "6",
|
||||
SK_KEY_7, "7",
|
||||
SK_KEY_8, "8",
|
||||
SK_KEY_9, "9",
|
||||
SK_KEY_0, "0",
|
||||
SK_KEY_MINUS, "-",
|
||||
SK_KEY_EQUALS, "=",
|
||||
SK_KEY_BACKSPACE, "backspace",
|
||||
SK_KEY_INSERT, "insert",
|
||||
SK_KEY_HOME, "home",
|
||||
SK_KEY_PGUP, "pgup",
|
||||
SK_KEY_NUMLOCK, "numlock",
|
||||
SK_KEY_NUMDIV, "numdiv",
|
||||
SK_KEY_NUMASTERISK, "numasterisk",
|
||||
SK_KEY_NUMMINUS, "numminus",
|
||||
SK_KEY_TAB, "tab",
|
||||
SK_KEY_Q, "q",
|
||||
SK_KEY_W, "w",
|
||||
SK_KEY_E, "e",
|
||||
SK_KEY_R, "r",
|
||||
SK_KEY_T, "t",
|
||||
SK_KEY_Y, "y",
|
||||
SK_KEY_U, "u",
|
||||
SK_KEY_I, "i",
|
||||
SK_KEY_O, "o",
|
||||
SK_KEY_P, "p",
|
||||
SK_KEY_OPEN_BRACKET, "[",
|
||||
SK_KEY_CLOSE_BRACKET, "]",
|
||||
SK_KEY_BACKSLASH, "]",
|
||||
SK_KEY_DELETE, "delete",
|
||||
SK_KEY_DELETE, "del",
|
||||
SK_KEY_END, "end",
|
||||
SK_KEY_PGDOWN, "pgdown",
|
||||
SK_KEY_NUM7, "num7",
|
||||
SK_KEY_NUM8, "num8",
|
||||
SK_KEY_NUM9, "num9",
|
||||
SK_KEY_NUMPLUS, "numplus",
|
||||
SK_KEY_CAPSLOCK, "caps",
|
||||
SK_KEY_CAPSLOCK, "capslock",
|
||||
SK_KEY_A, "a",
|
||||
SK_KEY_S, "s",
|
||||
SK_KEY_D, "d",
|
||||
SK_KEY_F, "f",
|
||||
SK_KEY_G, "g",
|
||||
SK_KEY_H, "h",
|
||||
SK_KEY_J, "j",
|
||||
SK_KEY_K, "k",
|
||||
SK_KEY_L, "l",
|
||||
SK_KEY_COLON, ";",
|
||||
SK_KEY_QUOTE, "'",
|
||||
SK_KEY_ENTER, "enter",
|
||||
SK_KEY_NUM4, "num4",
|
||||
SK_KEY_NUM5, "num5",
|
||||
SK_KEY_NUM6, "num6",
|
||||
SK_KEY_LSHIFT, "lshift",
|
||||
SK_KEY_Z, "z",
|
||||
SK_KEY_X, "x",
|
||||
SK_KEY_C, "c",
|
||||
SK_KEY_V, "v",
|
||||
SK_KEY_B, "b",
|
||||
SK_KEY_N, "n",
|
||||
SK_KEY_M, "m",
|
||||
SK_KEY_COMMA, ",",
|
||||
SK_KEY_DOT, ".",
|
||||
SK_KEY_SLASH, "/",
|
||||
SK_KEY_RSHIFT, "rshift",
|
||||
SK_KEY_UP, "up",
|
||||
SK_KEY_NUM1, "num1",
|
||||
SK_KEY_NUM2, "num2",
|
||||
SK_KEY_NUM3, "num3",
|
||||
SK_KEY_NUMENTER, "numenter",
|
||||
SK_KEY_LCTRL, "lctrl",
|
||||
SK_KEY_LWIN, "win",
|
||||
SK_KEY_LWIN, "super",
|
||||
SK_KEY_LALT, "lalt",
|
||||
SK_KEY_SPACE, "space",
|
||||
SK_KEY_ALTGR, "altgr",
|
||||
SK_KEY_ALTGR, "ralt",
|
||||
SK_KEY_SHARKOON, "sharkoon",
|
||||
SK_KEY_MENU, "menu",
|
||||
SK_KEY_RCTRL, "rctrl",
|
||||
SK_KEY_LEFT, "left",
|
||||
SK_KEY_DOWN, "down",
|
||||
SK_KEY_RIGHT, "right",
|
||||
SK_KEY_NUM0, "num0",
|
||||
SK_KEY_LWIN, "lwin",
|
||||
};
|
||||
|
||||
skillerctl_keyaddr_t skillerctl_keyaddr(const char* name)
|
||||
{
|
||||
size_t n = sizeof(keycodeLUT) / sizeof(keyaddr_name_pair);
|
||||
keyaddr_name_pair *current;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
current = keycodeLUT + i;
|
||||
|
||||
if (strcmp(current->name, name) == 0) {
|
||||
return current->addr;
|
||||
}
|
||||
return skillerctl_lut_search(
|
||||
keycodeLUT,
|
||||
sizeof(keycodeLUT) / sizeof(skillerctl_name_value_pair_t),
|
||||
name
|
||||
);
|
||||
}
|
||||
|
||||
char* skillerctl_keystr(skillerctl_keyaddr_t key)
|
||||
{
|
||||
switch (key) {
|
||||
case SK_KEY_BAD: return "SK_KEY_BAD";
|
||||
case SK_KEY_ESC: return "SK_KEY_ESC";
|
||||
case SK_KEY_F1: return "SK_KEY_F1";
|
||||
case SK_KEY_F2: return "SK_KEY_F2";
|
||||
case SK_KEY_F3: return "SK_KEY_F3";
|
||||
case SK_KEY_F4: return "SK_KEY_F4";
|
||||
case SK_KEY_F5: return "SK_KEY_F5";
|
||||
case SK_KEY_F6: return "SK_KEY_F6";
|
||||
case SK_KEY_F7: return "SK_KEY_F7";
|
||||
case SK_KEY_F8: return "SK_KEY_F8";
|
||||
case SK_KEY_F9: return "SK_KEY_F9";
|
||||
case SK_KEY_F10: return "SK_KEY_F10";
|
||||
case SK_KEY_F11: return "SK_KEY_F11";
|
||||
case SK_KEY_F12: return "SK_KEY_F12";
|
||||
case SK_KEY_PRTSC: return "SK_KEY_PRTSC";
|
||||
case SK_KEY_SCROLL_LOCK: return "SK_KEY_SCROLL_LOCK";
|
||||
case SK_KEY_BREAK: return "SK_KEY_BREAK";
|
||||
case SK_KEY_TILDE: return "SK_KEY_TILDE";
|
||||
case SK_KEY_1: return "SK_KEY_1";
|
||||
case SK_KEY_2: return "SK_KEY_2";
|
||||
case SK_KEY_3: return "SK_KEY_3";
|
||||
case SK_KEY_4: return "SK_KEY_4";
|
||||
case SK_KEY_5: return "SK_KEY_5";
|
||||
case SK_KEY_6: return "SK_KEY_6";
|
||||
case SK_KEY_7: return "SK_KEY_7";
|
||||
case SK_KEY_8: return "SK_KEY_8";
|
||||
case SK_KEY_9: return "SK_KEY_9";
|
||||
case SK_KEY_0: return "SK_KEY_0";
|
||||
case SK_KEY_MINUS: return "SK_KEY_MINUS";
|
||||
case SK_KEY_EQUALS: return "SK_KEY_EQUALS";
|
||||
case SK_KEY_BACKSPACE: return "SK_KEY_BACKSPACE";
|
||||
case SK_KEY_INSERT: return "SK_KEY_INSERT";
|
||||
case SK_KEY_HOME: return "SK_KEY_HOME";
|
||||
case SK_KEY_PGUP: return "SK_KEY_PGUP";
|
||||
case SK_KEY_NUMLOCK: return "SK_KEY_NUMLOCK";
|
||||
case SK_KEY_NUMDIV: return "SK_KEY_NUMDIV";
|
||||
case SK_KEY_NUMASTERISK: return "SK_KEY_NUMASTERISK";
|
||||
case SK_KEY_NUMMINUS: return "SK_KEY_NUMMINUS";
|
||||
case SK_KEY_TAB: return "SK_KEY_TAB";
|
||||
case SK_KEY_Q: return "SK_KEY_Q";
|
||||
case SK_KEY_W: return "SK_KEY_W";
|
||||
case SK_KEY_E: return "SK_KEY_E";
|
||||
case SK_KEY_R: return "SK_KEY_R";
|
||||
case SK_KEY_T: return "SK_KEY_T";
|
||||
case SK_KEY_Y: return "SK_KEY_Y";
|
||||
case SK_KEY_U: return "SK_KEY_U";
|
||||
case SK_KEY_I: return "SK_KEY_I";
|
||||
case SK_KEY_O: return "SK_KEY_O";
|
||||
case SK_KEY_P: return "SK_KEY_P";
|
||||
case SK_KEY_OPEN_BRACKET: return "SK_KEY_OPEN_BRACKET";
|
||||
case SK_KEY_CLOSE_BRACKET: return "SK_KEY_CLOSE_BRACKET";
|
||||
case SK_KEY_BACKSLASH: return "SK_KEY_BACKSLASH";
|
||||
case SK_KEY_DELETE: return "SK_KEY_DELETE";
|
||||
case SK_KEY_END: return "SK_KEY_END";
|
||||
case SK_KEY_PGDOWN: return "SK_KEY_PGDOWN";
|
||||
case SK_KEY_NUM7: return "SK_KEY_NUM7";
|
||||
case SK_KEY_NUM8: return "SK_KEY_NUM8";
|
||||
case SK_KEY_NUM9: return "SK_KEY_NUM9";
|
||||
case SK_KEY_NUMPLUS: return "SK_KEY_NUMPLUS";
|
||||
case SK_KEY_CAPSLOCK: return "SK_KEY_CAPSLOCK";
|
||||
case SK_KEY_A: return "SK_KEY_A";
|
||||
case SK_KEY_S: return "SK_KEY_S";
|
||||
case SK_KEY_D: return "SK_KEY_D";
|
||||
case SK_KEY_F: return "SK_KEY_F";
|
||||
case SK_KEY_G: return "SK_KEY_G";
|
||||
case SK_KEY_H: return "SK_KEY_H";
|
||||
case SK_KEY_J: return "SK_KEY_J";
|
||||
case SK_KEY_K: return "SK_KEY_K";
|
||||
case SK_KEY_L: return "SK_KEY_L";
|
||||
case SK_KEY_COLON: return "SK_KEY_COLON";
|
||||
case SK_KEY_QUOTE: return "SK_KEY_QUOTE";
|
||||
case SK_KEY_ENTER: return "SK_KEY_ENTER";
|
||||
case SK_KEY_NUM4: return "SK_KEY_NUM4";
|
||||
case SK_KEY_NUM5: return "SK_KEY_NUM5";
|
||||
case SK_KEY_NUM6: return "SK_KEY_NUM6";
|
||||
case SK_KEY_LSHIFT: return "SK_KEY_LSHIFT";
|
||||
case SK_KEY_Z: return "SK_KEY_Z";
|
||||
case SK_KEY_X: return "SK_KEY_X";
|
||||
case SK_KEY_C: return "SK_KEY_C";
|
||||
case SK_KEY_V: return "SK_KEY_V";
|
||||
case SK_KEY_B: return "SK_KEY_B";
|
||||
case SK_KEY_N: return "SK_KEY_N";
|
||||
case SK_KEY_M: return "SK_KEY_M";
|
||||
case SK_KEY_COMMA: return "SK_KEY_COMMA";
|
||||
case SK_KEY_DOT: return "SK_KEY_DOT";
|
||||
case SK_KEY_SLASH: return "SK_KEY_SLASH";
|
||||
case SK_KEY_RSHIFT: return "SK_KEY_RSHIFT";
|
||||
case SK_KEY_UP: return "SK_KEY_UP";
|
||||
case SK_KEY_NUM1: return "SK_KEY_NUM1";
|
||||
case SK_KEY_NUM2: return "SK_KEY_NUM2";
|
||||
case SK_KEY_NUM3: return "SK_KEY_NUM3";
|
||||
case SK_KEY_NUMENTER: return "SK_KEY_NUMENTER";
|
||||
case SK_KEY_LCTRL: return "SK_KEY_LCTRL";
|
||||
case SK_KEY_LWIN: return "SK_KEY_LWIN";
|
||||
case SK_KEY_LALT: return "SK_KEY_LALT";
|
||||
case SK_KEY_SPACE: return "SK_KEY_SPACE";
|
||||
case SK_KEY_ALTGR: return "SK_KEY_ALTGR";
|
||||
case SK_KEY_SHARKOON: return "SK_KEY_SHARKOON";
|
||||
case SK_KEY_MENU: return "SK_KEY_MENU";
|
||||
case SK_KEY_RCTRL: return "SK_KEY_RCTRL";
|
||||
case SK_KEY_LEFT: return "SK_KEY_LEFT";
|
||||
case SK_KEY_DOWN: return "SK_KEY_DOWN";
|
||||
case SK_KEY_RIGHT: return "SK_KEY_RIGHT";
|
||||
case SK_KEY_NUM0: return "SK_KEY_NUM0";
|
||||
case SK_KEY_NUMDEL: return "SK_KEY_NUMDEL";
|
||||
}
|
||||
|
||||
return SK_KEY_BAD;
|
||||
return "SK_KEY_BAD";
|
||||
}
|
||||
|
@ -39,7 +39,7 @@
|
||||
#define SK_KEY_PGUP 0x006f
|
||||
#define SK_KEY_NUMLOCK 0x0072
|
||||
#define SK_KEY_NUMDIV 0x0075
|
||||
#define SK_KEY_NUMASTERIX 0x0078
|
||||
#define SK_KEY_NUMASTERISK 0x0078
|
||||
#define SK_KEY_NUMMINUS 0x007A
|
||||
#define SK_KEY_TAB 0x007E
|
||||
#define SK_KEY_Q 0x0081
|
||||
@ -109,11 +109,12 @@
|
||||
#define SK_KEY_NUM0 0x0171
|
||||
#define SK_KEY_NUMDEL 0x0174
|
||||
|
||||
#define SK_LIMIT_KEY 0x0177
|
||||
|
||||
typedef uint16_t skillerctl_keyaddr_t;
|
||||
|
||||
skillerctl_keyaddr_t skillerctl_keyaddr(const char* name);
|
||||
|
||||
char* skillerctl_keystr(skillerctl_keyaddr_t key);
|
||||
char* skillerctl_keystr(skillerctl_keyaddr_t key);
|
||||
|
||||
#endif /* KEYS_H */
|
||||
|
||||
|
117
src/skiller.c
117
src/skiller.c
@ -1,6 +1,28 @@
|
||||
#include "skiller.h"
|
||||
#include "utils.h"
|
||||
#include <memory.h>
|
||||
|
||||
skillerctl_name_value_pair_t modesLUT[] = {
|
||||
SK_MODE_WAVE , "wave",
|
||||
SK_MODE_DRIFT , "drift",
|
||||
SK_MODE_SWIRL , "swirl",
|
||||
SK_MODE_CHANGE , "change",
|
||||
SK_MODE_PULSATING, "pulsating",
|
||||
SK_MODE_PERMAMENT, "permament",
|
||||
SK_MODE_TRIGGER , "trigger",
|
||||
SK_MODE_EXPLOSION, "explosion",
|
||||
SK_MODE_BURST , "burst",
|
||||
SK_MODE_CHAOS , "chaos",
|
||||
SK_MODE_COSMIC , "cosmic",
|
||||
SK_MODE_GRADIENT , "gradient",
|
||||
SK_MODE_TIDE , "tide",
|
||||
SK_MODE_LIGHTING , "lighting",
|
||||
SK_MODE_MATRIX , "matrix",
|
||||
SK_MODE_RICOCHET , "ricochet",
|
||||
SK_MODE_RIPPLE , "ripple",
|
||||
SK_MODE_CUSTOM , "custom",
|
||||
};
|
||||
|
||||
skillerctl_packet_t* skillerctl_unpack(skillerctl_packet_t *packet, uint8_t *data, size_t length) {
|
||||
if (*(unsigned char*)data != 0x04 || length < 1) {
|
||||
return NULL;
|
||||
@ -68,17 +90,102 @@ void skillerctl_color_command(skillerctl_packet_t *packet, skillerctl_keyaddr_t
|
||||
payload.color[0].g = (color >> 8) & 0xFF;
|
||||
payload.color[0].b = color & 0xFF;
|
||||
|
||||
skillerctl_make_packet(packet, SK_CMD_COLOR, address, &payload, 3);
|
||||
skillerctl_make_packet(packet, SK_CMD_SET_COLOR, address, &payload, 3);
|
||||
}
|
||||
|
||||
void skillerctl_enable_command(skillerctl_packet_t *packet)
|
||||
void skillerctl_color_batch_command(skillerctl_packet_t *packet, skillerctl_keyaddr_t address, uint32_t *color, size_t n)
|
||||
{
|
||||
skillerctl_payload_color_t payload;
|
||||
skillerctl_make_packet(packet, SK_CMD_ENABLE, 0x0000, NULL, 0);
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
payload.color[i].r = (color[i] >> 16) & 0xFF;
|
||||
payload.color[i].g = (color[i] >> 8) & 0xFF;
|
||||
payload.color[i].b = color[i] & 0xFF;
|
||||
}
|
||||
|
||||
skillerctl_make_packet(packet, SK_CMD_SET_COLOR, address, &payload, 3*n);
|
||||
}
|
||||
|
||||
void skillerctl_disable_command(skillerctl_packet_t *packet)
|
||||
void skillerctl_enable_led_command(skillerctl_packet_t *packet)
|
||||
{
|
||||
skillerctl_payload_color_t payload;
|
||||
skillerctl_make_packet(packet, SK_CMD_DISABLE, 0x0000, NULL, 0);
|
||||
skillerctl_make_packet(packet, SK_CMD_ENABLE_LED, 0x0000, NULL, 0);
|
||||
}
|
||||
|
||||
void skillerctl_disable_led_command(skillerctl_packet_t *packet)
|
||||
{
|
||||
skillerctl_payload_color_t payload;
|
||||
skillerctl_make_packet(packet, SK_CMD_DISABLE_LED, 0x0000, NULL, 0);
|
||||
}
|
||||
|
||||
void skillerctl_set_mode_command(skillerctl_packet_t *packet, uint8_t mode)
|
||||
{
|
||||
skillerctl_make_packet(packet, SK_CMD_SET_PROP, SK_PROP_MODE, &mode, 1);
|
||||
}
|
||||
|
||||
void skillerctl_set_brightness_command(skillerctl_packet_t *packet, uint8_t brightness)
|
||||
{
|
||||
skillerctl_make_packet(packet, SK_CMD_SET_PROP, SK_PROP_BRIGHTNESS, &brightness, 1);
|
||||
}
|
||||
|
||||
void skillerctl_set_direction_command(skillerctl_packet_t *packet, uint8_t direction)
|
||||
{
|
||||
skillerctl_make_packet(packet, SK_CMD_SET_PROP, SK_PROP_DIRECTION, &direction, 1);
|
||||
}
|
||||
|
||||
void skillerctl_set_rgb_command(skillerctl_packet_t *packet, uint8_t rgb)
|
||||
{
|
||||
skillerctl_make_packet(packet, SK_CMD_SET_PROP, SK_PROP_RGB, &rgb, 1);
|
||||
}
|
||||
|
||||
void skillerctl_set_speed_command(skillerctl_packet_t *packet, uint8_t speed)
|
||||
{
|
||||
skillerctl_make_packet(packet, SK_CMD_SET_PROP, SK_PROP_SPEED, &speed, 1);
|
||||
}
|
||||
|
||||
void skillerctl_set_polling_command(skillerctl_packet_t *packet, uint8_t rate)
|
||||
{
|
||||
skillerctl_make_packet(packet, SK_CMD_SET_PROP, SK_PROP_POLLING, &rate, 1);
|
||||
}
|
||||
|
||||
void skillerctl_set_base_color_command(skillerctl_packet_t *packet, uint32_t color)
|
||||
{
|
||||
skillerctl_payload_color_t payload;
|
||||
|
||||
payload.color[0].r = (color >> 16) & 0xFF;
|
||||
payload.color[0].g = (color >> 8) & 0xFF;
|
||||
payload.color[0].b = color & 0xFF;
|
||||
|
||||
skillerctl_make_packet(packet, SK_CMD_SET_PROP, SK_PROP_COLOR, &payload, 3);
|
||||
}
|
||||
|
||||
char* skillerctl_modestr(skillerctl_mode_t mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case SK_MODE_WAVE: return "SK_MODE_WAVE";
|
||||
case SK_MODE_DRIFT: return "SK_MODE_DRIFT";
|
||||
case SK_MODE_SWIRL: return "SK_MODE_SWIRL";
|
||||
case SK_MODE_CHANGE: return "SK_MODE_CHANGE";
|
||||
case SK_MODE_PULSATING: return "SK_MODE_PULSATING";
|
||||
case SK_MODE_PERMAMENT: return "SK_MODE_PERMAMENT";
|
||||
case SK_MODE_TRIGGER: return "SK_MODE_TRIGGER";
|
||||
case SK_MODE_EXPLOSION: return "SK_MODE_EXPLOSION";
|
||||
case SK_MODE_BURST: return "SK_MODE_BURST";
|
||||
case SK_MODE_CHAOS: return "SK_MODE_CHAOS";
|
||||
case SK_MODE_COSMIC: return "SK_MODE_COSMIC";
|
||||
case SK_MODE_GRADIENT: return "SK_MODE_GRADIENT";
|
||||
case SK_MODE_TIDE: return "SK_MODE_TIDE";
|
||||
case SK_MODE_LIGHTING: return "SK_MODE_LIGHTING";
|
||||
case SK_MODE_MATRIX: return "SK_MODE_MATRIX";
|
||||
case SK_MODE_RICOCHET: return "SK_MODE_RICOCHET";
|
||||
case SK_MODE_RIPPLE: return "SK_MODE_RIPPLE";
|
||||
case SK_MODE_CUSTOM: return "SK_MODE_CUSTOM";
|
||||
}
|
||||
|
||||
return "SK_MODE_UNKNOWN";
|
||||
}
|
||||
|
||||
skillerctl_mode_t skillerctl_strmode(const char *mode)
|
||||
{
|
||||
return skillerctl_lut_search(modesLUT, sizeof(modesLUT) / sizeof(skillerctl_name_value_pair_t), mode);
|
||||
}
|
||||
|
@ -8,11 +8,44 @@
|
||||
#define SK_MAX_PAYLOAD 56
|
||||
#define SK_PACKET_SIZE 64
|
||||
|
||||
#define SK_MAGIC 0x04
|
||||
#define SK_MAGIC 0x04
|
||||
|
||||
#define SK_CMD_COLOR 0x11
|
||||
#define SK_CMD_ENABLE 0x01
|
||||
#define SK_CMD_DISABLE 0x02
|
||||
#define SK_CMD_DISABLE_LED 0x01 // Disables key backlight, takes some time
|
||||
#define SK_CMD_ENABLE_LED 0x02 // Enables key backlight, takes some time
|
||||
#define SK_CMD_SET_PROP 0x06 // Changes keyboard mode or mode settings
|
||||
#define SK_CMD_MAP_KEYS 0x08 // Writes key mapping to controller
|
||||
#define SK_CMD_WRITE_MACRO 0x0A // Saves macros in controller memory
|
||||
#define SK_CMD_SET_COLOR 0x11 // Changes LED RGB values in key given keys, or key range.
|
||||
|
||||
#define SK_PROP_MODE 0x00 // Changes backlight program (pulsing, permamant, custom, etc.)
|
||||
#define SK_PROP_BRIGHTNESS 0x01 // Sets brihgtness level
|
||||
#define SK_PROP_SPEED 0x02 // Sets animation speed
|
||||
#define SK_PROP_DIRECTION 0x03 // Sets animation direction
|
||||
#define SK_PROP_RGB 0x04 // LGBT promotion
|
||||
#define SK_PROP_COLOR 0x05 // Base color
|
||||
#define SK_PROP_POLLING 0x0F // Polling rate
|
||||
|
||||
#define SK_MODE_WAVE 0x01 // Wave
|
||||
#define SK_MODE_DRIFT 0x02 // Drift
|
||||
#define SK_MODE_SWIRL 0x03 // Swirl
|
||||
#define SK_MODE_CHANGE 0x04 // color change
|
||||
#define SK_MODE_PULSATING 0x05 // pulsating
|
||||
#define SK_MODE_PERMAMENT 0x06 // permament
|
||||
#define SK_MODE_TRIGGER 0x07 // Trigger
|
||||
#define SK_MODE_EXPLOSION 0x08 // Explosion
|
||||
#define SK_MODE_BURST 0x09 // Gamma Ray Burst
|
||||
#define SK_MODE_CHAOS 0x0A // Chaos
|
||||
#define SK_MODE_COSMIC 0x0B // Cosmic
|
||||
#define SK_MODE_GRADIENT 0x0C // Gradient
|
||||
#define SK_MODE_TIDE 0x0D // Tide
|
||||
#define SK_MODE_LIGHTING 0x0E // Ball Lighting
|
||||
#define SK_MODE_MATRIX 0x0F // Matrix
|
||||
#define SK_MODE_RICOCHET 0x10 // Ricochet
|
||||
#define SK_MODE_RIPPLE 0x12 // Ripple
|
||||
#define SK_MODE_CUSTOM 0x14 // Custom
|
||||
|
||||
typedef uint16_t skillerctl_property_t;
|
||||
typedef uint8_t skillerctl_mode_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t magic;
|
||||
@ -24,23 +57,38 @@ typedef struct {
|
||||
} skillerctl_packet_t;
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
} color[SK_MAX_PAYLOAD / 3];
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
} skillerctl_color_t;
|
||||
|
||||
typedef struct {
|
||||
skillerctl_color_t color[SK_MAX_PAYLOAD / 3];
|
||||
} skillerctl_payload_color_t;
|
||||
|
||||
void skillerctl_make_packet(skillerctl_packet_t *packet, uint8_t command, uint16_t address, void* payload, uint8_t size);
|
||||
|
||||
void skillerctl_color_command(skillerctl_packet_t *packet, skillerctl_keyaddr_t address, uint32_t color);
|
||||
void skillerctl_enable_command(skillerctl_packet_t *packet);
|
||||
void skillerctl_disable_command(skillerctl_packet_t *packet);
|
||||
void skillerctl_color_batch_command(skillerctl_packet_t *packet, skillerctl_keyaddr_t start, uint32_t *colors, size_t n);
|
||||
|
||||
void skillerctl_enable_led_command(skillerctl_packet_t *packet);
|
||||
void skillerctl_disable_led_command(skillerctl_packet_t *packet);
|
||||
|
||||
void skillerctl_set_mode_command(skillerctl_packet_t *packet, skillerctl_mode_t mode);
|
||||
void skillerctl_set_brightness_command(skillerctl_packet_t *packet, uint8_t brightness);
|
||||
void skillerctl_set_direction_command(skillerctl_packet_t *packet, uint8_t direction);
|
||||
void skillerctl_set_rgb_command(skillerctl_packet_t *packet, uint8_t rgb);
|
||||
void skillerctl_set_base_color_command(skillerctl_packet_t *packet, uint32_t color);
|
||||
void skillerctl_set_speed_command(skillerctl_packet_t *packet, uint8_t speed);
|
||||
void skillerctl_set_polling_command(skillerctl_packet_t *packet, uint8_t rate);
|
||||
|
||||
skillerctl_packet_t* skillerctl_unpack(skillerctl_packet_t *packet, uint8_t *data, size_t length);
|
||||
void* skillerctl_pack(skillerctl_packet_t *packet, uint8_t *data);
|
||||
|
||||
uint16_t skillectl_packet_checksum(skillerctl_packet_t *packet);
|
||||
|
||||
char* skillerctl_modestr(skillerctl_mode_t mode);
|
||||
skillerctl_mode_t skillerctl_strmode(const char *mode);
|
||||
|
||||
#endif /* SKILLER_H */
|
||||
|
||||
|
114
src/skillerctl.c
114
src/skillerctl.c
@ -1,49 +1,122 @@
|
||||
/**
|
||||
* Ten program jest napisany bardziej w postaci PoC niż faktycznej aplikacji użytkowej - stąd brak jakiejkolwiek walidacji inputu użytkownika.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "skiller.h"
|
||||
#include "usb.h"
|
||||
#include "utils.h"
|
||||
|
||||
void stuff(libusb_device *skiller)
|
||||
#define PACKETS_MAX 255
|
||||
|
||||
skillerctl_packet_t packets[255] = {};
|
||||
size_t count = 0;
|
||||
|
||||
char *input_pop_arg(int *i, int argc, char **argv)
|
||||
{
|
||||
if (++*i >= argc) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return argv[*i];
|
||||
}
|
||||
|
||||
size_t handle_input(int argc, char **argv)
|
||||
{
|
||||
char *arg;
|
||||
int i = 0;
|
||||
|
||||
while ((arg = input_pop_arg(&i, argc, argv))) {
|
||||
skillerctl_packet_t *current = packets + count;
|
||||
|
||||
if (strcmp(arg, "-d") == 0) {
|
||||
printf("Disable leds.\n");
|
||||
skillerctl_disable_led_command(current);
|
||||
|
||||
count++;
|
||||
} else if (strcmp(arg, "-e") == 0) {
|
||||
printf("Enable leds.\n");
|
||||
skillerctl_enable_led_command(current);
|
||||
|
||||
count++;
|
||||
} else if (strcmp(arg, "-c") == 0) {
|
||||
char *keys = input_pop_arg(&i, argc, argv);
|
||||
uint32_t color = strtol(input_pop_arg(&i, argc, argv), NULL, 16);
|
||||
|
||||
keys = strtok(keys, ",");
|
||||
do {
|
||||
skillerctl_keyaddr_t addr = skillerctl_keyaddr(keys);
|
||||
printf("Set key %s [%04xh] color to #%06x.\n", skillerctl_keystr(addr), addr, color);
|
||||
skillerctl_color_command(packets + count++, addr, color);
|
||||
} while ((keys = strtok(NULL, ",")));
|
||||
} else if (strcmp(arg, "-C") == 0) {
|
||||
uint32_t color = strtol(input_pop_arg(&i, argc, argv), NULL, 16);
|
||||
|
||||
printf("Clear to #%06x.\n", color);
|
||||
|
||||
uint32_t colors[18] = {};
|
||||
for (int i = 0; i < 18; i++) colors[i] = color;
|
||||
|
||||
for (int i = 0; i <= SK_LIMIT_KEY / 54; i++) {
|
||||
skillerctl_color_batch_command(packets + count++, 54*i, colors, 18);
|
||||
}
|
||||
} else if (strcmp(arg, "-b") == 0) {
|
||||
uint8_t brightness = strtol(input_pop_arg(&i, argc, argv), NULL, 10);
|
||||
|
||||
printf("Set brightness to %d.\n", brightness);
|
||||
skillerctl_set_brightness_command(current, brightness);
|
||||
|
||||
count++;
|
||||
} else if (strcmp(arg, "-m") == 0) {
|
||||
skillerctl_mode_t mode = skillerctl_strmode(input_pop_arg(&i, argc, argv));
|
||||
|
||||
if (mode == 0xFF) {
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("Set mode to to %s [%02xh].\n", skillerctl_modestr(mode), mode);
|
||||
skillerctl_set_mode_command(current, mode);
|
||||
|
||||
count++;
|
||||
} else {
|
||||
printf("Unknown command %s, omiting.\n", arg);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void handle_logic(libusb_device *skiller)
|
||||
{
|
||||
libusb_device_handle *handle;
|
||||
skillerctl_packet_t packet;
|
||||
|
||||
if (skiller == NULL) {
|
||||
printf("Device not found kurwa.\n");
|
||||
printf("Cannot found compatibile keyboard, is it connected?\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (libusb_open(skiller, &handle) != LIBUSB_SUCCESS) {
|
||||
printf("Nie udało się nawiązać połączenia kurwa..\n");
|
||||
printf("Cannot open device, try with sudo.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Hura kurwa.\n");
|
||||
|
||||
libusb_detach_kernel_driver(handle, 1);
|
||||
libusb_claim_interface(handle, 1);
|
||||
|
||||
/* skillerctl_enable_command(&packet); */
|
||||
/* skillerctl_send_command(handle, &packet); */
|
||||
|
||||
skillerctl_color_command(&packet, SK_KEY_ESC, 0xFF0000);
|
||||
skillerctl_send_command(handle, &packet);
|
||||
skillerctl_color_command(&packet, SK_KEY_F1, 0x00FF00);
|
||||
skillerctl_send_command(handle, &packet);
|
||||
skillerctl_color_command(&packet, SK_KEY_F2, 0x0000FF);
|
||||
skillerctl_send_command(handle, &packet);
|
||||
|
||||
/* skillerctl_disable_command(&packet); */
|
||||
/* skillerctl_send_command(handle, &packet); */
|
||||
for (int i = 0; i < count; i++) {
|
||||
skillerctl_send_command(handle, packets + i);
|
||||
}
|
||||
|
||||
libusb_release_interface(handle, 1);
|
||||
libusb_attach_kernel_driver(handle, 1);
|
||||
libusb_close(handle);
|
||||
}
|
||||
|
||||
int main()
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
libusb_device **list;
|
||||
|
||||
@ -51,7 +124,8 @@ int main()
|
||||
size_t count = libusb_get_device_list(NULL, &list);
|
||||
libusb_device *skiller = skillerctl_find_device(list, count);
|
||||
|
||||
stuff(skiller);
|
||||
handle_input(argc, argv);
|
||||
handle_logic(skiller);
|
||||
|
||||
libusb_free_device_list(list, 1);
|
||||
libusb_exit(NULL);
|
||||
|
11
src/utils.c
11
src/utils.c
@ -1,5 +1,6 @@
|
||||
#include "utils.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
void hexdump(void* data, size_t length)
|
||||
{
|
||||
@ -15,3 +16,13 @@ void hexdump(void* data, size_t length)
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t skillerctl_lut_search(skillerctl_name_value_pair_t *lut, size_t n, const char* name)
|
||||
{
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (strcmp(lut[i].name, name) == 0) {
|
||||
return lut[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@ -17,8 +17,14 @@
|
||||
} while (0)
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
typedef struct {
|
||||
uint16_t value;
|
||||
char* name;
|
||||
} skillerctl_name_value_pair_t;
|
||||
|
||||
void hexdump(void* bytes, size_t length);
|
||||
uint16_t skillerctl_lut_search(skillerctl_name_value_pair_t *lut, size_t n, const char* name);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user