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.
@@ -0,0 +1,416 @@
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 "open3"
6
+ require_relative("../xdo")
7
+ module XDo
8
+
9
+ #This class represents a window on the screen. Each window is uniquely identified by
10
+ #an internal ID; before you can create a reference to a window (a XWindow object) you
11
+ #have to obtain the internal ID of that window and pass it into XWindow.new.
12
+ #Or you use the class methods of this class, notably XWindow.active_window.
13
+ #
14
+ #Via the XWindow object you get you can manipulate a window in serveral ways, e.g.
15
+ #you can move or resize it. Some methods are not available on every window
16
+ #manager: XWindow.active_window, XWindow.desktop_num, XWindow.desktop_num=, XWindow.desktop,
17
+ #XWindow.desktop=, XWindow.from_active, #raise, #activate, #desktop, #desktop=.
18
+ #Some of them may be available, some not. On my machine (an Ubuntu Jaunty) for
19
+ #example I can use active_window, desktop_num and #activate, but not #raise or #desktop=.
20
+ #Those methods are tagged with the sentence "Part of the EWMH standard XY". Not all
21
+ #parts of the EWMH standard are provided by every window manager.
22
+ #
23
+ #Many methods accept a +name+ parameter; be aware that this name is not the whole
24
+ #name of a window, but a pattern to match. So, if you pass in "edit", it will even match "gedit".
25
+ #+xdotool+ handles that parameter with C style regexps.
26
+ #
27
+ #The +opt+ parameter of many methods is a hash that can have the following keys:
28
+ # Key | Effect if true
29
+ # =============+====================================
30
+ # :title | Window titles are searched.
31
+ # -------------+------------------------------------
32
+ # :name | Window names are searched.
33
+ # -------------+------------------------------------
34
+ # :class | Window classes are searched.
35
+ # -------------+------------------------------------
36
+ # :onlyvisible | Only visible windows are searched.
37
+ #The default values for them depend on the method you want to use. See the method's
38
+ #argument list to find out if a parameter is set to true or, if it isn't mentioned, to nil.
39
+ #
40
+ #Be <i>very careful</i> with the methods that are part of the two desktop EWMH standards.
41
+ #After I set the number of desktops and changed the current desktop, I had to reboot my
42
+ #system to get the original configuration back. I don't know if I'm not using +xdotool+ correct,
43
+ #but neither my library nor +xdotool+ itself could rescue my desktop settings. Btw, that's the
44
+ #reason why it's not in XDo's unit tests (but it should work; at least in one way...).
45
+ class XWindow
46
+ include Open3
47
+ #The internal ID of the window.
48
+ attr_reader :id
49
+
50
+ class << self
51
+ include Open3
52
+ #Checks if a window whose name matches +name+ exists.
53
+ #Think about passing :onlyvisible in the +opt+ hash.
54
+ def exists?(name, opts = {title: true, name: true, :class => true})
55
+ begin
56
+ !search(name, opts).empty?
57
+ rescue
58
+ false
59
+ end
60
+ end
61
+
62
+ #Returns true if the given window ID exists, false otherwise.
63
+ def id_exists?(id)
64
+ err = ""
65
+ popen3("#{XDo::XWININFO} -id #{id}"){|stdin, stdout, stderr| err << stderr.read}
66
+ return false unless err.empty?
67
+ return true
68
+ end
69
+
70
+ #Waits for a window name to exist and returns the ID of that window.
71
+ #Returns immediately if the window does already exist.
72
+ def wait_for_window(name, opts = {title: true, name: true, :class => true, :onlyvisible => true})
73
+ loop{break if exists?(name, opts);sleep(0.5)}
74
+ sleep 1 #To ensure it's really there
75
+ search(name, opts).first
76
+ end
77
+
78
+ #Waits for a window to close. If the window does not exists when calling +wait_for_close+,
79
+ #the method returns immediately.
80
+ def wait_for_close(name, opts = {title: true, name: true, :class => true, :onlyvisible => true})
81
+ loop{break if !exists?(name, opts);sleep(0.5)}
82
+ nil
83
+ end
84
+
85
+ #Search for a window name to get the internal ID of a window.
86
+ #Return value is an array containing all found IDs or an
87
+ #empty array if none is found.
88
+ def search(name, opts = {title: true, name: true, :class => true})
89
+ cmd = "#{XDo::XDOTOOL} search "
90
+ opts.each_pair{|key, value| cmd << "--#{key} " if value}
91
+ cmd << '"' << name << '"'
92
+ #Error wird nicht behandelt, weil im Fehlerfall einfach nur ein leeres Array zurückkommen soll
93
+ out = `#{cmd}`
94
+ out.lines.to_a.collect{|l| l.strip.to_i}
95
+ end
96
+
97
+ #Returns the internal ID of the currently focused window.
98
+ #If the +notice_childs+ parameter is true, also childwindows
99
+ #are noticed. This method may find an invisible window, see
100
+ #active_window for a more reliable method.
101
+ def focused_window(notice_childs = false)
102
+ err = ""
103
+ out = ""
104
+ popen3("#{XDo::XDOTOOL} getwindowfocus #{notice_childs ? "-f" : ""}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
105
+ raise(XDo::XError, err) unless err.empty?
106
+ return out.to_i
107
+ end
108
+
109
+ #Returns the internal ID of the currently focused window.
110
+ #This method is more reliable than focused_window.
111
+ #Part of the EWMH standard ACTIVE_WINDOW.
112
+ def active_window
113
+ err = ""
114
+ out = ""
115
+ popen3("#{XDo::XDOTOOL} getactivewindow"){|stdin, stdout, stderr| out = stdout.read; err = stderr.read}
116
+ raise(XDo::XError, err) unless err.empty?
117
+ return Integer(out)
118
+ end
119
+
120
+ #Set the number of working desktops.
121
+ #Part of the EWMH standard WM_DESKTOP.
122
+ def desktop_num=(num)
123
+ err = ""
124
+ popen3("#{XDo::XDOTOOL} set_num_desktops #{num}"){|stdin, stdout, stderr| err << stderr.read}
125
+ raise(XDo::Error, err) unless err.empty?
126
+ num
127
+ end
128
+
129
+ #Get the number of working desktops.
130
+ #Part of the EWMH standard WM_DESKTOP.
131
+ def desktop_num
132
+ err = ""
133
+ out = ""
134
+ popen3("#{XDo::XDOTOOL} get_num_desktops"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
135
+ raise(XDo::XError, err) unless err.empty?
136
+ Integer(out)
137
+ end
138
+
139
+ #Change the view to desktop +num+.
140
+ #Part of the EWMH standard CURRENT_DESKTOP.
141
+ def desktop=(num)
142
+ err = ""
143
+ popen3("#{XDo::XDOTOOL} set_desktop #{num}"){|stdin, stdout, stderr| err << stderr.read}
144
+ raise(XDo::XError, err) unless err.empty?
145
+ num
146
+ end
147
+
148
+ #Output the number of the active desktop.
149
+ #Part of the EWMH standard CURRENT_DESKTOP.
150
+ def desktop
151
+ err = ""
152
+ out = ""
153
+ popen3("#{XDo::XDOTOOL} get_desktop"){|stdin, stdout, stderr| out = stdout.read; err = stderr.read}
154
+ raise(XDo::XError, err) unless err.empty?
155
+ Integer(out)
156
+ end
157
+
158
+ #Creates a XWindow by calling search with the given parameters.
159
+ #The window is created from the first ID found.
160
+ def from_name(name, opts = {title: true, name: true, :class => true})
161
+ ids = search(name, opts)
162
+ raise(XDo::XError, "The window '#{name}' wasn't found!") if ids.empty?
163
+ new(ids.first)
164
+ end
165
+
166
+ #Creates a XWindow by calling focused_window with the given parameter.
167
+ def from_focused(notice_childs = false)
168
+ new(focused_window(notice_childs))
169
+ end
170
+
171
+ #Creates a XWindow by calling active_window.
172
+ def from_active
173
+ new(active_window)
174
+ end
175
+
176
+ #Set this to the name of your desktop window.
177
+ def desktop_name=(name)
178
+ @desktop_name = name
179
+ end
180
+
181
+ #Name of the desktop window. Default is "x-nautilus-desktop".
182
+ def desktop_name
183
+ @desktop_name ||= "x-nautilus-desktop"
184
+ end
185
+
186
+ #Activate the desktop
187
+ def focus_desktop
188
+ desktop = from_name(desktop_name)
189
+ desktop.focus
190
+ desktop.activate
191
+ end
192
+ alias activate_desktop focus_desktop
193
+
194
+ #Minimize all windows (or restore, if already) by sending [CTRL]+[ALT]+[D].
195
+ #Available after requireing "xdo/keyboard".
196
+ def toggle_minimize_all
197
+ raise(NotImplementedError, "You have to require 'xdo/keyboard' before you can use #{__method__}!") unless defined? XDo::Keyboard
198
+ XDo::Keyboard.ctrl_alt_d
199
+ end
200
+
201
+ #Minimizes the active window. There's no way to restore a specific minimized window.
202
+ #Available after requireing "xdo/keyboard".
203
+ def minimize
204
+ raise(NotImplementedError, "You have to require 'xdo/keyboard' before you can use #{__method__}!") unless defined? XDo::Keyboard
205
+ XDo::Keyboard.key("Alt+F9")
206
+ end
207
+
208
+ #Maximize or normalize the active window if already maximized.
209
+ #Available after requireing "xdo/keyboard".
210
+ def toggle_maximize
211
+ raise(NotImplementedError, "You have to require 'xdo/keyboard' before you can use #{__method__}!") unless defined? XDo::Keyboard
212
+ XDo::Keyboard.key("Alt+F10")
213
+ end
214
+
215
+ end
216
+
217
+ #Creates a new XWindow object from an internal ID. See the XWindow class methods.
218
+ def initialize(id)
219
+ @id = id.to_i
220
+ end
221
+
222
+ #Human-readable output of form
223
+ # <XDo::XWindow: "title" (window_id)>
224
+ def inspect
225
+ %Q|<XDo::XWindow: "#{title}" (#{id})>|
226
+ end
227
+
228
+ #Set the size of a window. This has no effect on maximized winwows.
229
+ def resize(width, height, use_hints = false)
230
+ err = ""
231
+ cmd = "#{XDo::XDOTOOL} windowsize #{use_hints ? "--usehints " : ""}#{@id} #{width} #{height}"
232
+ popen3("#{cmd}"){|stdin, stdout, stderr| err << stderr.read}
233
+ Kernel.raise(XDo::XError, err) unless err.empty?
234
+ end
235
+
236
+ #Moves a window. +xdotool+ is not really exact with the coordinates,
237
+ #the window will be within a range of +-10 pixels.
238
+ def move(x, y)
239
+ err = ""
240
+ popen3("#{XDo::XDOTOOL} windowmove #{@id} #{x} #{y}"){|stdin, stdout, stderr| err << stderr.read}
241
+ Kernel.raise(XDo::XError, err) unless err.empty?
242
+ end
243
+
244
+ #Set the input focus to the window (but don't bring it to the front).
245
+ def focus
246
+ err = ""
247
+ popen3("#{XDo::XDOTOOL} windowfocus #{@id}"){|stdin, stdout, stderr| err << stderr.read}
248
+ Kernel.raise(XDo::XError, err) unless err.empty?
249
+ end
250
+
251
+ #The window loses the input focus by setting it to the desktop.
252
+ def unfocus
253
+ XDo::XWindow.focus_desktop
254
+ end
255
+
256
+ #Map a window to the screen (make it visible).
257
+ def map
258
+ err = ""
259
+ popen3("#{XDo::XDOTOOL} windowmap #{@id}"){|stdin, stdout, stderr| err << stderr.read}
260
+ Kernel.raise(XDo::XError, err) unless err.empty?
261
+ end
262
+
263
+ #Unmap a window from the screen (make it invisible).
264
+ def unmap
265
+ err = ""
266
+ popen3("#{XDo::XDOTOOL} windowunmap #{@id}"){|stdin, stdout, stderr| err << stderr.read}
267
+ Kernel.raise(XDo::XError, err) unless err.empty?
268
+ end
269
+
270
+ #Bring a window to the front (but don't give it the input focus).
271
+ #Not implemented in all window managers.
272
+ def raise
273
+ err = ""
274
+ popen3("#{XDo::XDOTOOL} windowraise #{@id}"){|stdin, stdout, stderr| err << stderr.read}
275
+ raise(XDo::XError, err) unless err.empty?
276
+ end
277
+
278
+ #Activate a window. That is, bring it to top and give it the input focus.
279
+ #Part of the EWMH standard ACTIVE_WINDOW.
280
+ def activate
281
+ err = ""
282
+ popen3("#{XDo::XDOTOOL} windowactivate #{@id}"){|stdin, stdout, stderr| err << stderr.read}
283
+ Kernel.raise(XDo::XError, err) unless err.empty?
284
+ end
285
+
286
+ #Move a window to a desktop.
287
+ #Part of the EWMH standard CURRENT_DESKTOP.
288
+ def desktop=(num)
289
+ err = ""
290
+ popen3("#{XDo::XDOTOOL} set_desktop_for_window #{@id} #{num}"){|stdin, stdout, stderr| err << stderr.read}
291
+ Kernel.raise(XDo::XError, err) unless err.empty?
292
+ end
293
+
294
+ #Get the desktop the window is on.
295
+ #Part of the EWMH standard CURRENT_DESKTOP.
296
+ def desktop
297
+ err = ""
298
+ out = ""
299
+ popen3("#{XDo::XDOTOOL} get_desktop_for_window #{@id}"){|stdin, stdout, stderr| out = stdout.read; err << stderr.read}
300
+ Kernel.raise(XDo::XError, err) unless err.empty?
301
+ Integer(out)
302
+ end
303
+
304
+ #The title of the window or nil if it doesn't have a title.
305
+ def title
306
+ err = ""
307
+ out = ""
308
+ popen3("#{XDo::XWININFO} -id #{@id}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
309
+ Kernel.raise(XDo::XError, err) unless err.empty?
310
+ title = out.strip.lines.to_a[0].match(/"(.*)"/)[1] rescue Kernel.raise(XDo::XError, "No window with ID #{@id} found!")
311
+ return title #Kann auch nil sein, dann ist das Fenster namenlos.
312
+ end
313
+
314
+ #The absolute position of the window on the screen.
315
+ def abs_position
316
+ out = ""
317
+ err = ""
318
+ popen3("#{XDo::XWININFO} -id #{@id}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
319
+ Kernel.raise(XDo::XError, err) unless err.empty?
320
+ out = out.strip.lines.to_a
321
+ x = out[2].match(/:\s+(\d+)/)[1]
322
+ y = out[3].match(/:\s+(\d+)/)[1]
323
+ [x.to_i, y.to_i]
324
+ end
325
+ alias position abs_position
326
+
327
+ #The position of the window relative to it's parent window.
328
+ def rel_position
329
+ out = ""
330
+ err = ""
331
+ popen3("#{XDo::XWININFO} -id #{@id}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
332
+ Kernel.raise(XDo::XError, err) unless err.empty?
333
+ out = out.strip.lines.to_a
334
+ x = out[4].match(/:\s+(\d+)/)[1]
335
+ y = out[5].match(/:\s+(\d+)/)[1]
336
+ [x.to_i, y.to_i]
337
+ end
338
+
339
+ #The size of the window.
340
+ def size
341
+ out = ""
342
+ err = ""
343
+ popen3("#{XDo::XWININFO} -id #{@id}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
344
+ out = out.strip.lines.to_a
345
+ Kernel.raise(XDo::XError, err) unless err.empty?
346
+ width = out[6].match(/:\s+(\d+)/)[1]
347
+ height = out[7].match(/:\s+(\d+)/)[1]
348
+ [width.to_i, height.to_i]
349
+ end
350
+
351
+ #true if the window is mapped to the screen.
352
+ def visible?
353
+ err = ""
354
+ out = ""
355
+ popen3("#{XDo::XWININFO} -id #{@id}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
356
+ out = out.strip.lines.to_a
357
+ Kernel.raise(XDo::XError, err) unless err.empty?
358
+ return out[17].match(/:\s+(\w+)/)[1] == "IsViewable" ? true : false
359
+ end
360
+
361
+ #Returns true if the window exists.
362
+ def exists?
363
+ XDo::XWindow.exists?(@id)
364
+ end
365
+
366
+ #Closes a window by activating it and then sending [ALT] + [F4].
367
+ #A program could ask to save data.
368
+ #Use #kill! to kill the process running the window.
369
+ #Available after requireing "xdo/keyboard"
370
+ def close
371
+ raise(NotImplementedError, "You have to require 'xdo/keyboard' before you can use #{__method__}!") unless defined? XDo::Keyboard
372
+ activate
373
+ sleep 0.5
374
+ XDo::Keyboard.char("Alt+F4")
375
+ sleep 0.5
376
+ nil
377
+ end
378
+
379
+ #More aggressive variant of #close. Think of +close!+ as
380
+ #the middle between #close and #kill!. It first tries
381
+ #to close the window by calling #close and if that
382
+ #does not succeed (within +timeout+ seconds), it will call #kill!.
383
+ #Available after requireing "xdo/keyboard".
384
+ def close!(timeout = 2)
385
+ raise(NotImplementedError, "You have to require 'xdo/keyboard' before you can use #{__method__}!") unless defined? XDo::Keyboard
386
+ #Try to close normally
387
+ close
388
+ #Check if it's deleted
389
+ if exists?
390
+ #If not, wait some seconds and then check again
391
+ sleep timeout
392
+ if exists?
393
+ #If it's not deleted after some time, force it to close.
394
+ kill!
395
+ else
396
+ return
397
+ end
398
+ else
399
+ return
400
+ end
401
+ end
402
+
403
+ #Kills the process that runs a window. The window will be
404
+ #terminated immediatly, if that isn't what you want, have
405
+ #a look at #close.
406
+ def kill!
407
+ out = ""
408
+ err = ""
409
+ popen3("#{XDo::XKILL} -id #{@id}"){|stdin, stdout, stderr| out << stdout.read; err << stderr.read}
410
+ Kernel.raise(XDo::XError, err) unless err.empty?
411
+ nil
412
+ end
413
+
414
+ end
415
+
416
+ end
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env ruby
2
+ #Encoding: UTF-8
3
+ #--
4
+ #This file is part of XDo. Copyright © 2009 by Marvin Gülker.
5
+ #XDo is published under Ruby's license. See http://www.ruby-lang.org/en/LICENSE.txt
6
+ # Initia in potestate nostra sunt, de eventu fortuna iudicat.
7
+ #++
8
+
9
+ =begin
10
+ This is the full XDo demo. We will create a
11
+ command-line program that will be able to open
12
+ and close the default CD drive, open gedit and
13
+ type some text in tabular form and click the
14
+ "show desktop" button in the lower-left corner of
15
+ the Ubuntu desktop. Even if you don't use Ubuntu,
16
+ you may get the logic and find this demo useful.
17
+
18
+ Every OS and even every computer are different in their
19
+ user interface. If you'd like to add sample files for a
20
+ specific OS, feel free to contact me at sutniuq ät gmx Dot net.
21
+ =end
22
+
23
+ #First, require all Xdo files.
24
+ require "xdo/clipboard"
25
+ require "xdo/drive"
26
+ require "xdo/keyboard"
27
+ require "xdo/mouse"
28
+ require "xdo/xwindow"
29
+
30
+ class XXX
31
+
32
+ def keyboard
33
+ #Make sure gedit is not running, since it would open
34
+ #a new tab and not a new window if invoked again.
35
+ raise(RuntimeError, "gedit is already running; please close it before using.") unless XDo::XWindow.search("gedit").empty?
36
+ #If we would use system in the main program to open
37
+ #gedit, it would hang until gedit is closed. That's why
38
+ #we run it in a separate process.
39
+ fork{system("gedit")}
40
+ #Now we wait until gedit has made up its GUI.
41
+ #wait_for_window returns the ID of the found window, so
42
+ #we catch it and...
43
+ id = XDo::XWindow.wait_for_window("gedit")
44
+ #...use it to create a new reference to gedit's window.
45
+ #Note that this is a pseudo reference, not a real one.
46
+ #XDo allows you to create references even to unexisting
47
+ #windows, so the X window manager will not recognize
48
+ #the pseudo reference. You can check if the window
49
+ #you're looking for exists by calling #exists? on the
50
+ #XWindow object.
51
+ xwin = XDo::XWindow.new(id)
52
+ #Now we move it 20 pixels right and 10 down.
53
+ xwin.move(xwin.position[0] + 20, xwin.position[1] + 10)
54
+ #After having fun with it, let's do something useful.
55
+ #XDo::Keyboard.simulate fakes keystrokes and recognizes
56
+ #special escape sequences in braces { and }. For some
57
+ #special characters like tab you can use an ASCII escape
58
+ #like \t. The most special keys like [ESC] don't have
59
+ #those a shortcut, so you will have to write {ESC} in
60
+ #order to send them.
61
+ XDo::Keyboard.simulate("This will be some test text.")
62
+ XDo::Keyboard.ctrl_a
63
+ XDo::Keyboard.delete #This will send a BackSpace keypress. If you want a DEL, pass in true as a parameter.
64
+ #I promised at the beginning, we were goint to create data in tabular form,
65
+ #so here it is:
66
+ XDo::Keyboard.type("Percentage of smokers in different jobs in Germany".upcase) #type is usually faster than simulate if the text doesn't contain special characters or escape sequences
67
+ 2.times{XDo::Keyboard.return} #Return is the Enter key
68
+ #Set up the data
69
+ headings = ["Job", "Percentage"]
70
+ data = [
71
+ ["Judge", 28],
72
+ ["Architect", 29],
73
+ ["Doctor", 30],
74
+ ["Nurse", 45],
75
+ ["Teacher", 53]
76
+ ]
77
+ #Create the table headings
78
+ str =""
79
+ headings[0..-2].each{|h| str << h << "{TAB}{TAB}"}
80
+ str << headings[-1] << "\n"#No tab after the last heading
81
+ #Type the heading
82
+ XDo::Keyboard.simulate(str)
83
+ #Make a line between the heading and the data
84
+ XDo::Keyboard.type("=" * 30)
85
+ XDo::Keyboard.return
86
+ #Write the table data
87
+ data.each do |job, percentage|
88
+ #Insert tabs. If a word is longer than 8 (the normal tab size), don't append a second tab.
89
+ XDo::Keyboard.simulate("#{job}#{job.length > 8 ? "\t" : "\t\t"}#{percentage}\n") #\t will trigger the Tab key, \n the Return key.
90
+ end
91
+ #Oh yes, and save it of course. XDo::Keyboard tries to
92
+ #send every method name as a key combination if the
93
+ #method is not defined already. The method name
94
+ #will be capitalized and every underscore _ replaced
95
+ #by a + (that's internally important to combine keys).
96
+ File.delete("#{ENV["HOME"]}/testXDo.txt") if File.file? "#{ENV["HOME"]}/testXDo.txt" #This is the file we'll save to
97
+ XDo::Keyboard.ctrl_s
98
+ #Wait for the save window to exist. I can't use wait_for_window here, since
99
+ #it's named different in every language. Me as a German user have a title
100
+ #of "Speichern unter...", an english OS may show "Save as...".
101
+ sleep 1
102
+ #You really shouldn't try to simulate the ~ sign. xdotool seems to have a bug, so
103
+ #~ can't be simulated with one command. My library tries to simulate it with one
104
+ #command and it sometimes works, but you mustn't rely on it. Therefore I use
105
+ #the HOME environment variable here to get the home directory, rather than ~.
106
+ XDo::Keyboard.simulate("#{ENV["HOME"]}/testXDo.txt")
107
+ sleep 1 #gedit terminates if send [ALT]+[A] immediatly after the path
108
+ XDo::Keyboard.alt_s
109
+ #Now, let's duplicate our table. We could send all the stuff again,
110
+ #but I want to introduce you in the use of the X clipboard.
111
+ #First, we have to mark our text in order to be copied to the clipboard:
112
+ xwin.activate #After saving the window isn't active anymore
113
+ sleep 1 #Wait for the gedit window to be active again
114
+ XDo::Keyboard.ctrl_a
115
+ #Then copy it to the clipboard (you see, it's quite useful to know keyboard shortcuts)
116
+ XDo::Keyboard.ctrl_c
117
+ #gedit copies, like the most programs, it's data to the CLIPBOARD clipboard.
118
+ #There are two other clipboard, PRIMARY and SECONDARY, but we won't
119
+ #diskuss them here. If you are sure you've copied data to the clipboard and
120
+ ##read_clipboard doesn't find anything, check out #read_primary and #read_secondary.
121
+ #Also note, that XDo can only handle plain text data.
122
+ cliptext = XDo::Clipboard.read_clipboard
123
+ #Move to the end of the text
124
+ XDo::Keyboard.simulate("{DOWN}" * 9)
125
+ XDo::Keyboard.simulate("{END}")
126
+ #Since #simulate interprets \t correctly as a tab, we can simply put
127
+ #the clipboard's text in that method:
128
+ XDo::Keyboard.simulate("\n#{cliptext}") #Begin a new line before inserting the duplicate
129
+ sleep 1
130
+ XDo::Keyboard.ctrl_s
131
+ #Give some time to see the result
132
+ sleep 5
133
+ #Than close gedit. There are three methods to close a window,
134
+ ##close, #close! and #kill!. #close is like sending an [ALT]+[F4] keypress which may result in
135
+ #a dialog box asking you for confimation. #close! is a bit stronger. First it calls #close and waits
136
+ #a few seconds (you can specify how long exactly) then shuts down the window process. What
137
+ #leads us to the third method: #kill!. Be sure to call #kill! only on windows you know -
138
+ #it kills the process of a window by sending SIGTERM first and then SIGKILL. I've not tried
139
+ #what happens if you send this to the desktop window, but if you like to...
140
+ xwin.close #We use the normal #close here since we saved our data and gedit shouldn't complain.
141
+ end
142
+
143
+ def mouse
144
+ #Assuming that the first entry of your right-click menu is "Create folder",
145
+ #you can create new folders on your desktop.
146
+ XDo::XWindow.toggle_minimize_all
147
+ sleep 2
148
+
149
+ #Mouse.click is the method for executing mouse clicks. If you call it
150
+ #without any arguments, it will execute a left click on the current cursor position.
151
+ XDo::Mouse.click(400, 400, XDo::Mouse::RIGHT)
152
+ sleep 1 #Give the menu time to appear
153
+ XDo::Mouse.click
154
+ sleep 1 #Wait for the folder to be created
155
+ #Give it a name
156
+ XDo::Keyboard.simulate("A test folder\n") # Return to confirm
157
+ sleep 1 #Wait to accept the name
158
+ #Move the folder icon a bit upwards
159
+ XDo::Mouse.drag(nil, nil, 400, 200)
160
+ sleep 2
161
+ XDo::XWindow.toggle_minimize_all #Restore all windows
162
+ end
163
+
164
+ end
165
+
166
+ USAGE =<<USAGE
167
+ USAGE:
168
+ ./full_demo.rb [methodname]
169
+
170
+ Executes the full_demo XDo demo file. You can optionally provide a method
171
+ name, if you don't, both methods will be run.
172
+ USAGE
173
+
174
+ if ARGV.include?("-h") or ARGV.include?("--help")
175
+ puts USAGE
176
+ end
177
+
178
+ xxx = XXX.new
179
+ if ARGV.empty?
180
+ xxx.keyboard
181
+ sleep 3
182
+ xxx.mouse
183
+ elsif ARGV[0] == "mouse"
184
+ xxx.mouse
185
+ elsif ARGV[0] == "keyboard"
186
+ xxx.keyboard
187
+ else
188
+ puts USAGE
189
+ end