xdo 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,11 @@
1
+ =Deprecations
2
+ The following method uses are _deprecated_ and will be removed in the next minor version bump. They show a warning if you use them unless otherwise stated.
3
+
4
+ * XWindow.desktop_name= is obsolete now and has noo effect anymore.
5
+ * XWindow.desktop_name is obsolete now. It always returns "x-nautilus-desktop".
6
+ * XWindow.focus_desktop has been deprecated. Use XWindow.unfocus instead.
7
+ * All Clipboard module methods take a hash in order to specify which clipboards to interact with now take the symbols directly via a rest argument.
8
+ * All Mouse module methods that took constant values now accept symbols. The old behaviour is deprecated now.
9
+ * All XWindow class methods that take a hash in order to specify which windows to search now take the symbols directly via a rest argument.
10
+ * All XWindow class methods that take a string as the window to search for are now accepting Regular Expressions. That means, in later version you have to pass in a regexp if you don't want to look for an entire title at once, i.e. <tt>"edit"</tt> won't find a "gedit" window, but <tt>/edit/</tt> will. <b>This doesn't show a warning. </b>
11
+ * XWindow.from_name has been deprecated. The old functionality (i.e. the ability to specify all search parameters) is now provided by the XWindow.from_search method. XWindow.from_name will be used as an alias for XWindow.from_title in the next version.
@@ -0,0 +1,33 @@
1
+ =History of the xdo gem
2
+ This file shows the history of the xdo gem
3
+ from it's very beginning. Important changes in the
4
+ API are marked <b>bold</b>. Bugfixes are <i>italic</i>.
5
+
6
+ ==0.0.4
7
+ * <b>Several methods now accept a +sync+ parameter wrapping +xdotool+'s <tt>--sync</tt> option. </b>
8
+ * <b>Added XWindow.unfocus</b>
9
+ * <b>Added XWindow.root_id</b>
10
+ * <b>Added XWindow.from_root</b>
11
+ * <b>Added XWindow.from_null</b>
12
+ * Removed the internal SmallScanner class. We're now using StringScanner directly.
13
+ * All methods in the Mouse module now accept symbols for the +button+ parameter.
14
+ * <i>XWindow#exists? aways returned false. This has been fixed.</i>
15
+ * <i>XWindow#visible? always returned false. This has been fixed.</i>
16
+ * <b>Added XWindow#to_i and XWindow#to_s.</b>
17
+ * <b>Added XWindow#zero? and XWindow#nonzero?.</b>
18
+ * All methods in the Keyboard module that accept a +w_id+ parameter now can take XWindow objects.
19
+ * Removed Keyboard.sequence_escape.
20
+ * Several deprecations. See DEPRECATE.rdoc.
21
+ * <b>Added XWindow.from_title.</b>
22
+
23
+ ==0.0.3
24
+ * <i>Some XWindow instance methods (like #close!) showed wrong error messages due to the redundance of Kernel#raise with XWindow#raise. This has been fixed. </i>
25
+ * If run alone, the "test_xwindow.rb" test file failed with obscure errors. Fixed.
26
+
27
+ ==0.0.2
28
+ * Replaced fork{system("gedit")} in full_demo.rb with spawn("gedit")
29
+ * Removed "require 'pp'" from keyboard.rb
30
+ * <b>Added the Simulatable mixin</b>
31
+ * <b>Corrected window id usage for the XDo::Keyboard module</b>
32
+ * Added a test for the window id usage
33
+ * Made the test-unit gem a development dependency
@@ -0,0 +1,53 @@
1
+ --
2
+ This file is part of Xdo.
3
+ Copyright © 2009, 2010 Marvin Gülker
4
+ Initia in potestate nostra sunt, de eventu fortuna iudicat.
5
+ ++
6
+ =XDo
7
+ XDo is a library to simulate 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], eject[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 xwininfo, eject and xkill are usually already installed).
11
+ If not, try to install them via your favourite packaging manager.
12
+ After they're installed, install XDo via RubyGems:
13
+ sudo gem install xdo
14
+ ==Usage
15
+ #Require some of XDo's files
16
+ require "xdo/keyboard"
17
+ require "xdo/mouse"
18
+ require "xdo/xwindow"
19
+ #Move the cursor
20
+ XDo::Mouse.move(100, 100)
21
+ #Simulate text (with special escape sequences!)
22
+ XDo::Keyboard.simulate("This is{TAB}text.")
23
+ #Some sequences can be shortened:
24
+ XDo::Keyboard.simulate("This ist\ttext.")
25
+ #And this will move a window containing the string "gedit",
26
+ #unless it's maximized.
27
+ win = XDo::XWindow.from_title(/gedit/)
28
+ win.move(200, 200)
29
+ ==Files
30
+ You can require the following files in your projects:
31
+ * xdo/clipboard: Clipboard access
32
+ * xdo/drive: Get control of CD/DVD devices
33
+ * xdo/keyboard: Pretty self-explaining
34
+ * xdo/mouse: Automate the mouse
35
+ * xdo/xwindow: Manipulate windows in various ways
36
+ As an helpful extra, I created an executable ruby file "xinfo.rb". Thanks to RubyGems,
37
+ you can start this GUI tool right from the command line by typing:
38
+ xinfo.rb
39
+ It's by far not perfect, maybe not even good, but I think it can be useful sometimes
40
+ (you will need to have wxRuby installed, try <tt>sudo gem install wxruby-ruby19</tt>).
41
+ If you're looking for a more professional program, try the "X window information" tool.
42
+ ==Notes
43
+ * If your +xdotool+ seems to reject the --window option, you are not using the current version. Try building the newest one from the source.
44
+ * 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.
45
+ ==Fairly incomplete
46
+ * 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.
47
+ * 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. :-)
48
+ ==License/Copyright
49
+ Copyright © 2009, 2010 Marvin Gülker
50
+ This library is free software; you may redistribute it and/or modify it
51
+ under the terms of Ruby's license (see http://www.ruby-lang.org/en/LICENSE.txt).
52
+ You can contact me at sutniuq ät gmx Dot net.
53
+ Initia in potestate nostra sunt, de eventu fortuna iudicat.
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.4
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env ruby
2
+ #Encoding: UTF-8
3
+ #This file is part of Xdo.
4
+ #Copyright © 2009, 2010 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
+
11
+ require "logger"
12
+ require "wx"
13
+
14
+ require_relative("../lib/xdo/xwindow")
15
+ require_relative("../lib/xdo/mouse")
16
+
17
+ #Class that retrieves the information of windows.
18
+ class InfoGetter
19
+
20
+ attr_reader :act_win
21
+ attr_reader :cursorpos
22
+
23
+ def initialize
24
+ @act_win = XDo::XWindow.from_active
25
+ @cursorpos = XDo::Mouse.position
26
+ end
27
+
28
+ def update
29
+ @act_win = XDo::XWindow.from_active
30
+ @cursorpos = XDo::Mouse.position
31
+ end
32
+
33
+ end
34
+
35
+ class XInfoFrame < Wx::Frame
36
+ include Wx
37
+
38
+ #Time intervall of updating the infos, in milliseconds.
39
+ #Default is 500, which is 1/2 second.
40
+ UPDATE_TIME = 500
41
+
42
+ def initialize(parent = nil)
43
+ super(parent, title: "XInfo", size: Size.new(300, 400), style: DEFAULT_FRAME_STYLE | STAY_ON_TOP)
44
+ self.background_colour = NULL_COLOUR
45
+ THE_APP.log.debug("Creating controls")
46
+ create_controls
47
+ THE_APP.log.debug("Setting up timer")
48
+ create_updater
49
+ end
50
+
51
+ private
52
+
53
+ def create_controls
54
+ StaticText.new(self, -1, "Title of active window: ", Point.new(20, 20))
55
+ @title = TextCtrl.new(self, pos: Point.new(20, 50), size: Size.new(260, 24), style: TE_READONLY)
56
+ StaticText.new(self, -1, "ID of active window: ", Point.new(20, 80))
57
+ @id = TextCtrl.new(self, -1, "", Point.new(20, 110), Size.new(260, 24), TE_READONLY)
58
+ StaticText.new(self, -1, "Absoloute and relative upper-left coords: ", Point.new(20,140))
59
+ StaticText.new(self, -1, "Abs: ", Point.new(20, 173))
60
+ @abs_xy = TextCtrl.new(self, -1, "", Point.new(60, 170), Size.new(70, 24), TE_READONLY)
61
+ StaticText.new(self, -1, "Rel: ", Point.new(150, 173))
62
+ @rel_xy = TextCtrl.new(self, -1, "", Point.new(190, 170), Size.new(70, 24), TE_READONLY)
63
+ StaticText.new(self, -1, "Size: ", Point.new(20, 200))
64
+ StaticText.new(self, -1, "Width: ", Point.new(20, 233))
65
+ @width = TextCtrl.new(self, -1, "", Point.new(65, 230), Size.new(70, 24), TE_READONLY)
66
+ StaticText.new(self, -1, "Height: ", Point.new(150, 233))
67
+ @height = TextCtrl.new(self, -1, "", Point.new(200, 230), Size.new(70, 24), TE_READONLY)
68
+
69
+ StaticText.new(self, -1, "Mouse position: ", Point.new(20, 300))
70
+ StaticText.new(self, -1, "X: ", Point.new(20, 333))
71
+ @x = TextCtrl.new(self, -1, "", Point.new(60, 330), Size.new(70, 24), TE_READONLY)
72
+ StaticText.new(self, -1, "Y: ", Point.new(150, 333))
73
+ @y = TextCtrl.new(self, -1, "", Point.new(190, 330), Size.new(70, 24), TE_READONLY)
74
+ end
75
+
76
+ def create_updater
77
+ @updater = InfoGetter.new
78
+ Timer.every(UPDATE_TIME) do
79
+ begin
80
+ @updater.update
81
+ @title.value = @updater.act_win.title
82
+ @id.value = @updater.act_win.id.inspect
83
+ @abs_xy.value = @updater.act_win.abs_position.join(", ")
84
+ @rel_xy.value = @updater.act_win.rel_position.join(", ")
85
+ ary = @updater.act_win.size
86
+ @width.value = ary[0].inspect
87
+ @height.value = ary[1].inspect
88
+ end
89
+
90
+ curpos = @updater.cursorpos
91
+ @x.value = curpos[0].inspect
92
+ @y.value = curpos[1].inspect
93
+ end
94
+ end
95
+
96
+ end
97
+
98
+ #Main App object of this program.
99
+ class XInfo < Wx::App
100
+ include Wx
101
+
102
+ #Logger.
103
+ attr_reader :log
104
+
105
+ def on_init
106
+ @log = Logger.new($stdout)
107
+ @log.level = Logger::INFO unless $VERBOSE || $DEBUG
108
+ @log.info("Started")
109
+ @log.debug "Creating main window"
110
+ @mainwindow = XInfoFrame.new
111
+ @mainwindow.show
112
+ end
113
+
114
+ def on_run
115
+ super
116
+ rescue => e
117
+ @log.fatal(e.class.name)
118
+ @log.fatal(e.message)
119
+ e.backtrace.each{|trace| @log.fatal(trace)}
120
+ message = "A #{e.class} occured: #{e.message} \n\nBacktrace: \n\n#{e.backtrace.join("\n")}"
121
+ message << "\n\nIf you want to contact me about the error, send an email to sutniuq ät gmx Dot net."
122
+ msgbox = MessageDialog.new(@mainwindow, message, $!.class.name, OK | ICON_ERROR)
123
+ msgbox.show_modal
124
+ raise
125
+ end
126
+
127
+ def on_exit
128
+ super
129
+ @log.info("Finished.")
130
+ end
131
+
132
+ end
133
+
134
+ if ARGV.include?("-h") or ARGV.include?("--help")
135
+ puts "This is xinfo.rb, from xdo #{XDo::VERSION}."
136
+ puts "xinfo.rb is a tool for inspecting GUI windows on X."
137
+ puts
138
+ puts "Copyright © 2010 Marvin Gülker"
139
+ puts "Licensed under the same terms as Ruby."
140
+ puts "You can find Ruby's license at http://www.ruby-lang.org/en/LICENSE.txt."
141
+ puts
142
+ puts "xinfo.rb doesn't understand many command-line options."
143
+ puts "There's -h for this message, -V for verbose output"
144
+ puts "and -d for debugging. -v shows XDo's version."
145
+ exit
146
+ elsif ARGV.include?("-v") or ARGV.include?("--version")
147
+ puts "This is xinfo.rb, from xdo #{XDo::VERSION}."
148
+ exit
149
+ end
150
+
151
+ $VERBOSE = true if ARGV.include?("-V")
152
+ $DEBUG = true if ARGV.include?("-d")
153
+
154
+ x = XInfo.new
155
+ x.main_loop
@@ -0,0 +1,37 @@
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
+ require "open3"
7
+ require "strscan"
8
+
9
+ #The namespace of this library.
10
+ module XDo
11
+
12
+ #The command to start xdotool.
13
+ XDOTOOL = "xdotool"
14
+
15
+ #The command to start xsel.
16
+ XSEL = "xsel"
17
+
18
+ #The command to start xwininfo.
19
+ XWININFO = "xwininfo"
20
+
21
+ #The command to start xkill.
22
+ XKILL = "xkill"
23
+
24
+ #The command to start eject.
25
+ EJECT = "eject"
26
+
27
+ #The version of this library.
28
+ VERSION = File.read(File.join(File.expand_path(File.dirname(__FILE__)), "..", "VERSION")).freeze
29
+
30
+ #Class for errors in this library.
31
+ class XError < StandardError
32
+ end
33
+
34
+ class ParseError < StandardError
35
+ end
36
+
37
+ end #module XDo
@@ -0,0 +1,208 @@
1
+ #Encoding: UTF-8
2
+ #This file is part of Xdo.
3
+ #Copyright © 2009, 2010 Marvin Gülker
4
+ # Initia in potestate nostra sunt, de eventu fortuna iudicat.
5
+
6
+ require_relative("../xdo")
7
+
8
+ module XDo
9
+
10
+ #A module for interaction with the X clipboard. Please note, that the X clipboard
11
+ #consists of three parts: The PRIMARY clipboard, the CLIPBOARD clipboard, and
12
+ #the SECONDARY clipboard. The clipboard you access normally via [CTRL]+[C]
13
+ #or by right-clicking and selecting "copy", is usually the CLIPBOARD clipboard (but that
14
+ #depends on the application you use). The three main methods of this module (#read, #write
15
+ #and #clear) take a list symbols of the clipboards to interact with. If you don't want to
16
+ #pass in the symbols, use the predefined read_xy, write_xy and clear_xy methods. They cannot
17
+ #access more than one clipboard at a time.
18
+ #The symbols for the clipboards are:
19
+ #[PRIMARY] :primary
20
+ #[SECONDARY] :secondary
21
+ #[CLIPBOARD] :clipboard
22
+ #You cannot store complex objects like images via this interface, only strings. However,
23
+ #you could translate an image into a string (packed pixels maybe?) and put that on the
24
+ #clipboard -- for your own application this may be fine, but it won't magically allow
25
+ #a user to paste that image into a graphics program.
26
+ #
27
+ #The +xsel+ program used by this module is quite outdated. As far as I can see, it's
28
+ #last update happened in 2002 and since I do not believe that software exists that
29
+ #won't break over a period of 8 years without a single modification while updating systems I'm about to
30
+ #switch to a newer one. +xclip+ is likely, but that one got it's last update in early
31
+ #2009...
32
+ module Clipboard
33
+
34
+ class << self
35
+
36
+ ##
37
+ # :singleton-method: read_primary
38
+ #Returns the contents of the PRIMARY clipboard.
39
+ #See #read for an explanation.
40
+
41
+ ##
42
+ # :singleton-method: read_clipboard
43
+ #Returns the contents of the CLIPBOARD clipboard.
44
+ #See #read for an explanation.
45
+
46
+ ##
47
+ # :singleton-method: read_secondary
48
+ #Returns the contents of the SECONDARY clipboard.
49
+ #See #read for an explanation.
50
+
51
+ ##
52
+ # :singleton-method: write_primary
53
+ #Writes to the PRIMARY clipboard.
54
+ #See #write for an explanation.
55
+
56
+ ##
57
+ # :singleton-method: write_clipboard
58
+ #Writes to the CLIPBOARD clipboard.
59
+ #See #write for an explanation.
60
+
61
+ ##
62
+ # :singleton-method: write_secondary
63
+ #Writes to the SECONDARY clipboard.
64
+ #See #write for an explanation.
65
+
66
+ ##
67
+ # :singleton-method: clear_primary
68
+ #Clears the PRIMARY clipboard.
69
+ #See #clear for an explanation.
70
+
71
+ ##
72
+ # :singleton-method: clear_clipboard
73
+ #Clears the CLIPBOARD clipboard.
74
+ #See #clear for an explanation.
75
+
76
+ ##
77
+ # :singleton-method: clear_secondary
78
+ #Clears the SECONDARY clipboard.
79
+ #See #clear for an explanation.
80
+
81
+ #Reads text from a X clipboard.
82
+ #===Parameters
83
+ #[<tt>*from</tt>] (<tt>:clipboard</tt>, <tt>:primary</tt>, <tt>:secondary</tt>) Specifies from which clipboards you want to read (in 70% of all cases you want to read from <tt>:clipboard</tt>).
84
+ #===Return value
85
+ #A hash of form
86
+ # {:clip_sym => "clipboard_content"}
87
+ #If you didn't pass any arguments to #read, the hash will contain keys for
88
+ #all clipboard, i.e. for <tt>:clipboard</tt>, <tt>:primary</tt> and <tt>:secondary</tt>.
89
+ #If you did, only those symbols will be included you passed. See
90
+ #the _Example_ section for an example of this.
91
+ #===Example
92
+ # XDo::Clipboard.read #| {:clipboard => "...", :primary => "...", :secondary => "..."}
93
+ # XDo::Clipboard.read(:primary) #| {:primary => "..."}
94
+ # XDo::Clipboard.read(:clipboard, :secondary) #| {clipboard => "...", :secondary => "..."}
95
+ #===Remarks
96
+ #You could also use one of the read_* methods for convenience.
97
+ def read(*from)
98
+ if from.first.kind_of? Hash
99
+ warn("#{caller.first}: Deprecation warning: Use symbols as a rest argument now!")
100
+ from = from.first.keys
101
+ end
102
+ from.concat([:clipboard, :primary, :secondary]) if from.empty?
103
+
104
+ hsh = {}
105
+ hsh[:primary] = `#{XSEL}` if from.include? :primary
106
+ hsh[:clipboard] = `#{XSEL} -b` if from.include? :clipboard
107
+ hsh[:secondary] = `#{XSEL} -s` if from.include? :secondary
108
+ hsh
109
+ end
110
+
111
+
112
+ #Writes text to a X clipboard.
113
+ #===Parameters
114
+ #[<tt>*to</tt>] (<tt>:clipboard</tt>) Specifies to what clipboards you want to wrote to.
115
+ #===Return value
116
+ #The text written.
117
+ #===Example
118
+ # XDo::Clipboard.write("I love Ruby") #You can now paste this via [CTRL] + [V]
119
+ # XDo::Clipboard.write("I love Ruby", :primary) #You can now paste this via a middle-mouse-button click
120
+ # XDo::Clipboard.write("I love Ruby", :clipboard, :primary) #Both of the above
121
+ #===Remarks
122
+ #You could also use one of the write_* methods for convenience.
123
+ def write(text, *to)
124
+ if to.first.kind_of? Hash
125
+ warn("#{caller.first}: Deprecation warning: Use symbols as a rest argument now!")
126
+ to = to.first.keys
127
+ end
128
+ to << :clipboard if to.empty?
129
+
130
+ IO.popen("xsel -i", "w"){|io| io.write(text)} if to.include? :primary
131
+ IO.popen("xsel -b -i", "w"){|io| io.write(text)} if to.include? :clipboard
132
+ IO.popen("xsel -s -i", "w"){|io| io.write(text)} if to.include? :secondary
133
+ text
134
+ end
135
+
136
+ #Appends text to a X clipboard.
137
+ #===Parameters
138
+ #[+text+] The text to append.
139
+ #[<tt>*to</tt>] (<tt>:clipboard</tt>) The clipboards to which you want to append.
140
+ #===Return value
141
+ #Undefined.
142
+ #===Example
143
+ # XDo::Clipboard.write("I love ")
144
+ # XDo::Clipboard.append("Ruby")
145
+ # puts XDo::Clipboard.read(:clipboard)[:clipboard] #=> I love Ruby
146
+ #
147
+ # XDo::Clipboard.write("I love", :primary)
148
+ # XDo::Clipboard.append("Ruby", :primary, :clipboard)
149
+ # #If you now paste via [CTRL] + [V], you'll get 'Ruby'. If you
150
+ # #paste via the middle mouse button, you'll get 'I love Ruby'
151
+ # #(Assuming you didn't execute the first block of code, of course).
152
+ def append(text, *to)
153
+ if to.first.kind_of? Hash
154
+ warn("#{caller.first}: Deprecation warning: Use symbols as a rest argument now!")
155
+ to = to.first.keys
156
+ end
157
+ to << :clipboard if to.empty?
158
+
159
+ IO.popen("xsel -a -i", "w"){|io| io.write(text)} if to.include? :primary
160
+ IO.popen("xsel -b -a -i", "w"){|io| io.write(text)} if to.include? :clipboard
161
+ IO.popen("xsel -s -a -i", "w"){|io| io.write(text)} if to.include? :secondary
162
+ end
163
+
164
+ #Clears the specified clipboards.
165
+ #===Parameters
166
+ #[<tt>*clips</tt>] (<tt>:primary</tt>, <tt>:clipboard</tt>, <tt>:secondary</tt>) The clipboards you want to clear.
167
+ #===Return value
168
+ #nil.
169
+ #===Example
170
+ # XDo::Clipboard.write("I love Ruby")
171
+ # XDo::Clipboard.clear
172
+ # #Nothing can be pasted anymore
173
+ #
174
+ # XDo::Clipboard.write("I love Ruby", :clipboard, :primary)
175
+ # XDo::Clipboard.clear(:primary)
176
+ # #You can still paste via [CTRL] + [V], but not with the middle mouse button
177
+ def clear(*clips)
178
+ if clips.first.kind_of? Hash
179
+ warn("#{caller.first}: Deprecation warning: Use symbols as a rest argument now!")
180
+ clips = clips.first.keys
181
+ end
182
+ clips.concat([:primary, :clipboard, :secondary]) if clips.empty?
183
+
184
+ `#{XSEL} -c` if clips.include? :primary
185
+ `#{XSEL} -b -c` if clips.include? :clipboard
186
+ `#{XSEL} -s -c` if clips.include? :secondary
187
+ nil
188
+ end
189
+
190
+ [:primary, :clipboard, :secondary].each do |sym|
191
+
192
+ define_method(:"read_#{sym}") do
193
+ read(sym)[sym]
194
+ end
195
+
196
+ define_method(:"write_#{sym}") do |text|
197
+ write(text, sym)
198
+ end
199
+
200
+ define_method(:"clear_#{sym}") do
201
+ clear(sym)
202
+ end
203
+
204
+ end
205
+
206
+ end
207
+ end
208
+ end