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
input_linux.c
Go to the documentation of this file.
1 #include "command.h"
2 #include "device.h"
3 #include "input.h"
4 
5 #ifdef OS_LINUX
6 
7 // Xorg has buggy handling of combined keyboard + mouse devices, so instead we should create two separate devices:
8 // One for keyboard events, one for mouse.
9 int uinputopen(struct uinput_user_dev* indev, int mouse){
10  int fd = open("/dev/uinput", O_RDWR);
11  if(fd < 0){
12  // If that didn't work, try /dev/input/uinput instead
13  fd = open("/dev/input/uinput", O_RDWR);
14  if(fd < 0){
15  ckb_err("Failed to open uinput: %s\n", strerror(errno));
16  return 0;
17  }
18  }
19  // Enable all keys and mouse buttons
20  ioctl(fd, UI_SET_EVBIT, EV_KEY);
21  for(int i = 0; i < KEY_CNT; i++)
22  ioctl(fd, UI_SET_KEYBIT, i);
23  if(mouse){
24  // Enable mouse axes
25  ioctl(fd, UI_SET_EVBIT, EV_REL);
26  for(int i = 0; i < REL_CNT; i++)
27  ioctl(fd, UI_SET_RELBIT, i);
28  } else {
29  // Enable LEDs
30  ioctl(fd, UI_SET_EVBIT, EV_LED);
31  for(int i = 0; i < LED_CNT; i++)
32  ioctl(fd, UI_SET_LEDBIT, i);
33  // Eanble autorepeat
34  ioctl(fd, UI_SET_EVBIT, EV_REP);
35  }
36  // Enable sychronization
37  ioctl(fd, UI_SET_EVBIT, EV_SYN);
38  // Create the device
39  if(write(fd, indev, sizeof(*indev)) <= 0)
40  ckb_warn("uinput write failed: %s\n", strerror(errno));
41  if(ioctl(fd, UI_DEV_CREATE)){
42  ckb_err("Failed to create uinput device: %s\n", strerror(errno));
43  close(fd);
44  return 0;
45  }
46  return fd + 1;
47 }
48 
56  // Create the new input device
57  int index = INDEX_OF(kb, keyboard);
58  struct uinput_user_dev indev;
59  memset(&indev, 0, sizeof(indev));
60  snprintf(indev.name, UINPUT_MAX_NAME_SIZE, "ckb%d: %s", index, kb->name);
61  indev.id.bustype = BUS_USB;
62  indev.id.vendor = kb->vendor;
63  indev.id.product = kb->product;
64  indev.id.version = kb->fwversion;
65  // Open keyboard
66  int fd = uinputopen(&indev, 0);
67  kb->uinput_kb = fd;
68  if(fd <= 0)
69  return 0;
70  // Open mouse
71  fd = uinputopen(&indev, 1);
72  kb->uinput_mouse = fd;
73  return fd <= 0;
74 }
75 
77  if(kb->uinput_kb <= 0 || kb->uinput_mouse <= 0)
78  return;
79  // Set all keys released
80  struct input_event event;
81  memset(&event, 0, sizeof(event));
82  event.type = EV_KEY;
83  for(int key = 0; key < KEY_CNT; key++){
84  event.code = key;
85  if(write(kb->uinput_kb - 1, &event, sizeof(event)) <= 0)
86  ckb_warn("uinput write failed: %s\n", strerror(errno));
87  if(write(kb->uinput_mouse - 1, &event, sizeof(event)) <= 0)
88  ckb_warn("uinput write failed: %s\n", strerror(errno));
89  }
90  event.type = EV_SYN;
91  event.code = SYN_REPORT;
92  if(write(kb->uinput_kb - 1, &event, sizeof(event)) <= 0)
93  ckb_warn("uinput write failed: %s\n", strerror(errno));
94  if(write(kb->uinput_mouse - 1, &event, sizeof(event)) <= 0)
95  ckb_warn("uinput write failed: %s\n", strerror(errno));
96  // Close the keyboard
97  ioctl(kb->uinput_kb - 1, UI_DEV_DESTROY);
98  close(kb->uinput_kb - 1);
99  kb->uinput_kb = 0;
100  // Close the mouse
101  ioctl(kb->uinput_mouse - 1, UI_DEV_DESTROY);
102  close(kb->uinput_mouse - 1);
103  kb->uinput_mouse = 0;
104 }
105 
106 // Generate SYN reports to synchronize device
107 static void isync(usbdevice* kb){
108  struct input_event event;
109  memset(&event, 0, sizeof(event));
110  event.type = EV_SYN;
111  event.code = SYN_REPORT;
112  if(write(kb->uinput_kb - 1, &event, sizeof(event)) <= 0)
113  ckb_warn("uinput write failed: %s\n", strerror(errno));
114  if(write(kb->uinput_mouse - 1, &event, sizeof(event)) <= 0)
115  ckb_warn("uinput write failed: %s\n", strerror(errno));
116 }
117 
118 void os_keypress(usbdevice* kb, int scancode, int down){
119  struct input_event event;
120  memset(&event, 0, sizeof(event));
121  int is_mouse = 0;
122  if(scancode == BTN_WHEELUP || scancode == BTN_WHEELDOWN){
123  // The mouse wheel is a relative axis
124  if(!down)
125  return;
126  event.type = EV_REL;
127  event.code = REL_WHEEL;
128  event.value = (scancode == BTN_WHEELUP ? 1 : -1);
129  is_mouse = 1;
130  } else {
131  // Mouse buttons and key events are both EV_KEY. The scancodes are already correct, just remove the ckb bit
132  event.type = EV_KEY;
133  event.code = scancode & ~SCAN_MOUSE;
134  event.value = down;
135  is_mouse = !!(scancode & SCAN_MOUSE);
136  }
137  if(write((is_mouse ? kb->uinput_mouse : kb->uinput_kb) - 1, &event, sizeof(event)) <= 0)
138  ckb_warn("uinput write failed: %s\n", strerror(errno));
139  else
140  isync(kb);
141 }
142 
143 void os_mousemove(usbdevice* kb, int x, int y){
144  struct input_event event;
145  memset(&event, 0, sizeof(event));
146  event.type = EV_REL;
147  if(x != 0){
148  event.code = REL_X;
149  event.value = x;
150  if(write(kb->uinput_mouse - 1, &event, sizeof(event)) <= 0)
151  ckb_warn("uinput write failed: %s\n", strerror(errno));
152  else
153  isync(kb);
154  }
155  if(y != 0){
156  event.code = REL_Y;
157  event.value = y;
158  if(write(kb->uinput_mouse - 1, &event, sizeof(event)) <= 0)
159  ckb_warn("uinput write failed: %s\n", strerror(errno));
160  else
161  isync(kb);
162  }
163 }
164 
165 void* _ledthread(void* ctx){
166  usbdevice* kb = ctx;
167  uchar ileds = 0;
168  // Read LED events from the uinput device
169  struct input_event event;
170  while (read(kb->uinput_kb - 1, &event, sizeof(event)) > 0) {
171  if (event.type == EV_LED && event.code < 8){
172  char which = 1 << event.code;
173  if(event.value)
174  ileds |= which;
175  else
176  ileds &= ~which;
177  }
178  // Update them if needed
179  pthread_mutex_lock(dmutex(kb));
180  if(kb->hw_ileds != ileds){
181  kb->hw_ileds = ileds;
182  kb->vtable->updateindicators(kb, 0);
183  }
184  pthread_mutex_unlock(dmutex(kb));
185  }
186  return 0;
187 }
188 
190  // Initialize LEDs to all off
191  kb->hw_ileds = kb->hw_ileds_old = kb->ileds = 0;
192  // Create and detach thread to read LED events
193  pthread_t thread;
194  int err = pthread_create(&thread, 0, _ledthread, kb);
195  if(err != 0)
196  return err;
197  pthread_detach(thread);
198  return 0;
199 }
200 
201 #endif
void * _ledthread(void *ctx)
Definition: input_linux.c:165
float y
Definition: main.c:66
char name[40+1]
Definition: structures.h:233
void os_keypress(usbdevice *kb, int scancode, int down)
Definition: input_linux.c:118
int uinput_kb
Definition: structures.h:189
static void isync(usbdevice *kb)
Definition: input_linux.c:107
#define ckb_err(fmt, args...)
Definition: includes.h:49
float x
Definition: main.c:66
ushort fwversion
Definition: structures.h:239
usbdevice keyboard[9]
remember all usb devices. Needed for closeusb().
Definition: device.c:10
void os_inputclose(usbdevice *kb)
Definition: input_linux.c:76
uchar hw_ileds_old
Definition: structures.h:247
Definition: keymap.h:49
uchar ileds
Definition: structures.h:247
int os_inputopen(usbdevice *kb)
os_inputopen
Definition: input_linux.c:55
#define BTN_WHEELUP
Definition: keymap.h:12
unsigned char uchar
Definition: includes.h:24
int uinput_mouse
Definition: structures.h:189
#define ckb_warn(fmt, args...)
Definition: includes.h:52
short product
Definition: structures.h:237
#define INDEX_OF(entry, array)
Definition: includes.h:27
const union devcmd * vtable
Definition: structures.h:180
int os_setupindicators(usbdevice *kb)
Definition: input_linux.c:189
uchar hw_ileds
Definition: structures.h:247
void os_mousemove(usbdevice *kb, int x, int y)
Definition: input_linux.c:143
#define SCAN_MOUSE
Definition: keymap.h:58
#define dmutex(kb)
Definition: device.h:18
short vendor
Definition: structures.h:237
int uinputopen(struct uinput_user_dev *indev, int mouse)
Definition: input_linux.c:9
#define BTN_WHEELDOWN
Definition: keymap.h:13