xdo 0.0.1-x86-linux
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/Rakefile +46 -0
- data/bin/xinfo.rb +136 -0
- data/lib/README.rdoc +55 -0
- data/lib/xdo.rb +28 -0
- data/lib/xdo/clipboard.rb +109 -0
- data/lib/xdo/drive.rb +66 -0
- data/lib/xdo/keyboard.rb +274 -0
- data/lib/xdo/mouse.rb +143 -0
- data/lib/xdo/wxaliases.rb +57 -0
- data/lib/xdo/xwindow.rb +416 -0
- data/samples/full_demo.rb +189 -0
- data/samples/mouse.rb +27 -0
- data/test/test_clipboard.rb +49 -0
- data/test/test_drive.rb +23 -0
- data/test/test_keyboard.rb +60 -0
- data/test/test_mouse.rb +28 -0
- data/test/test_xwindow.rb +104 -0
- metadata +94 -0
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
#Encoding: UTF-8
|
2
|
+
#This file is part of Xdo.
|
3
|
+
#Copyright © 2009 Marvin Gülker
|
4
|
+
# Initia in potestate nostra sunt, de eventu fortuna iudicat.
|
5
|
+
require "rake/gempackagetask"
|
6
|
+
require "rake/rdoctask"
|
7
|
+
require "rake/testtask"
|
8
|
+
|
9
|
+
spec = Gem::Specification.new do |s|
|
10
|
+
s.name = "xdo"
|
11
|
+
s.summary = "Simulate keyboard and mouse input via a ruby interface to xdotool and other console programs."
|
12
|
+
s.description =<<DESCRIPTION
|
13
|
+
XDo is a library to automate your mouse, fake keyboard input and
|
14
|
+
manipulate windows in a Linux X server environment. It's wrapped
|
15
|
+
around a lot of command line tools (see requirements) of which xdotool
|
16
|
+
is the main one, the others are usually installed.
|
17
|
+
DESCRIPTION
|
18
|
+
s.add_dependency("test-unit", ">= 2.0")
|
19
|
+
s.requirements = ["The xdotool command-line tool.", "xwininfo (usually installed)", "The xsel command-line tool.", "eject (usually installed)", "xkill (usually installed)"]
|
20
|
+
s.requirements << "The unit-test gem (will be installed if you don't have it)"
|
21
|
+
s.version = "0.0.1"
|
22
|
+
s.author = "Marvin Gülker"
|
23
|
+
s.email = "sutniuq@gmx.net"
|
24
|
+
s.platform = Gem::Platform::CURRENT
|
25
|
+
s.required_ruby_version = ">=1.9"
|
26
|
+
s.files = ["bin/xinfo.rb", Dir["lib/**/*.rb"], Dir["test/*.rb"], Dir["samples/*.rb"], "Rakefile", "lib/README.rdoc"].flatten
|
27
|
+
s.executables = ["xinfo.rb"]
|
28
|
+
s.has_rdoc = true
|
29
|
+
s.test_files = Dir["test/test_*.rb"]
|
30
|
+
s.rubyforge_project = "Automations"
|
31
|
+
end
|
32
|
+
Rake::GemPackageTask.new(spec).define
|
33
|
+
|
34
|
+
Rake::RDocTask.new do |rd|
|
35
|
+
rd.rdoc_files.include("lib/**/*.rb", "lib/README.rdoc")
|
36
|
+
rd.title = "xdo RDocs"
|
37
|
+
rd.main = "lib/README.rdoc"
|
38
|
+
end
|
39
|
+
|
40
|
+
Rake::TestTask.new("test") do |t|
|
41
|
+
t.pattern = "test/test_*.rb"
|
42
|
+
t.warning = true
|
43
|
+
end
|
44
|
+
|
45
|
+
desc "Tests XDo and then builds the gem file."
|
46
|
+
task :full_gem => [:test, :gem]
|
data/bin/xinfo.rb
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#Encoding: UTF-8
|
3
|
+
#This file is part of Xdo.
|
4
|
+
#Copyright © 2009 Marvin Gülker
|
5
|
+
# Initia in potestate nostra sunt, de eventu fortuna iudicat.
|
6
|
+
#
|
7
|
+
#This program displays information about the currently selected window
|
8
|
+
#and the mouse. The displayed infos are updated every 1/2 second,
|
9
|
+
#but set XInfo::UPDATE_TIME to another value if you'd like to change that.
|
10
|
+
require_relative("../lib/xdo/xwindow")
|
11
|
+
require_relative("../lib/xdo/mouse")
|
12
|
+
require "wx"
|
13
|
+
require_relative("../lib/xdo/wxaliases")
|
14
|
+
|
15
|
+
puts "=" * 80
|
16
|
+
puts "Started: #{Time.now}"
|
17
|
+
at_exit{puts "Finished: #{Time.now}"}
|
18
|
+
|
19
|
+
|
20
|
+
#--
|
21
|
+
#=================================================
|
22
|
+
#Backend
|
23
|
+
#=================================================
|
24
|
+
#++
|
25
|
+
|
26
|
+
#Class that retrieves the information of windows.
|
27
|
+
class InfoGetter
|
28
|
+
|
29
|
+
attr_reader :act_win
|
30
|
+
attr_reader :cursorpos
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
@act_win = XDo::XWindow.from_active
|
34
|
+
@cursorpos = XDo::Mouse.position
|
35
|
+
end
|
36
|
+
|
37
|
+
def update
|
38
|
+
@act_win = XDo::XWindow.from_active
|
39
|
+
@cursorpos = XDo::Mouse.position
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
#--
|
45
|
+
#=================================================
|
46
|
+
#Frontend
|
47
|
+
#=================================================
|
48
|
+
#++
|
49
|
+
include Wx
|
50
|
+
|
51
|
+
#Frontend of this program.
|
52
|
+
class XInfo < App
|
53
|
+
|
54
|
+
#Time intervall of updating the infos, in milliseconds.
|
55
|
+
#Default is 500, which is 1/2 second.
|
56
|
+
UPDATE_TIME = 500
|
57
|
+
|
58
|
+
def on_init
|
59
|
+
puts "Creating main window"
|
60
|
+
@mainwindow = Frame.new(nil, -1, "XInfo", DEFAULT_POSITION, Size.new(300, 400), DEFAULT_FRAME_STYLE | STAY_ON_TOP)
|
61
|
+
@mainwindow.background_colour = NULL_COLOUR
|
62
|
+
puts "Creating controls"
|
63
|
+
create_controls
|
64
|
+
puts "Setting up timer"
|
65
|
+
create_updater
|
66
|
+
|
67
|
+
puts "Display GUI"
|
68
|
+
@mainwindow.show
|
69
|
+
end
|
70
|
+
|
71
|
+
def create_controls
|
72
|
+
StaticText.new(@mainwindow, -1, "Title of active window: ", Point.new(20, 20))
|
73
|
+
@title = TextCtrl.new(@mainwindow, -1, "", Point.new(20, 50), Size.new(260, 24), TE_READONLY)
|
74
|
+
StaticText.new(@mainwindow, -1, "ID of active window: ", Point.new(20, 80))
|
75
|
+
@id = TextCtrl.new(@mainwindow, -1, "", Point.new(20, 110), Size.new(260, 24), TE_READONLY)
|
76
|
+
StaticText.new(@mainwindow, -1, "Absoloute and relative upper-left coords: ", Point.new(20,140))
|
77
|
+
StaticText.new(@mainwindow, -1, "Abs: ", Point.new(20, 173))
|
78
|
+
@abs_xy = TextCtrl.new(@mainwindow, -1, "", Point.new(60, 170), Size.new(70, 24), TE_READONLY)
|
79
|
+
StaticText.new(@mainwindow, -1, "Rel: ", Point.new(150, 173))
|
80
|
+
@rel_xy = TextCtrl.new(@mainwindow, -1, "", Point.new(190, 170), Size.new(70, 24), TE_READONLY)
|
81
|
+
StaticText.new(@mainwindow, -1, "Size: ", Point.new(20, 200))
|
82
|
+
StaticText.new(@mainwindow, -1, "Width: ", Point.new(20, 233))
|
83
|
+
@width = TextCtrl.new(@mainwindow, -1, "", Point.new(65, 230), Size.new(70, 24), TE_READONLY)
|
84
|
+
StaticText.new(@mainwindow, -1, "Height: ", Point.new(150, 233))
|
85
|
+
@height = TextCtrl.new(@mainwindow, -1, "", Point.new(200, 230), Size.new(70, 24), TE_READONLY)
|
86
|
+
|
87
|
+
StaticText.new(@mainwindow, -1, "Mouse position: ", Point.new(20, 300))
|
88
|
+
StaticText.new(@mainwindow, -1, "X: ", Point.new(20, 333))
|
89
|
+
@x = TextCtrl.new(@mainwindow, -1, "", Point.new(60, 330), Size.new(70, 24), TE_READONLY)
|
90
|
+
StaticText.new(@mainwindow, -1, "Y: ", Point.new(150, 333))
|
91
|
+
@y = TextCtrl.new(@mainwindow, -1, "", Point.new(190, 330), Size.new(70, 24), TE_READONLY)
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
def create_updater
|
96
|
+
@updater = InfoGetter.new
|
97
|
+
Timer.every(UPDATE_TIME) do
|
98
|
+
begin
|
99
|
+
@updater.update
|
100
|
+
@title.text = @updater.act_win.title
|
101
|
+
@id.text = @updater.act_win.id.inspect
|
102
|
+
@abs_xy.text = @updater.act_win.abs_position.join(", ")
|
103
|
+
@rel_xy.text = @updater.act_win.rel_position.join(", ")
|
104
|
+
ary = @updater.act_win.size
|
105
|
+
@width.text = ary[0].inspect
|
106
|
+
@height.text = ary[1].inspect
|
107
|
+
rescue NoMethodError
|
108
|
+
puts "Window closed. Skipping NoMethodError. "
|
109
|
+
#Das aktive Fenster wird wohl gerade gelöscht.
|
110
|
+
#Daher nichts machen.
|
111
|
+
end
|
112
|
+
|
113
|
+
curpos = @updater.cursorpos
|
114
|
+
@x.text = curpos[0].inspect
|
115
|
+
@y.text = curpos[1].inspect
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
begin
|
124
|
+
puts "Creating GUI"
|
125
|
+
x = XInfo.new
|
126
|
+
puts "Starting main loop"
|
127
|
+
x.main_loop
|
128
|
+
rescue
|
129
|
+
message = "An #{$!.class} occured. Backtrace: \n\n#{$@.join("\n")}"
|
130
|
+
message << "\n\nThe error message will be printed in the ~/.xinfo.rb.log file. "
|
131
|
+
message << "If you want to contact me about the error, send an email to sutniuq ät gmx Dot net and "
|
132
|
+
message << "attach the Err.log file."
|
133
|
+
msgbox = Wx::MessageDialog.new(nil, message, $!.class.to_s, OK | ICON_ERROR)
|
134
|
+
msgbox.show_modal
|
135
|
+
raise #for logging
|
136
|
+
end
|
data/lib/README.rdoc
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
--
|
2
|
+
This file is part of Xdo.
|
3
|
+
Copyright © 2009 Marvin Gülker
|
4
|
+
Initia in potestate nostra sunt, de eventu fortuna iudicat.
|
5
|
+
++
|
6
|
+
=XDo
|
7
|
+
XDo is a library to simmulate keyboard and mouse input and manipulating windows on the X server.
|
8
|
+
It's wrapped around the command-line tools xdotool[http://www.semicomplete.com/projects/xdotool/],
|
9
|
+
xsel[http://linux.die.net/man/1/xsel], xwininfo[http://linux.die.net/man/1/xwininfo], ecject[http://linux.die.net/man/1/eject] and xkill[http://linux.die.net/man/1/xkill],
|
10
|
+
so you will need to have them installed if you want to use Xdo (even if xsel, xwininfo, eject and xkill are usually already installed).
|
11
|
+
If not, as an Ubuntu or Debian user try to install them via
|
12
|
+
sudo apt-get install xdotool xsel xwininfo eject xkill
|
13
|
+
After they're installed, install XDo via RubyGems:
|
14
|
+
sudo gem install xdo
|
15
|
+
If you want to run the tests, change to the gem's installation directory and type "rake test".
|
16
|
+
Keep in mind that, while the tests run, you won't be able to use your computer, since they take control
|
17
|
+
of all things XDo is able to.
|
18
|
+
==Usage
|
19
|
+
#Require some of XDo's files
|
20
|
+
require "xdo/keyboard"
|
21
|
+
require "xdo/mouse"
|
22
|
+
require "xdo/xwindow"
|
23
|
+
#Move the cursor
|
24
|
+
XDo::Mouse.move(100, 100)
|
25
|
+
#Simulate text (with special escape sequences!)
|
26
|
+
XDo::Keyboard.simulate("This is{TAB}text.")
|
27
|
+
#And this will move a window containing the string "gedit",
|
28
|
+
#unless it's maximized.
|
29
|
+
win = XDo::XWindow.from_name("gedit")
|
30
|
+
win.move(200, 200)
|
31
|
+
==Files
|
32
|
+
You can require the following files in your projects:
|
33
|
+
* xdo/clipboard: Clipboard access
|
34
|
+
* xdo/drive: Get control of CD/DVD devices
|
35
|
+
* xdo/keyboard: Pretty self-explaining
|
36
|
+
* xdo/mouse: Automate the mouse
|
37
|
+
* xdo/xwindow: Manipulate windows in various ways
|
38
|
+
As an helpful extra, I created an executable ruby file "xinfo.rb". Thanks to RubyGems,
|
39
|
+
you can start this GUI tool right from the command line by typing:
|
40
|
+
xinfo.rb
|
41
|
+
It's by far not perfect, maybe not even good, but I think it can be useful sometimes
|
42
|
+
(you will need to have wxRuby installed, try <tt>sudo gem install wxruby-ruby19</tt>).
|
43
|
+
If you're looking for a more professional program, try the "X window information" tool.
|
44
|
+
==Notes
|
45
|
+
* +xdotool+ rejects to accept the --window option although it's documented, so you can't use the +w_id+ parameter of many methods in XDo::Keyboard.
|
46
|
+
* I recommand the "X window information" tool to get infos about your windows if you aren't satisfied by the xinfo.rb shipped with this package.
|
47
|
+
==Fairly incomplete
|
48
|
+
* I'm sure there are several things I didn't notice that can be automated somehow. If you know about, email me! Please add a description of the possibilities and a sample script (but don't expect that I will understand it - I only speak Ruby fluently, a bit C and a bit sh ;-) )
|
49
|
+
* Another interesting thing are the samples. There are many Linux distrubitions out there, and even many of them rely on X. I cannot test with another than a recent Ubuntu machine, but if you want to contribute and send samples for another OS, I want to encourage you to - I surely won't reject your work. :-)
|
50
|
+
==License/Copyright
|
51
|
+
Copyright © 2009 Marvin Gülker
|
52
|
+
This library is free software; you may redistribute it and/or modify it
|
53
|
+
under the terms of Ruby's license (see http://www.ruby-lang.org/en/LICENSE.txt).
|
54
|
+
You can contact me at sutniuq ät gmx Dot net.
|
55
|
+
Initia in potestate nostra sunt, de eventu fortuna iudicat.
|
data/lib/xdo.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#Encoding: UTF-8
|
2
|
+
#This file is part of Xdo.
|
3
|
+
#Copyright © 2009 Marvin Gülker
|
4
|
+
# Initia in potestate nostra sunt, de eventu fortuna iudicat.
|
5
|
+
|
6
|
+
#The namespace of this library.
|
7
|
+
module XDo
|
8
|
+
|
9
|
+
#The command to start xdotool.
|
10
|
+
XDOTOOL = "xdotool"
|
11
|
+
|
12
|
+
#The command to start xsel.
|
13
|
+
XSEL = "xsel"
|
14
|
+
|
15
|
+
#The command to start xwininfo.
|
16
|
+
XWININFO = "xwininfo"
|
17
|
+
|
18
|
+
#The command to start xkill.
|
19
|
+
XKILL = "xkill"
|
20
|
+
|
21
|
+
#The command to start eject.
|
22
|
+
EJECT = "eject"
|
23
|
+
|
24
|
+
#Class for errors in this library.
|
25
|
+
class XError < StandardError
|
26
|
+
end
|
27
|
+
|
28
|
+
end #module XDo
|
@@ -0,0 +1,109 @@
|
|
1
|
+
#Encoding: UTF-8
|
2
|
+
require_relative("../xdo")
|
3
|
+
|
4
|
+
module XDo
|
5
|
+
|
6
|
+
#A module for interaction with the X clipboard. Please note, that the X clipboard
|
7
|
+
#consists of three parts: The PRIMARY clipboard, the CLIPBOARD clipboard, and
|
8
|
+
#the SECONDARY clipboard. The clipboard you access normally via [CTRL]+[C]
|
9
|
+
#or by right-clicking and selecting "copy", is usually the CLIPBOARD clipboard (but that
|
10
|
+
#depends on the application you use). The three main methods of this module (#read, #write
|
11
|
+
#and #clear) take a hash with the symbols of the clipboards to interact with. If you don't want to
|
12
|
+
#pass in the symbols, use the predefined read_xy, write_xy and clear_xy methods. They cannot
|
13
|
+
#access more than one clipboard at a time.
|
14
|
+
#The symbols for the clipboards are:
|
15
|
+
#[PRIMARY] :primary
|
16
|
+
#[SECONDARY] :secondary
|
17
|
+
#[CLIPBOARD] :clipboard
|
18
|
+
module Clipboard
|
19
|
+
|
20
|
+
class << self
|
21
|
+
|
22
|
+
##
|
23
|
+
# :singleton-method: read_primary
|
24
|
+
|
25
|
+
##
|
26
|
+
# :singleton-method: read_clipboard
|
27
|
+
|
28
|
+
##
|
29
|
+
# :singleton-method: read_secondary
|
30
|
+
|
31
|
+
##
|
32
|
+
# :singleton-method: write_primary
|
33
|
+
|
34
|
+
##
|
35
|
+
# :singleton-method: write_clipboard
|
36
|
+
|
37
|
+
##
|
38
|
+
# :singleton-method: write_secondary
|
39
|
+
|
40
|
+
##
|
41
|
+
# :singleton-method: clear_primary
|
42
|
+
|
43
|
+
##
|
44
|
+
# :singleton-method: clear_clipboard
|
45
|
+
|
46
|
+
##
|
47
|
+
# :singleton-method: clear_secondary
|
48
|
+
|
49
|
+
[:primary, :clipboard, :secondary].each do |sym|
|
50
|
+
|
51
|
+
define_method(:"read_#{sym}") do
|
52
|
+
read({sym => true})[sym]
|
53
|
+
end
|
54
|
+
|
55
|
+
define_method(:"write_#{sym}") do |text|
|
56
|
+
write(text, {sym => true})
|
57
|
+
text
|
58
|
+
end
|
59
|
+
|
60
|
+
define_method(:"clear_#{sym}") do
|
61
|
+
clear({sym => true})
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
#Reads text from the X clipboard. The +from+ argument specifies
|
68
|
+
#from what clipboard you want to read (in 70% of all cases you
|
69
|
+
#want to read from :clipboard). Return value is a hash with the
|
70
|
+
#clipboards you specified as the keys. The contents of the clipboards
|
71
|
+
#are the values. You can also use one of the read_xy methods directly.
|
72
|
+
def read(from = {:clipboard => true})
|
73
|
+
hsh = {}
|
74
|
+
hsh[:primary] = `#{XSEL}` if from[:primary]
|
75
|
+
hsh[:clipboard] = `#{XSEL} -b` if from[:clipboard]
|
76
|
+
hsh[:secondary] = `#{XSEL} -s` if from[:secondary]
|
77
|
+
hsh
|
78
|
+
end
|
79
|
+
|
80
|
+
#Writes data to the X clipboard. The +to+ argument soecifies
|
81
|
+
#the clipboard you want to write to. If you want to be able to paste
|
82
|
+
#your text via [CTRL]+[v], use :clipboard. You can also use the
|
83
|
+
#write_xy methods if you don't want to pass in the hash.
|
84
|
+
def write(text, to = {:primary => true, :clipboard => true})
|
85
|
+
IO.popen("xsel -i", "w"){|io| io.write(text)} if to[:primary]
|
86
|
+
IO.popen("xsel -b -i", "w"){|io| io.write(text)} if to[:clipboard]
|
87
|
+
IO.popen("xsel -s -i", "w"){|io| io.write(text)} if to[:secondary]
|
88
|
+
text
|
89
|
+
end
|
90
|
+
|
91
|
+
#Append data to text already written to the X clipboard. As in #write,
|
92
|
+
#you can specify the clipboard you want to append text to.
|
93
|
+
def append(text, to = {:primary => true, :clipboard => true})
|
94
|
+
IO.popen("xsel -a -i", "w"){|io| io.write(text)} if to[:primary]
|
95
|
+
IO.popen("xsel -b -a -i", "w"){|io| io.write(text)} if to[:clipboard]
|
96
|
+
IO.popen("xsel -s -a -i", "w"){|io| io.write(text)} if to[:secondary]
|
97
|
+
end
|
98
|
+
|
99
|
+
#Clears the specified clipboards.
|
100
|
+
def clear(clips = {:primary => true, :clipboard => true})
|
101
|
+
`#{XSEL} -c` if clips[:primary]
|
102
|
+
`#{XSEL} -b -c` if clips[:clipboard]
|
103
|
+
`#{XSEL} -s -c` if clips[:secondary]
|
104
|
+
nil
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
data/lib/xdo/drive.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
#Encoding: UTF-8
|
2
|
+
require "open3"
|
3
|
+
require_relative("../xdo")
|
4
|
+
|
5
|
+
module XDo
|
6
|
+
|
7
|
+
#Some methods to interact with CD (and DVD, of course) drives.
|
8
|
+
#The value of the +drive+ parameter of many methods can be
|
9
|
+
#either a mount point or a device file like scd0.
|
10
|
+
#
|
11
|
+
#If you don't pass in a drive name, the returnvalue of #default will
|
12
|
+
#be used.
|
13
|
+
module Drive
|
14
|
+
|
15
|
+
class << self
|
16
|
+
include Open3
|
17
|
+
#Opens a drive.
|
18
|
+
def eject(drive = nil)
|
19
|
+
err = ""
|
20
|
+
drive = default unless drive
|
21
|
+
popen3("#{XDo::EJECT} #{drive}"){|stdin, stdout, stderr| err << stderr.read}
|
22
|
+
raise(XDo::XError, err) unless err.empty?
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
#Closes a drive.
|
27
|
+
def close(drive = nil)
|
28
|
+
drive = default unless drive
|
29
|
+
err = ""
|
30
|
+
popen3("eject -t #{drive}"){|stdin, stdout, stderr| err << stderr.read}
|
31
|
+
raise(XDo::XError, err) unless err.empty?
|
32
|
+
end
|
33
|
+
|
34
|
+
#Returns the mount point of the default drive.
|
35
|
+
#You can use it as a value for a +drive+ parameter.
|
36
|
+
def default
|
37
|
+
err = ""
|
38
|
+
out = ""
|
39
|
+
popen3("#{XDo::EJECT} -d"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
|
40
|
+
raise(XDo::XError, err) unless err.empty?
|
41
|
+
out.match(/`(.*)'/)[1]
|
42
|
+
end
|
43
|
+
|
44
|
+
#Locks a drive, so that it can't be opened by
|
45
|
+
#using the eject button.
|
46
|
+
def lock(drive = nil)
|
47
|
+
drive = default unless drive
|
48
|
+
err = ""
|
49
|
+
popen3("#{XDo::EJECT} -i on #{drive}"){|stdin, stdout, stderr| err << stderr.read}
|
50
|
+
raise(XDo::XError, err) unless err.empty?
|
51
|
+
true
|
52
|
+
end
|
53
|
+
|
54
|
+
#Unlocks a drive, so that it can be opened
|
55
|
+
#by the eject button.
|
56
|
+
def release(drive = nil)
|
57
|
+
drive = default unless drive
|
58
|
+
err = ""
|
59
|
+
popen3("#{XDo::EJECT} -i off #{drive}")
|
60
|
+
raise(XDo::XError,err) unless err.empty?
|
61
|
+
true
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|