gyruby 0.0.2 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/extconf.rb +1 -1
- data/ext/gyruby_ext.c +239 -253
- data/lib/gyruby/mplayer_controller.rb +88 -0
- data/lib/gyruby/remote.rb +92 -0
- data/lib/gyruby.rb +6 -1
- metadata +5 -3
data/ext/extconf.rb
CHANGED
@@ -29,7 +29,7 @@ unless find_executable("pkg-config")
|
|
29
29
|
end
|
30
30
|
|
31
31
|
$CFLAGS += " -std=c99 -Wall -I. " + `pkg-config --cflags glib-2.0`.strip
|
32
|
-
$LIBS += " " + `pkg-config --libs
|
32
|
+
$LIBS += " " + `pkg-config --libs gthread-2.0`
|
33
33
|
|
34
34
|
unless have_library('glib-2.0')
|
35
35
|
crash "libglib-2.0 needed"
|
data/ext/gyruby_ext.c
CHANGED
@@ -19,7 +19,9 @@
|
|
19
19
|
#include <stdio.h>
|
20
20
|
#include "ruby.h"
|
21
21
|
#include <glib.h>
|
22
|
+
#include <stdlib.h>
|
22
23
|
#include <X11/Xlib.h>
|
24
|
+
#include <errno.h>
|
23
25
|
|
24
26
|
#define RB_REMOTE(c_remote_pointer,klass) (c_remote_pointer->rb_remote = (Data_Wrap_Struct(klass, c_remote_mark, c_remote_free, (c_remote_pointer))))
|
25
27
|
#define C_REMOTE(rb_remote,c_remote_pointer) Data_Get_Struct((rb_remote), c_remote, (c_remote_pointer))
|
@@ -27,15 +29,37 @@
|
|
27
29
|
#define PACKET_SIZE 6
|
28
30
|
#define BUFFER_UNIT 1024
|
29
31
|
|
32
|
+
extern gint errno;
|
33
|
+
extern gint sys_nerr;
|
34
|
+
extern const char *sys_errlist[];
|
35
|
+
|
30
36
|
typedef struct {
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
+
/*
|
38
|
+
* The ruby representation of this object.
|
39
|
+
*/
|
40
|
+
VALUE rb_remote;
|
41
|
+
|
42
|
+
/*
|
43
|
+
* Mouse capture runtime data.
|
44
|
+
*/
|
45
|
+
Display *display;
|
46
|
+
|
47
|
+
/*
|
48
|
+
* USB capture runtime data.
|
49
|
+
*/
|
50
|
+
usb_dev_handle *usb_handle;
|
51
|
+
GAsyncQueue *usb_event_queue;
|
52
|
+
gboolean run_usb_thread;
|
53
|
+
GThread *usb_thread;
|
37
54
|
} c_remote;
|
38
55
|
|
56
|
+
typedef struct {
|
57
|
+
gint x;
|
58
|
+
gint y;
|
59
|
+
gint xmax;
|
60
|
+
gint ymax;
|
61
|
+
} mouse_event;
|
62
|
+
|
39
63
|
typedef VALUE
|
40
64
|
(*gyration_data_handler)(gint result, gchar *data, gpointer user_data);
|
41
65
|
|
@@ -44,6 +68,15 @@ typedef VALUE
|
|
44
68
|
|
45
69
|
static VALUE rb_remote;
|
46
70
|
|
71
|
+
static const gchar*
|
72
|
+
errmsg() {
|
73
|
+
if (errno < sys_nerr) {
|
74
|
+
return sys_errlist[errno];
|
75
|
+
} else {
|
76
|
+
return "UNKNOWN ERROR";
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
47
80
|
static gchar*
|
48
81
|
c_remote_inspect(c_remote *remote) {
|
49
82
|
gchar *buffer = g_new(gchar, BUFFER_UNIT);
|
@@ -54,29 +87,37 @@ c_remote_inspect(c_remote *remote) {
|
|
54
87
|
}
|
55
88
|
|
56
89
|
static void
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
fprintf(stderr, "Unable to close usb handle! Freeing %s anyway.", buffer);
|
63
|
-
free(buffer);
|
64
|
-
}
|
65
|
-
}
|
66
|
-
free(remote);
|
90
|
+
unclaim_device_handle(usb_dev_handle *handle) {
|
91
|
+
if (usb_release_interface(handle, 1) < 0)
|
92
|
+
rb_raise(rb_eRuntimeError, "Failed releasing device: %s", errmsg());
|
93
|
+
if (usb_close(handle) < 0)
|
94
|
+
rb_raise(rb_eRuntimeError, "Failed closing device: %s", errmsg());
|
67
95
|
}
|
68
96
|
|
69
97
|
static void
|
70
|
-
|
71
|
-
|
72
|
-
|
98
|
+
c_remote_unclaim_device(c_remote *remote) {
|
99
|
+
remote->run_usb_thread = FALSE;
|
100
|
+
if (g_thread_self() != remote->usb_thread)
|
101
|
+
g_thread_join(remote->usb_thread);
|
102
|
+
unclaim_device_handle(remote->usb_handle);
|
103
|
+
remote->usb_handle = NULL;
|
104
|
+
remote->usb_thread = NULL;
|
105
|
+
g_async_queue_unref(remote->usb_event_queue);
|
73
106
|
}
|
74
107
|
|
75
108
|
static void
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
109
|
+
ungrab_mouse(Display *display) {
|
110
|
+
XUngrabPointer(display, CurrentTime);
|
111
|
+
XCloseDisplay(display);
|
112
|
+
}
|
113
|
+
|
114
|
+
static void
|
115
|
+
c_remote_free(c_remote *remote) {
|
116
|
+
if (remote->display != NULL)
|
117
|
+
ungrab_mouse(remote->display);
|
118
|
+
if (remote->usb_handle != NULL)
|
119
|
+
c_remote_unclaim_device(remote);
|
120
|
+
free(remote);
|
80
121
|
}
|
81
122
|
|
82
123
|
static VALUE
|
@@ -91,29 +132,19 @@ rb_remote_inspect(VALUE self) {
|
|
91
132
|
return rval;
|
92
133
|
}
|
93
134
|
|
94
|
-
static
|
95
|
-
|
96
|
-
gchar *subscription = (gchar *) key;
|
97
|
-
guint hash = 5381;
|
98
|
-
|
99
|
-
for (int i = 0; i < (sizeof(gint) / sizeof(gchar)) + PACKET_SIZE; i++)
|
100
|
-
hash = ((hash << 5) + hash) + subscription[i]; /* hash * 33 + subscription[i] */
|
101
|
-
|
102
|
-
return hash;
|
103
|
-
}
|
104
|
-
|
105
|
-
static gboolean
|
106
|
-
subscription_equal(gconstpointer a, gconstpointer b) {
|
107
|
-
return memcmp(a, b, sizeof(gchar) * ((sizeof(gint) / sizeof(gchar)) + PACKET_SIZE)) == 0;
|
135
|
+
static void
|
136
|
+
c_remote_mark(c_remote *remote) {
|
108
137
|
}
|
109
138
|
|
110
139
|
static VALUE
|
111
140
|
rb_remote_alloc(VALUE class) {
|
112
141
|
c_remote *remote = ALLOC(c_remote);
|
113
|
-
remote->usb_handle = NULL;
|
114
|
-
remote->subscriptions = g_hash_table_new_full(subscription_hash, subscription_equal, free, free);
|
115
142
|
remote->display = NULL;
|
116
|
-
|
143
|
+
|
144
|
+
remote->usb_handle = NULL;
|
145
|
+
remote->usb_event_queue = NULL;
|
146
|
+
remote->run_usb_thread = FALSE;
|
147
|
+
remote->usb_thread = NULL;
|
117
148
|
return RB_REMOTE(remote, class);
|
118
149
|
}
|
119
150
|
|
@@ -124,56 +155,96 @@ rb_gyruby_set_debug(VALUE self, VALUE arg) {
|
|
124
155
|
return arg;
|
125
156
|
}
|
126
157
|
|
127
|
-
static
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
158
|
+
static VALUE
|
159
|
+
rb_remote_unclaim_device(VALUE self) {
|
160
|
+
c_remote *this;
|
161
|
+
C_REMOTE(self, this);
|
162
|
+
if (this->usb_handle == NULL) {
|
163
|
+
return Qfalse;
|
164
|
+
} else {
|
165
|
+
c_remote_unclaim_device(this);
|
166
|
+
return Qtrue;
|
167
|
+
}
|
168
|
+
}
|
169
|
+
|
170
|
+
static usb_dev_handle*
|
171
|
+
fetch_device_handle() {
|
172
|
+
struct usb_bus *busses = usb_get_busses();
|
173
|
+
for (struct usb_bus *bus = busses; bus; bus = bus->next) {
|
174
|
+
for (struct usb_device *dev = bus->devices; dev; dev = dev->next) {
|
175
|
+
if (dev->descriptor.idVendor == 0x0c16 &&
|
176
|
+
dev->descriptor.idProduct == 0x0006) {
|
177
|
+
return usb_open(dev);
|
137
178
|
}
|
138
179
|
}
|
139
180
|
}
|
181
|
+
return NULL;
|
140
182
|
}
|
141
183
|
|
142
|
-
static
|
143
|
-
|
144
|
-
|
145
|
-
if (
|
146
|
-
|
184
|
+
static usb_dev_handle*
|
185
|
+
claim_device_handle() {
|
186
|
+
usb_dev_handle *handle = fetch_device_handle();
|
187
|
+
if (handle == NULL) {
|
188
|
+
rb_raise(rb_eRuntimeError, "Failed finding device. Do you have permission to list it? Is it plugged in?");
|
189
|
+
} else {
|
190
|
+
if (usb_claim_interface(handle, 1) < 0) {
|
147
191
|
char dname[32];
|
148
|
-
if (usb_get_driver_np(
|
149
|
-
if (usb_detach_kernel_driver_np(
|
150
|
-
rb_raise(rb_eRuntimeError,
|
192
|
+
if (usb_get_driver_np(handle, 1, dname, 31) == 0) {
|
193
|
+
if (usb_detach_kernel_driver_np(handle, 1) < 0) {
|
194
|
+
rb_raise(rb_eRuntimeError,
|
195
|
+
"Failed claiming device. Also failed detaching kernel driver for device: %s", errmsg());
|
151
196
|
} else {
|
152
|
-
if (usb_claim_interface(
|
153
|
-
rb_raise(rb_eRuntimeError,
|
197
|
+
if (usb_claim_interface(handle, 1) < 0) {
|
198
|
+
rb_raise(rb_eRuntimeError,
|
199
|
+
"Failed claiming device. Succeded in detaching kernel driver for device. But still failed claiming device: %s", errmsg());
|
154
200
|
}
|
155
201
|
}
|
156
202
|
} else {
|
157
|
-
rb_raise(rb_eRuntimeError,
|
203
|
+
rb_raise(rb_eRuntimeError,
|
204
|
+
"Failed claiming device. Also failed getting kernel driver for device: %s", errmsg());
|
158
205
|
}
|
159
206
|
}
|
160
207
|
}
|
208
|
+
return handle;
|
209
|
+
}
|
210
|
+
|
211
|
+
static gpointer
|
212
|
+
read_usb(gpointer arg) {
|
213
|
+
c_remote *remote = (c_remote *) arg;
|
214
|
+
gchar inpacket[PACKET_SIZE];
|
215
|
+
while (remote->run_usb_thread) {
|
216
|
+
gint result = usb_interrupt_read(remote->usb_handle,
|
217
|
+
0x82,
|
218
|
+
inpacket,
|
219
|
+
PACKET_SIZE,
|
220
|
+
50);
|
221
|
+
if (result < 0 && result != -110) {
|
222
|
+
fprintf(stderr, "Weird error: The result code from usb_interrupt_read was: %i\n", result);
|
223
|
+
c_remote_unclaim_device(remote);
|
224
|
+
} else if (result != -110) {
|
225
|
+
gchar *packet_copy = g_new(gchar, PACKET_SIZE);
|
226
|
+
memcpy(packet_copy, inpacket, sizeof(gchar) * PACKET_SIZE);
|
227
|
+
g_async_queue_push(remote->usb_event_queue, packet_copy);
|
228
|
+
}
|
229
|
+
}
|
230
|
+
return NULL;
|
161
231
|
}
|
162
232
|
|
233
|
+
|
163
234
|
static VALUE
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
235
|
+
rb_remote_claim_device(VALUE self) {
|
236
|
+
c_remote *this;
|
237
|
+
C_REMOTE(self, this);
|
238
|
+
if (this->usb_handle == NULL) {
|
239
|
+
this->usb_handle = claim_device_handle();
|
240
|
+
|
241
|
+
this->usb_event_queue = g_async_queue_new_full(free);
|
242
|
+
this->run_usb_thread = TRUE;
|
243
|
+
this->usb_thread = g_thread_create(read_usb, this, TRUE, NULL);
|
244
|
+
return Qtrue;
|
245
|
+
} else {
|
246
|
+
return Qfalse;
|
175
247
|
}
|
176
|
-
return handler(result, inpacket, user_data);
|
177
248
|
}
|
178
249
|
|
179
250
|
static Bool
|
@@ -181,222 +252,135 @@ true_predicate(Display *display, XEvent *event, XPointer arg) {
|
|
181
252
|
return True;
|
182
253
|
}
|
183
254
|
|
184
|
-
static
|
185
|
-
|
255
|
+
static mouse_event*
|
256
|
+
fetch_mouse_event(Display *display) {
|
186
257
|
XEvent event;
|
187
|
-
if (XCheckIfEvent(
|
258
|
+
if (XCheckIfEvent(display, &event, true_predicate, NULL) == True &&
|
188
259
|
event.xmotion.same_screen == True) {
|
189
|
-
|
190
|
-
|
260
|
+
mouse_event *rval = ALLOC(mouse_event);
|
261
|
+
Screen *screen = XDefaultScreenOfDisplay(display);
|
262
|
+
rval->x = event.xmotion.x_root;
|
263
|
+
rval->y = event.xmotion.y_root;
|
264
|
+
rval->xmax = WidthOfScreen(screen);
|
265
|
+
rval->ymax = HeightOfScreen(screen);
|
266
|
+
return rval;
|
191
267
|
} else {
|
192
|
-
return
|
268
|
+
return NULL;
|
193
269
|
}
|
194
270
|
}
|
195
271
|
|
196
|
-
static
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
272
|
+
static VALUE
|
273
|
+
rb_remote_fetch_mouse_event(VALUE self) {
|
274
|
+
c_remote *this;
|
275
|
+
C_REMOTE(self, this);
|
276
|
+
if (this->display == NULL) {
|
277
|
+
rb_raise(rb_eRuntimeError,
|
278
|
+
"You can't fetch mouse events from a %s that hasn't grabbed the pointer.",
|
279
|
+
rb_obj_classname(self));
|
280
|
+
} else {
|
281
|
+
mouse_event *event = fetch_mouse_event(this->display);
|
282
|
+
if (event == NULL) {
|
283
|
+
return Qnil;
|
284
|
+
} else {
|
285
|
+
VALUE rval = rb_hash_new();
|
286
|
+
rb_hash_aset(rval, ID2SYM(rb_intern("x")), INT2NUM(event->x));
|
287
|
+
rb_hash_aset(rval, ID2SYM(rb_intern("y")), INT2NUM(event->y));
|
288
|
+
rb_hash_aset(rval, ID2SYM(rb_intern("xmax")), INT2NUM(event->xmax));
|
289
|
+
rb_hash_aset(rval, ID2SYM(rb_intern("ymax")), INT2NUM(event->ymax));
|
290
|
+
free(event);
|
291
|
+
return rval;
|
211
292
|
}
|
212
293
|
}
|
213
294
|
}
|
214
295
|
|
215
296
|
static VALUE
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
if (
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
remote->display_name != Qnil &&
|
231
|
-
(rval = c_remote_handle_grab_data(remote, grab_handler, user_data)) != Qnil)
|
297
|
+
rb_remote_fetch_usb_event(VALUE self) {
|
298
|
+
c_remote *this;
|
299
|
+
C_REMOTE(self, this);
|
300
|
+
if (this->usb_event_queue == NULL) {
|
301
|
+
rb_raise(rb_eRuntimeError,
|
302
|
+
"You can't fetch usb events from a %s that hasn't claimed the device.",
|
303
|
+
rb_obj_classname(self));
|
304
|
+
} else {
|
305
|
+
gpointer next_event = g_async_queue_try_pop(this->usb_event_queue);
|
306
|
+
if (next_event == NULL) {
|
307
|
+
return Qnil;
|
308
|
+
} else {
|
309
|
+
VALUE rval = rb_str_new((gchar *) next_event, 6);
|
310
|
+
free(next_event);
|
232
311
|
return rval;
|
233
|
-
|
312
|
+
}
|
234
313
|
}
|
235
|
-
return rval;
|
236
314
|
}
|
237
315
|
|
238
|
-
static
|
239
|
-
|
240
|
-
|
241
|
-
if (
|
242
|
-
|
243
|
-
|
244
|
-
|
316
|
+
static Display*
|
317
|
+
grab_mouse() {
|
318
|
+
Display *display = XOpenDisplay(NULL);
|
319
|
+
if (XGrabPointer(display,
|
320
|
+
XDefaultRootWindow(display),
|
321
|
+
False,
|
322
|
+
PointerMotionMask,
|
323
|
+
GrabModeAsync,
|
324
|
+
GrabModeAsync,
|
325
|
+
None,
|
326
|
+
None,
|
327
|
+
CurrentTime) != GrabSuccess) {
|
328
|
+
rb_raise(rb_eRuntimeError, "Failed grabbing the pointer for the root window!");
|
245
329
|
}
|
246
|
-
return
|
247
|
-
}
|
248
|
-
|
249
|
-
static VALUE
|
250
|
-
c_remote_handle_data_until(c_remote *remote, gyration_data_handler gyration_handler, grab_data_handler grab_handler, gpointer user_data) {
|
251
|
-
VALUE rval;
|
252
|
-
gpointer loop_args[4] = { remote, gyration_handler, grab_handler, user_data };
|
253
|
-
c_remote_claim_device(remote);
|
254
|
-
c_remote_grab_pointer(remote);
|
255
|
-
rval = rb_ensure(c_remote_handle_data_loop, GPOINTER_TO_INT(loop_args), c_remote_release_pointer, GPOINTER_TO_INT(remote));
|
256
|
-
return rval;
|
257
|
-
}
|
258
|
-
|
259
|
-
static gchar*
|
260
|
-
subscription_from_result_and_packet(gint result, gchar *packet) {
|
261
|
-
gchar *subscription = malloc(sizeof(gint) + (sizeof(gchar) * PACKET_SIZE));
|
262
|
-
memcpy(subscription,
|
263
|
-
&result,
|
264
|
-
sizeof(gint));
|
265
|
-
memcpy(subscription + (sizeof(gint) / sizeof(gchar)),
|
266
|
-
packet,
|
267
|
-
sizeof(gchar) * 6);
|
268
|
-
return subscription;
|
269
|
-
}
|
270
|
-
|
271
|
-
static VALUE
|
272
|
-
c_remote_yield_gyration_data(gint result, gchar *packet, gpointer user_data) {
|
273
|
-
VALUE result_value = INT2NUM(result);
|
274
|
-
VALUE result_string = rb_str_new(packet, PACKET_SIZE);
|
275
|
-
return rb_yield_values(2, result_value, result_string);
|
276
|
-
}
|
277
|
-
|
278
|
-
static VALUE
|
279
|
-
c_remote_call_grab_handler(gint x, gint y, gint maxx, gint maxy, gpointer user_data) {
|
280
|
-
c_remote *remote = (c_remote *) user_data;
|
281
|
-
return rb_funcall(remote->rb_remote,
|
282
|
-
remote->grab_callback,
|
283
|
-
4,
|
284
|
-
INT2NUM(x),
|
285
|
-
INT2NUM(y),
|
286
|
-
INT2NUM(maxx),
|
287
|
-
INT2NUM(maxy));
|
288
|
-
}
|
289
|
-
|
290
|
-
static VALUE
|
291
|
-
c_remote_call_subscription(gint result, gchar *packet, gpointer user_data) {
|
292
|
-
gchar *subscription = subscription_from_result_and_packet(result, packet);
|
293
|
-
c_remote *remote = (c_remote *) user_data;
|
294
|
-
ID *callback;
|
295
|
-
if ((callback = g_hash_table_lookup(remote->subscriptions, subscription)) != NULL) {
|
296
|
-
return rb_funcall(remote->rb_remote,
|
297
|
-
*callback,
|
298
|
-
2,
|
299
|
-
INT2NUM(result),
|
300
|
-
rb_str_new(packet, PACKET_SIZE));
|
301
|
-
} else {
|
302
|
-
return Qnil;
|
303
|
-
}
|
304
|
-
}
|
305
|
-
|
306
|
-
static VALUE
|
307
|
-
rb_remote_listen(VALUE self) {
|
308
|
-
c_remote *this;
|
309
|
-
C_REMOTE(self, this);
|
310
|
-
return c_remote_handle_data_until(this, c_remote_call_subscription, c_remote_call_grab_handler, this);
|
330
|
+
return display;
|
311
331
|
}
|
312
332
|
|
313
333
|
static VALUE
|
314
|
-
|
334
|
+
rb_remote_ungrab_mouse(VALUE self) {
|
315
335
|
c_remote *this;
|
316
336
|
C_REMOTE(self, this);
|
317
|
-
|
337
|
+
if (this->display == NULL) {
|
338
|
+
return Qfalse;
|
339
|
+
} else {
|
340
|
+
ungrab_mouse(this->display);
|
341
|
+
this->display = NULL;
|
342
|
+
return Qtrue;
|
343
|
+
}
|
318
344
|
}
|
319
345
|
|
320
346
|
static VALUE
|
321
|
-
|
347
|
+
rb_remote_grab_mouse(VALUE self) {
|
322
348
|
c_remote *this;
|
323
|
-
gchar *subscription;
|
324
|
-
ID *callback_id;
|
325
|
-
Check_Type(result_value, T_FIXNUM);
|
326
|
-
Check_Type(result_string, T_STRING);
|
327
|
-
Check_Type(callback, T_SYMBOL);
|
328
349
|
C_REMOTE(self, this);
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
}
|
336
|
-
|
337
|
-
static void
|
338
|
-
g_hash_table_copy_to_rb_hash(gpointer key, gpointer value, gpointer user_data) {
|
339
|
-
VALUE *hash = (VALUE *) user_data;
|
340
|
-
gchar *subscription = (gchar *) key;
|
341
|
-
ID *callback_id = (ID *) value;
|
342
|
-
VALUE ary = rb_ary_new();
|
343
|
-
gint result;
|
344
|
-
gchar packet[PACKET_SIZE];
|
345
|
-
memcpy(&result, subscription, sizeof(gint));
|
346
|
-
memcpy(packet, subscription + (sizeof(gint) / sizeof(gchar)), sizeof(gchar) * PACKET_SIZE);
|
347
|
-
rb_ary_push(ary, INT2NUM(result));
|
348
|
-
rb_ary_push(ary, rb_str_new(packet, PACKET_SIZE));
|
349
|
-
rb_hash_aset(*hash, ID2SYM(*callback_id), ary);
|
350
|
+
if (this->display == NULL) {
|
351
|
+
this->display = grab_mouse();
|
352
|
+
return Qtrue;
|
353
|
+
} else {
|
354
|
+
return Qfalse;
|
355
|
+
}
|
350
356
|
}
|
351
357
|
|
352
358
|
static VALUE
|
353
|
-
|
359
|
+
rb_remote_get_claimed_device(VALUE self) {
|
354
360
|
c_remote *this;
|
355
|
-
VALUE rval;
|
356
361
|
C_REMOTE(self, this);
|
357
|
-
|
358
|
-
|
359
|
-
|
362
|
+
if (this->usb_handle == NULL)
|
363
|
+
return Qfalse;
|
364
|
+
else
|
365
|
+
return Qtrue;
|
360
366
|
}
|
361
367
|
|
362
368
|
static VALUE
|
363
|
-
|
369
|
+
rb_remote_get_grabbed_mouse(VALUE self) {
|
364
370
|
c_remote *this;
|
365
|
-
VALUE rval;
|
366
371
|
C_REMOTE(self, this);
|
367
372
|
if (this->display == NULL)
|
368
|
-
return
|
369
|
-
|
370
|
-
|
371
|
-
rb_ary_push(rval, ID2SYM(this->grab_callback));
|
372
|
-
return rval;
|
373
|
-
}
|
374
|
-
|
375
|
-
static VALUE
|
376
|
-
rb_remote_grab(VALUE self, VALUE display_name_value, VALUE callback) {
|
377
|
-
c_remote *this;
|
378
|
-
Check_Type(display_name_value, T_STRING);
|
379
|
-
Check_Type(callback, T_SYMBOL);
|
380
|
-
C_REMOTE(self, this);
|
381
|
-
this->grab_callback = rb_to_id(callback);
|
382
|
-
this->display_name = display_name_value;
|
383
|
-
return display_name_value;
|
384
|
-
}
|
385
|
-
|
386
|
-
static VALUE
|
387
|
-
rb_remote_release(VALUE self) {
|
388
|
-
c_remote *this;
|
389
|
-
C_REMOTE(self, this);
|
390
|
-
if (this->display_name == Qnil)
|
391
|
-
rb_raise(rb_eRuntimeError, "You can't release a %s that isn't grabbed.", rb_obj_classname(self));
|
392
|
-
this->display_name = Qnil;
|
393
|
-
return self;
|
373
|
+
return Qfalse;
|
374
|
+
else
|
375
|
+
return Qtrue;
|
394
376
|
}
|
395
377
|
|
396
378
|
#ifdef __cplusplus
|
397
379
|
extern "C" {
|
398
380
|
#endif
|
399
381
|
void Init_gyruby_ext() {
|
382
|
+
g_thread_init(NULL);
|
383
|
+
|
400
384
|
usb_init();
|
401
385
|
usb_find_busses();
|
402
386
|
usb_find_devices();
|
@@ -406,15 +390,17 @@ extern "C" {
|
|
406
390
|
rb_remote = rb_define_class_under(rb_gyruby,
|
407
391
|
"Remote",
|
408
392
|
rb_cObject);
|
393
|
+
|
409
394
|
rb_define_alloc_func(rb_remote, rb_remote_alloc);
|
410
|
-
rb_define_method(rb_remote, "record", rb_remote_record, 0);
|
411
|
-
rb_define_method(rb_remote, "subscribe", rb_remote_subscribe, 3);
|
412
395
|
rb_define_method(rb_remote, "inspect", rb_remote_inspect, 0);
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
396
|
+
rb_define_private_method(rb_remote, "grab_mouse", rb_remote_grab_mouse, 0);
|
397
|
+
rb_define_private_method(rb_remote, "ungrab_mouse", rb_remote_ungrab_mouse, 0);
|
398
|
+
rb_define_private_method(rb_remote, "claim_device", rb_remote_claim_device, 0);
|
399
|
+
rb_define_private_method(rb_remote, "unclaim_device", rb_remote_unclaim_device, 0);
|
400
|
+
rb_define_private_method(rb_remote, "fetch_usb_event", rb_remote_fetch_usb_event, 0);
|
401
|
+
rb_define_private_method(rb_remote, "fetch_mouse_event", rb_remote_fetch_mouse_event, 0);
|
402
|
+
rb_define_private_method(rb_remote, "claimed_device?", rb_remote_get_claimed_device, 0);
|
403
|
+
rb_define_private_method(rb_remote, "grabbed_mouse?", rb_remote_get_grabbed_mouse, 0);
|
418
404
|
}
|
419
405
|
#ifdef __cplusplus
|
420
406
|
}
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# gyruby - a ruby binding for the Gyration FiireChief remote control for LinuxMCE
|
2
|
+
# Copyright (C) 2008 Martin Kihlgren <zond at troja dot ath dot cx>
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or
|
5
|
+
# modify it under the terms of the GNU General Public License
|
6
|
+
# as published by the Free Software Foundation; either version 2
|
7
|
+
# of the License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program; if not, write to the Free Software
|
16
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
17
|
+
|
18
|
+
require 'pathname'
|
19
|
+
|
20
|
+
class MplayerController < Gyruby::Remote
|
21
|
+
|
22
|
+
def initialize(user)
|
23
|
+
super()
|
24
|
+
subscribe("\b%\377\351\000\000") do |s|
|
25
|
+
volume_up
|
26
|
+
end
|
27
|
+
subscribe("\b%\377\352\000\000") do |s|
|
28
|
+
volume_down
|
29
|
+
end
|
30
|
+
subscribe("\b%\377\234\000\000") do |s|
|
31
|
+
osd_up
|
32
|
+
end
|
33
|
+
subscribe("\b%\377\235\000\000") do |s|
|
34
|
+
osd_down
|
35
|
+
end
|
36
|
+
subscribe("\b%\377\313\000\000", "\b%\377\000\000\000") do |key, options|
|
37
|
+
seek(options[:x].to_f/ options[:xmax].to_f)
|
38
|
+
end
|
39
|
+
@osd = 0
|
40
|
+
@user = user
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def send_command(cmd)
|
46
|
+
ctrl_path = Pathname.new(File.join("/home", @user, ".mplayer", "fifo"))
|
47
|
+
ctrl_path.open("a") do |ctrl|
|
48
|
+
ctrl.puts(cmd)
|
49
|
+
end if ctrl_path.exist? && mplayer_running?
|
50
|
+
end
|
51
|
+
|
52
|
+
def seek(f)
|
53
|
+
puts f.inspect
|
54
|
+
send_command("seek #{f * 100} 1")
|
55
|
+
end
|
56
|
+
|
57
|
+
def osd_up
|
58
|
+
@osd += 1 if @osd < 3
|
59
|
+
send_command("osd #{@osd}")
|
60
|
+
end
|
61
|
+
|
62
|
+
def osd_down
|
63
|
+
@osd -= 1 if @osd > 0
|
64
|
+
send_command("osd #{@osd}")
|
65
|
+
end
|
66
|
+
|
67
|
+
def volume_up
|
68
|
+
send_command("volume 10")
|
69
|
+
end
|
70
|
+
|
71
|
+
def volume_down
|
72
|
+
send_command("volume -10")
|
73
|
+
end
|
74
|
+
|
75
|
+
def mplayer_running?
|
76
|
+
pgrep_pid = fork do
|
77
|
+
STDOUT.reopen(open("/dev/null", "w"))
|
78
|
+
args = ["/usr/bin/env",
|
79
|
+
"pgrep",
|
80
|
+
"-U", @user,
|
81
|
+
"mplayer"]
|
82
|
+
exec(*args)
|
83
|
+
end
|
84
|
+
pid, status = Process.wait2(pgrep_pid)
|
85
|
+
status.exitstatus == 0
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# gyruby - a ruby binding for the Gyration FiireChief remote control for LinuxMCE
|
2
|
+
# Copyright (C) 2008 Martin Kihlgren <zond at troja dot ath dot cx>
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or
|
5
|
+
# modify it under the terms of the GNU General Public License
|
6
|
+
# as published by the Free Software Foundation; either version 2
|
7
|
+
# of the License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program; if not, write to the Free Software
|
16
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
17
|
+
|
18
|
+
module Gyruby
|
19
|
+
|
20
|
+
class Remote
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@subscribed_buttons = {}
|
24
|
+
@pressed_buttons = {}
|
25
|
+
@mouse_buttons = {}
|
26
|
+
@listening = false
|
27
|
+
end
|
28
|
+
|
29
|
+
def subscribe(button, release = false, frequency = 10, &block)
|
30
|
+
if release
|
31
|
+
@mouse_buttons[button] = {
|
32
|
+
:action => :press,
|
33
|
+
:block => block,
|
34
|
+
:frequency => frequency,
|
35
|
+
:last => nil
|
36
|
+
}
|
37
|
+
@mouse_buttons[release] = {:action => :release, :press => button}
|
38
|
+
else
|
39
|
+
@subscribed_buttons[button] = block
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def record(&block)
|
44
|
+
claim_device unless claimed_device?
|
45
|
+
loop do
|
46
|
+
event = fetch_usb_event
|
47
|
+
yield event unless event.nil?
|
48
|
+
sleep(0.001)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def listen
|
53
|
+
claim_device unless claimed_device?
|
54
|
+
loop do
|
55
|
+
handle_usb_event if claimed_device?
|
56
|
+
handle_mouse_event if grabbed_mouse?
|
57
|
+
sleep(0.001)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def handle_usb_event
|
64
|
+
event = fetch_usb_event
|
65
|
+
if block = @subscribed_buttons[event]
|
66
|
+
block.call(event)
|
67
|
+
end
|
68
|
+
if button_status = @mouse_buttons[event]
|
69
|
+
if button_status[:action] == :press
|
70
|
+
@pressed_buttons[event] = button_status
|
71
|
+
grab_mouse unless grabbed_mouse?
|
72
|
+
elsif button_status[:action] == :release
|
73
|
+
@pressed_buttons.delete(button_status[:press])
|
74
|
+
ungrab_mouse if grabbed_mouse? && @pressed_buttons.empty?
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def handle_mouse_event
|
80
|
+
mouse_event = fetch_mouse_event
|
81
|
+
@pressed_buttons.each do |key_event, button_status|
|
82
|
+
button_status[:last] ||= Time.now
|
83
|
+
if (Time.now - button_status[:last]) > 1.0 / button_status[:frequency]
|
84
|
+
@mouse_buttons[key_event][:block].call(key_event, mouse_event)
|
85
|
+
button_status[:last] = Time.now
|
86
|
+
end
|
87
|
+
end unless mouse_event.nil?
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
data/lib/gyruby.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gyruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Kihlgren
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-05-
|
12
|
+
date: 2008-05-26 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -23,6 +23,8 @@ extra_rdoc_files: []
|
|
23
23
|
|
24
24
|
files:
|
25
25
|
- lib/gyruby.rb
|
26
|
+
- lib/gyruby/remote.rb
|
27
|
+
- lib/gyruby/mplayer_controller.rb
|
26
28
|
- ext/extconf.rb
|
27
29
|
- ext/gyruby_ext.c
|
28
30
|
has_rdoc: true
|
@@ -48,7 +50,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
48
50
|
requirements: []
|
49
51
|
|
50
52
|
rubyforge_project:
|
51
|
-
rubygems_version: 1.
|
53
|
+
rubygems_version: 1.1.1
|
52
54
|
signing_key:
|
53
55
|
specification_version: 2
|
54
56
|
summary: A ruby binding for the Gyration FiireChief remote control for LinuxMCE.
|