ckb-next  v0.2.8 at branch master
ckb-next driver for corsair devices
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
command.c File Reference
#include <limits.h>
#include "command.h"
#include "device.h"
#include "devnode.h"
#include "led.h"
#include "notify.h"
#include "profile.h"
#include "usb.h"
+ Include dependency graph for command.c:

Go to the source code of this file.

Macros

#define TRY_WITH_RESET(action)
 

Functions

int readcmd (usbdevice *kb, const char *line)
 

Variables

static const char *const cmd_strings [(CMD_LAST-CMD_FIRST+2)-1]
 

Macro Definition Documentation

#define TRY_WITH_RESET (   action)
Value:
while(action){ \
if(usb_tryreset(kb)){ \
free(word); \
return 1; \
} \
}
int usb_tryreset(usbdevice *kb)
Definition: usb.c:475

Definition at line 59 of file command.c.

Referenced by readcmd().

Function Documentation

int readcmd ( usbdevice kb,
const char *  line 
)

< Because length of word is length of line + 1, there should be no problem with buffer overflow.

Definition at line 68 of file command.c.

References ACCEL, ACTIVE, usbdevice::active, BIND, CMD_COUNT, CMD_FIRST, cmd_strings, usbprofile::currentmode, DELAY, usbdevice::delay, DITHER, usbdevice::dither, devcmd::do_cmd, devcmd::do_io, devcmd::do_macro, DPI, DPISEL, ERASE, ERASEPROFILE, FEAT_ANSI, FEAT_BIND, FEAT_ISO, FEAT_LMASK, FEAT_MOUSEACCEL, FEAT_NOTIFY, usbdevice::features, lighting::forceupdate, FPS, FWUPDATE, GET, HAS_FEATURES, HWLOAD, HWSAVE, IAUTO, ID, IDLE, INDEX_OF, INOTIFY, IOFF, ION, IS_FULLRANGE, IS_MOUSE_DEV, keymap, LAYOUT, left, LIFT, usbmode::light, MACRO, mknotifynode(), MODE, usbprofile::mode, MODE_COUNT, N_KEYS_EXTENDED, NAME, NEEDS_FW_UPDATE, NONE, NOTIFY, NOTIFYOFF, NOTIFYON, OUTFIFO_MAX, POLLRATE, usbdevice::profile, PROFILEID, PROFILENAME, REBIND, RESTART, RGB, right(), rmnotifynode(), SCROLL_ACCELERATED, SCROLL_MAX, SCROLL_MIN, SCROLLSPEED, SNAP, SWITCH, TRY_WITH_RESET, UNBIND, usbdevice::usbdelay, and usbdevice::vtable.

Referenced by devmain().

68  {
69  char* word = malloc(strlen(line) + 1);
70  int wordlen;
71  const char* newline = 0;
72  const devcmd* vt = kb->vtable;
73  usbprofile* profile = kb->profile;
74  usbmode* mode = 0;
75  int notifynumber = 0;
76  // Read words from the input
77  cmd command = NONE;
78  while(sscanf(line, "%s%n", word, &wordlen) == 1){
79  line += wordlen;
80  // If we passed a newline, reset the context
81  if(line > newline){
82  mode = profile->currentmode;
83  command = NONE;
84  notifynumber = 0;
85  newline = strchr(line, '\n');
86  if(!newline)
87  newline = line + strlen(line);
88  }
89  // Check for a command word
90  for(int i = 0; i < CMD_COUNT - 1; i++){
91  if(!strcmp(word, cmd_strings[i])){
92  command = i + CMD_FIRST;
93 #ifndef OS_MAC
94  // Layout and mouse acceleration aren't used on Linux; ignore
95  if(command == LAYOUT || command == ACCEL || command == SCROLLSPEED)
96  command = NONE;
97 #endif
98  // Most commands require parameters, but a few are actions in and of themselves
99  if(command != SWITCH
100  && command != HWLOAD && command != HWSAVE
101  && command != ACTIVE && command != IDLE
102  && command != ERASE && command != ERASEPROFILE
103  && command != RESTART)
104  goto next_loop;
105  break;
106  }
107  }
108 
109  // Set current notification node when given @number
110  int newnotify;
111  if(sscanf(word, "@%u", &newnotify) == 1 && newnotify < OUTFIFO_MAX){
112  notifynumber = newnotify;
113  continue;
114  }
115 
116  // Reject unrecognized commands. Reject bind or notify related commands if the keyboard doesn't have the feature enabled.
117  if(command == NONE
118  || ((!HAS_FEATURES(kb, FEAT_BIND) && (command == BIND || command == UNBIND || command == REBIND || command == MACRO || command == DELAY))
119  || (!HAS_FEATURES(kb, FEAT_NOTIFY) && command == NOTIFY))){
120  next_loop:
121  continue;
122  }
123  // Reject anything not related to fwupdate if device has a bricked FW
124  if(NEEDS_FW_UPDATE(kb) && command != FWUPDATE && command != NOTIFYON && command != NOTIFYOFF)
125  continue;
126 
127  // Specially handled commands - these are available even when keyboard is IDLE
128  switch(command){
129  case NOTIFYON: {
130  // Notification node on
131  int notify;
132  if(sscanf(word, "%u", &notify) == 1)
133  mknotifynode(kb, notify);
134  continue;
135  } case NOTIFYOFF: {
136  // Notification node off
137  int notify;
138  if(sscanf(word, "%u", &notify) == 1 && notify != 0) // notify0 can't be removed
139  rmnotifynode(kb, notify);
140  continue;
141  } case GET:
142  // Output data to notification node
143  vt->get(kb, mode, notifynumber, 0, word);
144  continue;
145  case LAYOUT:
146  // OSX: switch ANSI/ISO keyboard layout
147  if(!strcmp(word, "ansi"))
148  kb->features = (kb->features & ~FEAT_LMASK) | FEAT_ANSI;
149  else if(!strcmp(word, "iso"))
150  kb->features = (kb->features & ~FEAT_LMASK) | FEAT_ISO;
151  continue;
152 #ifdef OS_MAC
153  case ACCEL:
154  // OSX mouse acceleration on/off
155  if(!strcmp(word, "on"))
156  kb->features |= FEAT_MOUSEACCEL;
157  else if(!strcmp(word, "off"))
158  kb->features &= ~FEAT_MOUSEACCEL;
159  continue;
160  case SCROLLSPEED:{
161  int newscroll;
162  if(sscanf(word, "%d", &newscroll) != 1)
163  break;
164  if(newscroll < SCROLL_MIN)
165  newscroll = SCROLL_ACCELERATED;
166  if(newscroll > SCROLL_MAX)
167  newscroll = SCROLL_MAX;
168  kb->scroll_rate = newscroll;
169  continue;
170  }
171 #endif
172  case MODE: {
173  // Select a mode number (1 - 6)
174  int newmode;
175  if(sscanf(word, "%u", &newmode) == 1 && newmode > 0 && newmode <= MODE_COUNT)
176  mode = profile->mode + newmode - 1;
177  continue;
178  }
179  case FPS: {
180  // USB command delay (2 - 10ms)
181  uint framerate;
182  if(sscanf(word, "%u", &framerate) == 1 && framerate > 0){
183  // Not all devices require the same number of messages per frame; select delay appropriately
184  uint per_frame = IS_MOUSE_DEV(kb) ? 2 : IS_FULLRANGE(kb) ? 14 : 5;
185  uint delay = 1000 / framerate / per_frame;
186  if(delay < 2)
187  delay = 2;
188  else if(delay > 10)
189  delay = 10;
190  kb->usbdelay = delay;
191  }
192  continue;
193  }
194  case DITHER: {
195  // 0: No dither, 1: Ordered dither.
196  uint dither;
197  if(sscanf(word, "%u", &dither) == 1 && dither <= 1){
198  kb->dither = dither;
199  profile->currentmode->light.forceupdate = 1;
200  mode->light.forceupdate = 1;
201  }
202  continue;
203  }
204  case DELAY: {
205  long int delay;
206  if(sscanf(word, "%ld", &delay) == 1 && 0 <= delay && delay < UINT_MAX) {
207  // Add delay of `newdelay` microseconds to macro playback
208  kb->delay = (unsigned int)delay;
209  } else if(strcmp(word, "on") == 0) {
210  // allow previous syntax, `delay on` means use old `long macro delay`
211  kb->delay = UINT_MAX;
212  } else {
213  // bad parameter to handle false commands like "delay off"
214  kb->delay = 0; // No delay.
215  }
216  continue;
217  }
218  case RESTART: {
219  char mybuffer[] = "no reason specified";
220  if (sscanf(line, " %[^\n]", word) == -1) {
221  word = mybuffer;
222  }
223  vt->do_cmd[command](kb, mode, notifynumber, 0, word);
224  continue;
225  }
226  default:;
227  }
228 
229  // If a keyboard is inactive, it must be activated before receiving any other commands
230  if(!kb->active){
231  if(command == ACTIVE)
232  TRY_WITH_RESET(vt->active(kb, mode, notifynumber, 0, 0));
233  continue;
234  }
235  // Specially handled commands only available when keyboard is ACTIVE
236  switch(command){
237  case IDLE:
238  TRY_WITH_RESET(vt->idle(kb, mode, notifynumber, 0, 0));
239  continue;
240  case SWITCH:
241  if(profile->currentmode != mode){
242  profile->currentmode = mode;
243  // Set mode light for non-RGB K95
244  int index = INDEX_OF(mode, profile->mode);
245  vt->setmodeindex(kb, index);
246  }
247  continue;
248  case HWLOAD: case HWSAVE:{
249  char delay = kb->usbdelay;
250  // Ensure delay of at least 10ms as the device can get overwhelmed otherwise
251  if(delay < 10)
252  kb->usbdelay = 10;
253  // Try to load/save the hardware profile. Reset on failure, disconnect if reset fails.
254  TRY_WITH_RESET(vt->do_io[command](kb, mode, notifynumber, 1, 0));
255  // Re-send the current RGB state as it sometimes gets scrambled
256  TRY_WITH_RESET(vt->updatergb(kb, 1));
257  kb->usbdelay = delay;
258  continue;
259  }
260  case FWUPDATE:
261  // FW update parses a whole word. Unlike hwload/hwsave, there's no try again on failure.
262  if(vt->fwupdate(kb, mode, notifynumber, 0, word)){
263  free(word);
264  return 1;
265  }
266  continue;
267  case POLLRATE: {
268  uint rate;
269  if(sscanf(word, "%u", &rate) == 1 && (rate == 1 || rate == 2 || rate == 4 || rate == 8))
270  TRY_WITH_RESET(vt->pollrate(kb, mode, notifynumber, rate, 0));
271  continue;
272  }
273  case ERASEPROFILE:
274  // Erase the current profile
275  vt->eraseprofile(kb, mode, notifynumber, 0, 0);
276  // Update profile/mode pointers
277  profile = kb->profile;
278  mode = profile->currentmode;
279  continue;
280  case ERASE: case NAME: case IOFF: case ION: case IAUTO: case INOTIFY: case PROFILENAME: case ID: case PROFILEID: case DPISEL: case LIFT: case SNAP:
281  // All of the above just parse the whole word
282  vt->do_cmd[command](kb, mode, notifynumber, 0, word);
283  continue;
284  case RGB: {
285  // RGB command has a special response for a single hex constant
286  int r, g, b;
287  if(sscanf(word, "%02x%02x%02x", &r, &g, &b) == 3){
288  // Set all keys
289  for(int i = 0; i < N_KEYS_EXTENDED; i++)
290  vt->rgb(kb, mode, notifynumber, i, word);
291  continue;
292  }
293  break;
294  }
295  case MACRO:
296  if(!strcmp(word, "clear")){
297  // Macro has a special clear command
298  vt->macro(kb, mode, notifynumber, 0, 0);
299  continue;
300  }
301  break;
302  default:;
303  }
304  // For anything else, split the parameter at the colon
305  int left = -1;
306  sscanf(word, "%*[^:]%n", &left);
307  if(left <= 0)
308  continue;
309  const char* right = word + left;
310  if(right[0] == ':')
311  right++;
312  // Macros and DPI have a separate left-side handler
313  if(command == MACRO || command == DPI){
314  word[left] = 0;
315  vt->do_macro[command](kb, mode, notifynumber, word, right);
316  continue;
317  }
318  // Scan the left side for key names and run the requested command
319  int position = 0, field = 0;
320  char keyname[11];
321  while(position < left && sscanf(word + position, "%10[^:,]%n", keyname, &field) == 1){
322  int keycode;
323  if(!strcmp(keyname, "all")){
324  // Set all keys
325  for(int i = 0; i < N_KEYS_EXTENDED; i++)
326  vt->do_cmd[command](kb, mode, notifynumber, i, right);
327  } else if((sscanf(keyname, "#%d", &keycode) && keycode >= 0 && keycode < N_KEYS_EXTENDED)
328  || (sscanf(keyname, "#x%x", &keycode) && keycode >= 0 && keycode < N_KEYS_EXTENDED)){
329  // Set a key numerically
330  vt->do_cmd[command](kb, mode, notifynumber, keycode, right);
331  } else {
332  // Find this key in the keymap
333  for(unsigned i = 0; i < N_KEYS_EXTENDED; i++){
334  if(keymap[i].name && !strcmp(keyname, keymap[i].name)){
335  vt->do_cmd[command](kb, mode, notifynumber, i, right);
336  break;
337  }
338  }
339  }
340  if(word[position += field] == ',')
341  position++;
342  }
343  }
344 
345  // Finish up
346  if(!NEEDS_FW_UPDATE(kb)){
347  TRY_WITH_RESET(vt->updatergb(kb, 0));
348  TRY_WITH_RESET(vt->updatedpi(kb, 0));
349  }
350  free(word);
351  return 0;
352 }
Definition: command.h:43
Definition: command.h:19
#define IS_FULLRANGE(kb)
Full color range (16.8M) vs partial color range (512)
Definition: usb.h:160
#define SCROLL_MIN
Definition: structures.h:165
#define FEAT_MOUSEACCEL
Definition: structures.h:148
Definition: command.h:73
#define MODE_COUNT
Definition: structures.h:100
Definition: command.h:10
uint delay
Definition: structures.h:251
usbprofile * profile
Definition: structures.h:221
Definition: command.h:48
Definition: command.h:29
usbmode * currentmode
Definition: structures.h:105
const key keymap[(((152+22+12)+25)+12)]
Definition: keymap.c:5
cmd
Definition: command.h:7
usbmode mode[6]
Definition: structures.h:103
#define SCROLL_ACCELERATED
Definition: structures.h:164
cmdhandler do_cmd[(CMD_LAST-CMD_VT_FIRST+1)]
Definition: command.h:75
Definition: command.h:42
#define SCROLL_MAX
Definition: structures.h:166
Definition: command.h:28
char dither
Definition: structures.h:249
Definition: command.h:54
#define FEAT_BIND
Definition: structures.h:140
#define FEAT_ANSI
Definition: structures.h:146
char active
Definition: structures.h:231
Definition: command.h:9
lighting light
Definition: structures.h:84
Definition: command.h:18
cmdhandler_mac do_macro[(CMD_LAST-CMD_VT_FIRST+1)]
Definition: command.h:77
Definition: command.h:13
Definition: command.h:40
uchar forceupdate
Definition: structures.h:77
Definition: command.h:46
#define CMD_COUNT
Definition: command.h:65
Definition: command.h:22
Definition: command.h:47
#define INDEX_OF(entry, array)
Definition: includes.h:27
Definition: command.h:60
#define NEEDS_FW_UPDATE(kb)
Definition: structures.h:161
double left
Definition: main.c:51
cmdhandler_io do_io[(CMD_LAST-CMD_VT_FIRST+1)]
Definition: command.h:76
static QString right(const QString &left)
const union devcmd * vtable
Definition: structures.h:180
Definition: command.h:53
Definition: command.h:36
Definition: command.h:41
Definition: command.h:23
#define FEAT_ISO
Definition: structures.h:147
Definition: command.h:34
ushort features
Definition: structures.h:229
#define IS_MOUSE_DEV(kb)
For calling with a usbdevice*, vendor and product are extracted and IS_MOUSE() is returned...
Definition: usb.h:166
char usbdelay
Definition: structures.h:243
#define HAS_FEATURES(kb, feat)
Definition: structures.h:157
#define FEAT_LMASK
Definition: structures.h:154
#define N_KEYS_EXTENDED
Definition: keymap.h:45
Definition: command.h:52
int rmnotifynode(usbdevice *kb, int notify)
Removes a notification node for the specified keyboard.
Definition: devnode.c:129
Definition: command.h:12
Definition: command.h:58
static const char *const cmd_strings[(CMD_LAST-CMD_FIRST+2)-1]
Definition: command.c:10
int mknotifynode(usbdevice *kb, int notify)
Creates a notification node for the specified keyboard.
Definition: devnode.c:108
#define FEAT_NOTIFY
Definition: structures.h:141
#define TRY_WITH_RESET(action)
Definition: command.c:59
Definition: command.h:14
Definition: command.h:11
Definition: command.h:32
Definition: command.h:55
Definition: command.h:49
#define OUTFIFO_MAX
Definition: structures.h:24

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Variable Documentation

const char* const cmd_strings[(CMD_LAST-CMD_FIRST+2)-1]
static

Definition at line 10 of file command.c.

Referenced by readcmd().