xdo 0.0.1-x86-linux

Sign up to get free protection for your applications and to get access to all the features.
@@ -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