Tell git to ignore generated files.
[hama_mce-eventclient.git] / hama_mce.cpp
blobad3481f33f7f080712f6bdd4efaddfabdf0f5c51
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <sys/ioctl.h>
8 #include <sys/time.h>
9 #include <fcntl.h>
10 #include <libusb-1.0/libusb.h>
12 #include "xbmcclient.h"
14 #define msg(x...) do { fprintf(stdout, x); } while (0)
15 #define err(x...) do { fprintf(stderr, x); } while (0)
17 #define PCHK(x...) \
18 do { \
19 int __err = (x); \
20 if (__err == -1) { \
21 err("*** POSIX ERROR *** in %s:%d [%s]: ", __FILE__, __LINE__, #x); \
22 perror(""); \
23 abort(); \
24 } \
25 } while (0)
27 #define UCHK(x...) \
28 do { \
29 int __err = (x); \
30 if (__err < 0) \
31 err("*** USB ERROR *** in %s:%d [%s]: %d\n", __FILE__, __LINE__, #x, __err); \
32 } while (0)
35 static CXBMCClient xbmc;
36 static int disconnected = 0;
39 static void xbmc_action (const char *action)
41 msg("send action '%s'\n", action);
42 xbmc.SendACTION(action);
45 static void xbmc_action_button (const char *btn)
47 msg("send action '%s' (button)\n", btn);
48 xbmc.SendACTION(btn, ACTION_BUTTON);
51 static void xbmc_key (const char *key)
53 msg("send key '%s'\n", key);
54 xbmc.SendButton(key, "R1", BTN_NO_REPEAT);
57 static void xbmc_key_kb (const char *key)
59 msg("send key '%s'\n", key);
60 xbmc.SendButton(key, "KB", BTN_NO_REPEAT);
63 static void emit_left_click (void)
65 xbmc_action_button("select");
68 static void emit_right_click (void)
70 xbmc_action_button("contextmenu");
73 static void emit_mouse (int dx, int dy)
75 if (dx != 0 || dy != 0) {
76 const int maxcoord = 65535;
77 static int x = maxcoord / 2;
78 static int y = maxcoord / 2;
79 x += dx * 64;
80 y += dy * 64;
81 if (x < 0)
82 x = 0;
83 if (y < 0)
84 y = 0;
85 if (x > maxcoord)
86 x = maxcoord;
87 if (y > maxcoord)
88 y = maxcoord;
89 msg("mouse dx %d, dy %d -- x %d y %d\n", dx, dy, x, y);
90 xbmc.SendMOUSE(x, y);
94 static void transfer0x81_cb (struct libusb_transfer *transfer)
96 static const struct {
97 char modifier;
98 char code;
99 void (*key_fn) (const char *key);
100 const char *key;
101 } translation_table [] = {
102 { 0x03, 0x17, xbmc_action, "XBMC.ActivateWindow(MyTV)" }, /* (yellow) TV */
103 { 0x01, 0x10, xbmc_action, "XBMC.ActivateWindow(MyMusic)" }, /* (blue) Music */
104 { 0x01, 0x0c, xbmc_action, "XBMC.ActivateWindow(MyPictures)" }, /* (green) Pictures */
105 { 0x01, 0x08, xbmc_action, "XBMC.ActivateWindow(MyVideos)" }, /* (red) Videos */
106 { 0x01, 0x12, xbmc_action_button, "AspectRatio" },
107 { 0x01, 0x0a, xbmc_action, "?" }, /**/
108 { 0x01, 0x17, xbmc_action, "?" }, /**/
109 { 0x03, 0x10, xbmc_action, "XBMC.EjectTray()" }, /* CD/DVD icon */
110 { 0x03, 0x05, xbmc_key, "reverse" }, /* Rewind */
111 { 0x03, 0x09, xbmc_key, "forward" }, /* FastForward */
112 { 0x01, 0x15, xbmc_action_button, "Queue" }, /* Record -> queue */
113 { 0x00, 0x2a, xbmc_key_kb, "escape" }, /* Back */
114 { 0x00, 0x28, xbmc_key_kb, "enter" }, /* ok -> enter */
115 { 0x00, 0x4f, xbmc_key, "right" },
116 { 0x00, 0x50, xbmc_key, "left" },
117 { 0x00, 0x51, xbmc_key, "down" },
118 { 0x00, 0x52, xbmc_key, "up" },
119 { 0x00, 0x4b, xbmc_key, "pageplus" }, /* ChannelUp -> PageUp*/
120 { 0x00, 0x4e, xbmc_key, "pageminus" }, /* ChannelDown -> PageUp */
121 { 0x0c, 0x28, xbmc_action, "XBMC.ActivateWindow(Home)" }, /* Start -> Home */
122 { 0x00, 0x59, xbmc_key, "one" },
123 { 0x00, 0x5a, xbmc_key, "two" },
124 { 0x00, 0x5b, xbmc_key, "three" },
125 { 0x00, 0x5c, xbmc_key, "four" },
126 { 0x00, 0x5d, xbmc_key, "five" },
127 { 0x00, 0x5e, xbmc_key, "six" },
128 { 0x00, 0x5f, xbmc_key, "seven" },
129 { 0x00, 0x60, xbmc_key, "eight" },
130 { 0x00, 0x61, xbmc_key, "nine" },
131 { 0x00, 0x62, xbmc_key, "zero" },
132 { 0x00, 0x55, xbmc_key, "star" },
133 { 0x04, 0x5d, xbmc_key, "hash" },
134 { 0x00, 0x29, xbmc_key, "clear" }, /* clear -> backspace */
135 { 0x04, 0x3d, xbmc_key, "back" }, /* close -> back */
136 { 0x04, 0x5b, NULL, NULL }, /* discard */
137 { 0x00, 0x53, NULL, NULL }, /* discard */
138 { 0x0c, 0x00, NULL, NULL }, /* discard */
139 { 0x08, 0x00, NULL, NULL }, /* discard */
140 { 0x04, 0x00, NULL, NULL }, /* discard */
141 { 0x03, 0x00, NULL, NULL }, /* discard */
142 { 0x01, 0x00, NULL, NULL }, /* discard */
144 static void (*repeat_fn) (const char *key) = NULL;
145 static const char *repeat_key = NULL;
146 if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) {
147 disconnected = 1;
148 return;
150 if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) {
151 if (repeat_fn != NULL && repeat_key != NULL)
152 repeat_fn(repeat_key);
153 goto done;
155 if (transfer->actual_length == 8) {
156 char m = transfer->buffer[0];
157 char c = transfer->buffer[2];
158 int i;
159 if (m == 0x00 && c == 0x00) {
160 repeat_fn = NULL;
161 repeat_key = NULL;
162 goto done;
164 for (i=0; i<sizeof(translation_table)/sizeof(translation_table[0]); i++) {
165 if (translation_table[i].modifier == m && translation_table[i].code == c) {
166 if (translation_table[i].key_fn != NULL)
167 translation_table[i].key_fn(translation_table[i].key);
168 repeat_fn = translation_table[i].key_fn;
169 repeat_key = translation_table[i].key;
170 goto done;
174 if (transfer->actual_length > 0) {
175 int i;
176 msg("*** unknown keycode: ");
177 for (i=0; i<transfer->actual_length; i++)
178 msg("%02x ", transfer->buffer[i] & 0xff);
179 msg("\n");
181 done:
182 UCHK(libusb_submit_transfer(transfer));
185 static void transfer0x82_cb (struct libusb_transfer *transfer)
187 static const struct {
188 char code [5];
189 void (*key_fn) (const char *key);
190 const char *key;
191 } translation_table [] = {
192 { { 0x03, 0x00, 0x55, 0x55, 0x55 }, xbmc_key, "power" },
193 { { 0x02, 0x02, 0x00, 0x00, 0x55 }, xbmc_key, "title" },
194 { { 0x02, 0x80, 0x00, 0x00, 0x55 }, xbmc_key, "skipminus" },
195 { { 0x02, 0x00, 0x02, 0x00, 0x55 }, xbmc_key, "skipplus" },
196 { { 0x02, 0x00, 0x00, 0x01, 0x55 }, xbmc_key, "stop" },
197 { { 0x02, 0x00, 0x00, 0x02, 0x55 }, xbmc_key, "pause" },
198 { { 0x02, 0x00, 0x01, 0x00, 0x55 }, xbmc_key, "mute" },
199 { { 0x02, 0x10, 0x00, 0x00, 0x55 }, xbmc_key, "volumeplus" },
200 { { 0x02, 0x00, 0x10, 0x00, 0x55 }, xbmc_key, "volumeminus" },
201 { { 0x03, 0x02, 0x55, 0x55, 0x55 }, NULL, NULL }, /* discard */
203 static void (*repeat_fn) (const char *key) = NULL;
204 static const char *repeat_key = NULL;
205 static int rclick_pending = 0;
206 if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE)
207 disconnected = 1;
208 if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) {
209 if (rclick_pending == 1) {
210 rclick_pending = 0;
211 xbmc_key("info");
213 if (repeat_fn != NULL && repeat_key != NULL)
214 repeat_fn(repeat_key);
215 goto done;
217 if (transfer->actual_length == 5) {
218 const char keycode_up [5] = { 0x02, 0x00, 0x00, 0x00, 0x55 };
219 int i;
220 if (transfer->buffer[0] == 0x01) {
221 if (transfer->buffer[1] == 0x00) {
222 char dx = transfer->buffer[2];
223 char dy = transfer->buffer[3];
224 emit_mouse(dx, dy);
225 if (rclick_pending > 0) {
226 if (--rclick_pending == 0)
227 emit_right_click();
229 } else {
230 if (transfer->buffer[1] == 0x01)
231 emit_left_click();
232 else if (transfer->buffer[1] == 0x02)
233 rclick_pending = 2;
235 repeat_fn = NULL;
236 repeat_key = NULL;
237 goto done;
239 if (memcmp(transfer->buffer, keycode_up, 5) == 0) {
240 repeat_fn = NULL;
241 repeat_key = NULL;
242 goto done;
244 for (i=0; i<sizeof(translation_table)/sizeof(translation_table[0]); i++) {
245 if (memcmp(translation_table[i].code, transfer->buffer, 5) == 0) {
246 if (translation_table[i].key_fn != NULL)
247 translation_table[i].key_fn(translation_table[i].key);
248 repeat_fn = translation_table[i].key_fn;
249 repeat_key = translation_table[i].key;
250 goto done;
253 msg("*** unknown keycode: ");
254 for (i=0; i<transfer->actual_length; i++)
255 msg("%02x ", transfer->buffer[i] & 0xff);
256 msg("\n");
258 done:
259 UCHK(libusb_submit_transfer(transfer));
262 int main (int argc, char **argv)
264 libusb_context *ctx;
265 libusb_device_handle *dev;
266 struct libusb_transfer *transfer0x81 = libusb_alloc_transfer(0);
267 struct libusb_transfer *transfer0x82 = libusb_alloc_transfer(0);
268 unsigned char buf0x81 [8];
269 unsigned char buf0x82 [5];
270 int i;
272 UCHK(libusb_init(&ctx));
274 if (!(dev = libusb_open_device_with_vid_pid(ctx, 0x05a4, 0x9881))) {
275 err("%s: No HAMA MCE remote control found.\n", argv[0]);
276 return -1;
279 if (libusb_kernel_driver_active(dev, 0))
280 UCHK(libusb_detach_kernel_driver(dev, 0));
281 if (libusb_kernel_driver_active(dev, 1))
282 UCHK(libusb_detach_kernel_driver(dev, 1));
283 UCHK(libusb_claim_interface(dev, 0));
284 UCHK(libusb_claim_interface(dev, 1));
286 libusb_fill_interrupt_transfer(transfer0x81, dev, 0x81, buf0x81, sizeof(buf0x81), transfer0x81_cb, NULL, 215);
287 UCHK(libusb_submit_transfer(transfer0x81));
289 libusb_fill_interrupt_transfer(transfer0x82, dev, 0x82, buf0x82, sizeof(buf0x82), transfer0x82_cb, NULL, 200);
290 UCHK(libusb_submit_transfer(transfer0x82));
292 while (!disconnected)
293 UCHK(libusb_handle_events(ctx));
295 libusb_free_transfer(transfer0x81);
296 libusb_free_transfer(transfer0x82);
298 /* not needed, if we arrive here, the device has been disconnected.
299 UCHK(libusb_release_interface(dev, 0));
300 UCHK(libusb_release_interface(dev, 1));
301 UCHK(libusb_attach_kernel_driver(dev, 0));
302 UCHK(libusb_attach_kernel_driver(dev, 1));
304 libusb_close(dev);
305 libusb_exit(ctx);
307 return 0;