gyruby 0.0.2 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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.
|