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)
21 err("*** POSIX ERROR *** in %s:%d [%s]: ", __FILE__, __LINE__, #x); \
31 err("*** USB ERROR *** in %s:%d [%s]: %d\n", __FILE__, __LINE__, #x, __err); \
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;
89 msg("mouse dx %d, dy %d -- x %d y %d\n", dx
, dy
, x
, y
);
94 static void transfer0x81_cb (struct libusb_transfer
*transfer
)
99 void (*key_fn
) (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
) {
150 if (transfer
->status
== LIBUSB_TRANSFER_TIMED_OUT
) {
151 if (repeat_fn
!= NULL
&& repeat_key
!= NULL
)
152 repeat_fn(repeat_key
);
155 if (transfer
->actual_length
== 8) {
156 char m
= transfer
->buffer
[0];
157 char c
= transfer
->buffer
[2];
159 if (m
== 0x00 && c
== 0x00) {
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
;
174 if (transfer
->actual_length
> 0) {
176 msg("*** unknown keycode: ");
177 for (i
=0; i
<transfer
->actual_length
; i
++)
178 msg("%02x ", transfer
->buffer
[i
] & 0xff);
182 UCHK(libusb_submit_transfer(transfer
));
185 static void transfer0x82_cb (struct libusb_transfer
*transfer
)
187 static const struct {
189 void (*key_fn
) (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
)
208 if (transfer
->status
== LIBUSB_TRANSFER_TIMED_OUT
) {
209 if (rclick_pending
== 1) {
213 if (repeat_fn
!= NULL
&& repeat_key
!= NULL
)
214 repeat_fn(repeat_key
);
217 if (transfer
->actual_length
== 5) {
218 const char keycode_up
[5] = { 0x02, 0x00, 0x00, 0x00, 0x55 };
220 if (transfer
->buffer
[0] == 0x01) {
221 if (transfer
->buffer
[1] == 0x00) {
222 char dx
= transfer
->buffer
[2];
223 char dy
= transfer
->buffer
[3];
225 if (rclick_pending
> 0) {
226 if (--rclick_pending
== 0)
230 if (transfer
->buffer
[1] == 0x01)
232 else if (transfer
->buffer
[1] == 0x02)
239 if (memcmp(transfer
->buffer
, keycode_up
, 5) == 0) {
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
;
253 msg("*** unknown keycode: ");
254 for (i
=0; i
<transfer
->actual_length
; i
++)
255 msg("%02x ", transfer
->buffer
[i
] & 0xff);
259 UCHK(libusb_submit_transfer(transfer
));
262 int main (int argc
, char **argv
)
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];
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]);
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));