added heatmap

This commit is contained in:
Kacper Donat 2019-01-07 22:17:14 +01:00
parent 413eb916e4
commit b6faa0bd2d
12 changed files with 926 additions and 148 deletions

View File

@ -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.

View File

@ -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};

View File

@ -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
View 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);
}

View File

@ -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";
}

View File

@ -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 */

View File

@ -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);
}

View File

@ -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 */

View File

@ -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);

View File

@ -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;
}

View File

@ -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