gyruby 0.1.1 → 0.1.3
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/bin/gyration_remote +52 -0
- data/ext/gyruby_ext.c +69 -0
- data/lib/gyruby/mplayer_controller.rb +49 -6
- data/lib/gyruby/remote.rb +52 -23
- metadata +8 -7
data/bin/gyration_remote
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'gyruby'
|
5
|
+
|
6
|
+
class RemoteRunner
|
7
|
+
@@class_to_run = MplayerController
|
8
|
+
def self.class_to_run=(c)
|
9
|
+
@@class_to_run = c
|
10
|
+
end
|
11
|
+
def self.gyration_pids
|
12
|
+
`pidof -x #{File.basename($0)}`.split.select do |pid|
|
13
|
+
pid.to_s != $$.to_s
|
14
|
+
end
|
15
|
+
end
|
16
|
+
def self.start
|
17
|
+
if gyration_pids.empty?
|
18
|
+
child_pid = fork do
|
19
|
+
grandchild_pid = fork do
|
20
|
+
c = @@class_to_run.new
|
21
|
+
c.listen
|
22
|
+
end
|
23
|
+
end
|
24
|
+
Process.wait(child_pid)
|
25
|
+
return 0
|
26
|
+
else
|
27
|
+
return 1
|
28
|
+
end
|
29
|
+
end
|
30
|
+
def self.stop
|
31
|
+
pids = gyration_pids
|
32
|
+
if pids.empty?
|
33
|
+
return 1
|
34
|
+
else
|
35
|
+
gyration_pids.each do |pid|
|
36
|
+
`kill #{pid}`
|
37
|
+
end
|
38
|
+
return 0
|
39
|
+
end
|
40
|
+
end
|
41
|
+
def self.go!
|
42
|
+
if ARGV.size != 1 || !["start", "stop"].include?(ARGV.first)
|
43
|
+
STDERR.puts("Usage: #{$0} start|stop")
|
44
|
+
exit 1
|
45
|
+
end
|
46
|
+
self.send(ARGV.first)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
if File.basename($0) == File.basename(__FILE__)
|
51
|
+
exit RemoteRunner.go!
|
52
|
+
end
|
data/ext/gyruby_ext.c
CHANGED
@@ -375,6 +375,73 @@ rb_remote_get_grabbed_mouse(VALUE self) {
|
|
375
375
|
return Qtrue;
|
376
376
|
}
|
377
377
|
|
378
|
+
static VALUE
|
379
|
+
rb_remote_send_key(VALUE self, VALUE state, VALUE keycode) {
|
380
|
+
c_remote *this;
|
381
|
+
gboolean grabbed_display = FALSE;
|
382
|
+
XEvent event;
|
383
|
+
Window focus;
|
384
|
+
int focus_return;
|
385
|
+
|
386
|
+
Check_Type(keycode, T_FIXNUM);
|
387
|
+
C_REMOTE(self, this);
|
388
|
+
if (this->display == NULL) {
|
389
|
+
this->display = XOpenDisplay(NULL);
|
390
|
+
grabbed_display = TRUE;
|
391
|
+
}
|
392
|
+
XGetInputFocus(this->display, &focus, &focus_return);
|
393
|
+
|
394
|
+
event.xkey.type = KeyPress;
|
395
|
+
event.xkey.root = XDefaultRootWindow(this->display);
|
396
|
+
event.xkey.window = focus;
|
397
|
+
event.xkey.subwindow = None;
|
398
|
+
event.xkey.keycode = NUM2INT(keycode);
|
399
|
+
event.xkey.same_screen = True;
|
400
|
+
event.xkey.time = CurrentTime;
|
401
|
+
event.xkey.x = 1;
|
402
|
+
event.xkey.y = 1;
|
403
|
+
event.xkey.x_root = 1;
|
404
|
+
event.xkey.y_root = 1;
|
405
|
+
event.xkey.state = NUM2INT(state);
|
406
|
+
XSendEvent(this->display, InputFocus, True, KeyPressMask, &event);
|
407
|
+
event.xkey.type = KeyRelease;
|
408
|
+
XSendEvent(this->display, InputFocus, True, KeyReleaseMask, &event);
|
409
|
+
if (grabbed_display) {
|
410
|
+
XCloseDisplay(this->display);
|
411
|
+
this->display = NULL;
|
412
|
+
}
|
413
|
+
return self;
|
414
|
+
}
|
415
|
+
|
416
|
+
static VALUE
|
417
|
+
rb_remote_close_active(VALUE self) {
|
418
|
+
c_remote *this;
|
419
|
+
Window active;
|
420
|
+
gint revert_to_return;
|
421
|
+
gboolean grabbed_display = FALSE;
|
422
|
+
|
423
|
+
C_REMOTE(self, this);
|
424
|
+
|
425
|
+
if (this->display == NULL) {
|
426
|
+
this->display = XOpenDisplay(NULL);
|
427
|
+
grabbed_display = TRUE;
|
428
|
+
}
|
429
|
+
|
430
|
+
XGetInputFocus(this->display, &active, &revert_to_return);
|
431
|
+
if (active != XDefaultRootWindow(this->display)) {
|
432
|
+
XSync(this->display, 0);
|
433
|
+
XDestroyWindow(this->display, active);
|
434
|
+
XSync(this->display, 0);
|
435
|
+
}
|
436
|
+
|
437
|
+
if (grabbed_display) {
|
438
|
+
XCloseDisplay(this->display);
|
439
|
+
this->display = NULL;
|
440
|
+
}
|
441
|
+
|
442
|
+
return self;
|
443
|
+
}
|
444
|
+
|
378
445
|
#ifdef __cplusplus
|
379
446
|
extern "C" {
|
380
447
|
#endif
|
@@ -401,6 +468,8 @@ extern "C" {
|
|
401
468
|
rb_define_private_method(rb_remote, "fetch_mouse_event", rb_remote_fetch_mouse_event, 0);
|
402
469
|
rb_define_private_method(rb_remote, "claimed_device?", rb_remote_get_claimed_device, 0);
|
403
470
|
rb_define_private_method(rb_remote, "grabbed_mouse?", rb_remote_get_grabbed_mouse, 0);
|
471
|
+
rb_define_private_method(rb_remote, "send_key", rb_remote_send_key, 2);
|
472
|
+
rb_define_private_method(rb_remote, "close_active", rb_remote_close_active, 0);
|
404
473
|
}
|
405
474
|
#ifdef __cplusplus
|
406
475
|
}
|
@@ -18,8 +18,10 @@
|
|
18
18
|
require 'pathname'
|
19
19
|
|
20
20
|
class MplayerController < Gyruby::Remote
|
21
|
+
|
22
|
+
MAX_SKIP = 16.0
|
21
23
|
|
22
|
-
def initialize
|
24
|
+
def initialize
|
23
25
|
super()
|
24
26
|
subscribe("\b%\377\351\000\000") do |s|
|
25
27
|
volume_up
|
@@ -34,26 +36,67 @@ class MplayerController < Gyruby::Remote
|
|
34
36
|
osd_down
|
35
37
|
end
|
36
38
|
subscribe("\b%\377\313\000\000", "\b%\377\000\000\000") do |key, options|
|
37
|
-
seek(options[:x].to_f/ options[:xmax].to_f)
|
39
|
+
seek(options[:x].to_f / options[:xmax].to_f)
|
40
|
+
end
|
41
|
+
subscribe("\b%\377\314\000\000") do |s|
|
42
|
+
start_skip
|
43
|
+
end
|
44
|
+
subscribe("\b%\377\000\000\000") do |s|
|
45
|
+
stop_skip
|
46
|
+
end
|
47
|
+
subscribe("\b%\377\314\000\000", "\b%\377\000\000\000") do |key, options|
|
48
|
+
@skip_speed = (((options[:x] * 2.0) / options[:xmax]) - 1.0) * MAX_SKIP
|
49
|
+
end
|
50
|
+
subscribe("\b%\377\315\000\000", "\b%\377\000\000\000") do |key, options|
|
51
|
+
volume(options[:x].to_f / options[:xmax].to_f)
|
38
52
|
end
|
39
53
|
@osd = 0
|
40
|
-
@
|
54
|
+
@skip_thread = nil
|
55
|
+
@skip_speed = 0.0
|
41
56
|
end
|
42
57
|
|
43
58
|
private
|
44
59
|
|
60
|
+
def start_skip
|
61
|
+
@skip_thread ||= Thread.new do
|
62
|
+
begin
|
63
|
+
sleep_started = Time.now
|
64
|
+
loop do
|
65
|
+
if @skip_speed != 0
|
66
|
+
if Time.now - sleep_started > (1.0 / @skip_speed.abs)
|
67
|
+
send_command("seek #{@skip_speed > 0 ? 1 : -1}")
|
68
|
+
sleep_started = Time.now
|
69
|
+
end
|
70
|
+
end
|
71
|
+
sleep 0.01
|
72
|
+
end
|
73
|
+
rescue Exception => e
|
74
|
+
STDERR.puts e
|
75
|
+
STDERR.puts e.backtrace.join("\n")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def stop_skip
|
81
|
+
@skip_thread.kill if @skip_thread.respond_to?(:alive?) && @skip_thread.alive?
|
82
|
+
@skip_thread = nil
|
83
|
+
end
|
84
|
+
|
45
85
|
def send_command(cmd)
|
46
|
-
ctrl_path = Pathname.new(File.join("
|
86
|
+
ctrl_path = Pathname.new(File.join(ENV["HOME"], ".mplayer", "fifo"))
|
47
87
|
ctrl_path.open("a") do |ctrl|
|
48
88
|
ctrl.puts(cmd)
|
49
89
|
end if ctrl_path.exist? && mplayer_running?
|
50
90
|
end
|
51
91
|
|
52
92
|
def seek(f)
|
53
|
-
puts f.inspect
|
54
93
|
send_command("seek #{f * 100} 1")
|
55
94
|
end
|
56
95
|
|
96
|
+
def volume(f)
|
97
|
+
send_command("volume #{f * 100} 1")
|
98
|
+
end
|
99
|
+
|
57
100
|
def osd_up
|
58
101
|
@osd += 1 if @osd < 3
|
59
102
|
send_command("osd #{@osd}")
|
@@ -77,7 +120,7 @@ class MplayerController < Gyruby::Remote
|
|
77
120
|
STDOUT.reopen(open("/dev/null", "w"))
|
78
121
|
args = ["/usr/bin/env",
|
79
122
|
"pgrep",
|
80
|
-
"-U",
|
123
|
+
"-U", ENV["USER"],
|
81
124
|
"mplayer"]
|
82
125
|
exec(*args)
|
83
126
|
end
|
data/lib/gyruby/remote.rb
CHANGED
@@ -15,10 +15,28 @@
|
|
15
15
|
# along with this program; if not, write to the Free Software
|
16
16
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
17
17
|
|
18
|
+
require 'set'
|
19
|
+
|
18
20
|
module Gyruby
|
19
21
|
|
20
22
|
class Remote
|
21
23
|
|
24
|
+
class MouseButton
|
25
|
+
attr_accessor :action, :block, :frequency, :last, :event, :press
|
26
|
+
def initialize(options)
|
27
|
+
@event, @block, @frequency = options.delete(:event), options.delete(:block), options.delete(:frequency)
|
28
|
+
@last = nil
|
29
|
+
@action = :press
|
30
|
+
@press = self
|
31
|
+
end
|
32
|
+
def release(event)
|
33
|
+
rval = self.clone
|
34
|
+
rval.action = :release
|
35
|
+
rval.event = event
|
36
|
+
return rval
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
22
40
|
def initialize
|
23
41
|
@subscribed_buttons = {}
|
24
42
|
@pressed_buttons = {}
|
@@ -26,17 +44,16 @@ module Gyruby
|
|
26
44
|
@listening = false
|
27
45
|
end
|
28
46
|
|
29
|
-
def subscribe(
|
47
|
+
def subscribe(press, release = false, frequency = 10, &block)
|
30
48
|
if release
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
}
|
37
|
-
@mouse_buttons[release] = {:action => :release, :press => button}
|
49
|
+
button = MouseButton.new(:block => block, :frequency => frequency, :event => press)
|
50
|
+
@mouse_buttons[press] ||= []
|
51
|
+
@mouse_buttons[press] << button
|
52
|
+
@mouse_buttons[release] ||= []
|
53
|
+
@mouse_buttons[release] << button.release(release)
|
38
54
|
else
|
39
|
-
@subscribed_buttons[
|
55
|
+
@subscribed_buttons[press] ||= []
|
56
|
+
@subscribed_buttons[press] << block
|
40
57
|
end
|
41
58
|
end
|
42
59
|
|
@@ -62,27 +79,39 @@ module Gyruby
|
|
62
79
|
|
63
80
|
def handle_usb_event
|
64
81
|
event = fetch_usb_event
|
65
|
-
if
|
66
|
-
block
|
82
|
+
if blocks = @subscribed_buttons[event]
|
83
|
+
blocks.each do |block|
|
84
|
+
block.call(event)
|
85
|
+
end
|
67
86
|
end
|
68
|
-
if
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
87
|
+
if mouse_buttons = @mouse_buttons[event]
|
88
|
+
mouse_buttons.each do |button|
|
89
|
+
if button.action == :press
|
90
|
+
@pressed_buttons[button.event] ||= Set.new
|
91
|
+
@pressed_buttons[button.event] << button
|
92
|
+
grab_mouse unless grabbed_mouse?
|
93
|
+
elsif button.action == :release
|
94
|
+
if buttons = @pressed_buttons[button.press.event]
|
95
|
+
buttons.delete(button.press)
|
96
|
+
if buttons.empty?
|
97
|
+
@pressed_buttons.delete(button.press.event)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
ungrab_mouse if grabbed_mouse? && @pressed_buttons.empty?
|
101
|
+
end
|
75
102
|
end
|
76
103
|
end
|
77
104
|
end
|
78
105
|
|
79
106
|
def handle_mouse_event
|
80
107
|
mouse_event = fetch_mouse_event
|
81
|
-
@pressed_buttons.each do |key_event,
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
108
|
+
@pressed_buttons.each do |key_event, buttons|
|
109
|
+
buttons.each do |button|
|
110
|
+
button.last ||= Time.now
|
111
|
+
if (Time.now - button.last) > 1.0 / button.frequency
|
112
|
+
button.block.call(key_event, mouse_event)
|
113
|
+
button.last = Time.now
|
114
|
+
end
|
86
115
|
end
|
87
116
|
end unless mouse_event.nil?
|
88
117
|
end
|
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.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Kihlgren
|
@@ -9,22 +9,23 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-06-06 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
16
16
|
description:
|
17
17
|
email: gyruby at troja dot ath dot cx
|
18
|
-
executables:
|
19
|
-
|
18
|
+
executables:
|
19
|
+
- gyration_remote
|
20
20
|
extensions:
|
21
21
|
- ext/extconf.rb
|
22
22
|
extra_rdoc_files: []
|
23
23
|
|
24
24
|
files:
|
25
|
-
- lib/gyruby.rb
|
26
|
-
- lib/gyruby/remote.rb
|
27
25
|
- lib/gyruby/mplayer_controller.rb
|
26
|
+
- lib/gyruby/remote.rb
|
27
|
+
- lib/gyruby.rb
|
28
|
+
- bin/gyration_remote
|
28
29
|
- ext/extconf.rb
|
29
30
|
- ext/gyruby_ext.c
|
30
31
|
has_rdoc: true
|
@@ -50,7 +51,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
50
51
|
requirements: []
|
51
52
|
|
52
53
|
rubyforge_project:
|
53
|
-
rubygems_version: 1.
|
54
|
+
rubygems_version: 1.0.1
|
54
55
|
signing_key:
|
55
56
|
specification_version: 2
|
56
57
|
summary: A ruby binding for the Gyration FiireChief remote control for LinuxMCE.
|