terminitor 0.4.1 → 0.5.0
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/Gemfile.lock +2 -4
- data/LICENSE +20 -0
- data/README.md +31 -4
- data/lib/terminitor.rb +12 -1
- data/lib/terminitor/abstract_core.rb +17 -6
- data/lib/terminitor/capture/cmd_capture.rb +7 -0
- data/lib/terminitor/capture/terminator_capture.rb +9 -0
- data/lib/terminitor/cli.rb +13 -2
- data/lib/terminitor/cores/cmd_core/cmd_core.rb +35 -0
- data/lib/terminitor/cores/cmd_core/input.rb +273 -0
- data/lib/terminitor/cores/cmd_core/windows_console.rb +83 -0
- data/lib/terminitor/cores/terminator_core.rb +117 -0
- data/lib/terminitor/dsl.rb +29 -12
- data/lib/terminitor/runner.rb +48 -14
- data/lib/terminitor/version.rb +1 -1
- data/lib/terminitor/yaml.rb +2 -0
- data/terminitor.gemspec +21 -10
- data/test.watchr +9 -5
- data/test/capture/mac_capture_test.rb +2 -6
- data/test/cli_test.rb +54 -22
- data/test/cores/cmd_core_test.rb +51 -0
- data/test/cores/iterm_core_test.rb +2 -5
- data/test/cores/konsole_core_test.rb +1 -1
- data/test/cores/mac_core_test.rb +12 -11
- data/test/cores/terminator_core_test.rb +39 -0
- data/test/dsl_test.rb +79 -25
- data/test/runner_test.rb +47 -24
- data/test/teststrap.rb +15 -7
- metadata +31 -87
- data/templates/example.yml.tt +0 -16
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
terminitor (0.4.
|
4
|
+
terminitor (0.4.1)
|
5
5
|
github (~> 0.6.0)
|
6
6
|
rb-appscript
|
7
7
|
text-format (= 1.0.0)
|
@@ -25,11 +25,9 @@ GEM
|
|
25
25
|
rake (>= 0.8.1)
|
26
26
|
rake (0.8.7)
|
27
27
|
rb-appscript (0.6.0)
|
28
|
-
riot (0.12.
|
28
|
+
riot (0.12.2)
|
29
29
|
rr
|
30
|
-
term-ansicolor
|
31
30
|
rr (1.0.2)
|
32
|
-
term-ansicolor (1.0.5)
|
33
31
|
text-format (1.0.0)
|
34
32
|
text-hyphen (~> 1.0.0)
|
35
33
|
text-hyphen (1.0.0)
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Arthur Chiu
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,7 +1,16 @@
|
|
1
1
|
Terminitor
|
2
2
|
===========
|
3
3
|
|
4
|
-
Terminitor automates your development workflow setup. Less time setting up,
|
4
|
+
Terminitor automates your development workflow setup. Less time setting up, more time getting things done.
|
5
|
+
|
6
|
+
Upgrading Terminitor from 0.4.1 and under
|
7
|
+
------------------------------------------
|
8
|
+
|
9
|
+
For those upgrading from Terminitor 0.4.1, please run:
|
10
|
+
|
11
|
+
$ terminitor update
|
12
|
+
|
13
|
+
This will move your terminitor files to the new directory located at .config/terminitor
|
5
14
|
|
6
15
|
Installation
|
7
16
|
------------
|
@@ -45,7 +54,7 @@ This will open your default editor (set through the $TERM_EDITOR or $EDITOR vari
|
|
45
54
|
|
46
55
|
#### YAML Syntax ( Legacy ) ####
|
47
56
|
|
48
|
-
# ~/.terminitor/foo.yml
|
57
|
+
# ~/.config/terminitor/foo.yml
|
49
58
|
# you can make as many tabs as you wish...
|
50
59
|
# tab names are actually arbitrary at this point too.
|
51
60
|
---
|
@@ -208,7 +217,7 @@ __windows__
|
|
208
217
|
|
209
218
|
### Running Terminitor Projects ###
|
210
219
|
|
211
|
-
Once the project file has been declared to your satisfaction, simply execute any project defined in the `~/.terminitor` directory with:
|
220
|
+
Once the project file has been declared to your satisfaction, simply execute any project defined in the `~/.config/terminitor` directory with:
|
212
221
|
|
213
222
|
$ terminitor start foo
|
214
223
|
|
@@ -296,6 +305,7 @@ Cores allow Terminitor to operate on a variety of platforms. They abstract the g
|
|
296
305
|
|
297
306
|
* MacCore - Mac OS X Terminal
|
298
307
|
* KonsoleCore - KDE Konsole
|
308
|
+
* TerminatorCore - [Terminator](http://www.tenshu.net/terminator/)
|
299
309
|
* ITermCore - Mac OS X iTerm
|
300
310
|
|
301
311
|
Feel free to contribute more cores so that Terminitor can support your terminal of choice :)
|
@@ -326,6 +336,19 @@ The fetch task only pulls off Github repositories at the moment. Later on, this
|
|
326
336
|
This feature is currently only available in Mac OS X at the moment.
|
327
337
|
|
328
338
|
|
339
|
+
#### Terminator support ####
|
340
|
+
|
341
|
+
This feature currently requires the "xdotool" utility to be installed and in
|
342
|
+
the search path. The xdotool homepage is
|
343
|
+
http://www.semicomplete.com/blog/projects/xdotool/.
|
344
|
+
|
345
|
+
|
346
|
+
#### Windows suppport ####
|
347
|
+
|
348
|
+
Windows support is currently limited to plain cmd.exe. It is also
|
349
|
+
limited to only creating new windows, as cmd.exe does not support tabs.
|
350
|
+
|
351
|
+
|
329
352
|
Authors
|
330
353
|
-------
|
331
354
|
|
@@ -338,12 +361,16 @@ Contributors
|
|
338
361
|
Thanks to the following people for their contributions so far:
|
339
362
|
|
340
363
|
* Pat George ([pcg79](https://github.com/pcg79)) for contributing a patch for when a project is not found.
|
364
|
+
* Tim Gossett ([[MrGossett](https://github.com/MrGossett)) for a patch to fix comment reading
|
341
365
|
* Flavio Castelli ([flavio](https://github.com/flavio)) for contributing Konsole(KDE) core.
|
342
366
|
* Alexey Kuleshov ([kulesa](https://github.com/kulesa)) for contributing the terminal settings and terminal settings capture functionality
|
343
367
|
* Arthur Gunn ([gunn](https://github.com/gunn)) for contributing a path to support tab syntax and load path.
|
344
368
|
* Elliot Winkler ([mcmire](https://github.com/mcmire)) for adding 1.8.6 compatiblity and ensuring tabs open in order.
|
345
369
|
* Justin Hilemen ([bobthecow](https://github.com/bobthecow)) for fixing the list command to remove the term extensions.
|
346
|
-
*
|
370
|
+
* Dave Perrett ([recurser](https://github.com/recurser)) for adding basic iTerm support.
|
371
|
+
* Ilkka Laukkanen ([ilkka](https://github.com/achiu/terminitor/commits/master?author=ilkka)) for Terminator core and other fixes
|
372
|
+
* Elia Schito ([elia](https://github.com/achiu/terminitor/commits/master?author=elia)) for patch to allow usage of "&" for background operations
|
373
|
+
* Dotan J. Nahum ([[jondot](https://github.com/jondot)) for adding windows(cmd.exe) support
|
347
374
|
|
348
375
|
Acknowledgements
|
349
376
|
-----------------
|
data/lib/terminitor.rb
CHANGED
@@ -20,6 +20,17 @@ module Terminitor
|
|
20
20
|
when %r{linux}
|
21
21
|
require 'dbus'
|
22
22
|
autoload :KonsoleCore, 'terminitor/cores/konsole_core'
|
23
|
-
autoload :KonsoleCapture, 'terminitor/capture/konsole_capture'
|
23
|
+
autoload :KonsoleCapture, 'terminitor/capture/konsole_capture'
|
24
|
+
autoload :TerminatorCore, 'terminitor/cores/terminator_core'
|
25
|
+
autoload :TerminatorCapture, 'terminitor/capture/terminator_capture'
|
26
|
+
when %r{mswin|mingw}
|
27
|
+
require 'windows/process'
|
28
|
+
require 'windows/handle'
|
29
|
+
require 'win32/process'
|
30
|
+
require 'windows/window'
|
31
|
+
|
32
|
+
require 'terminitor/cores/cmd_core/input'
|
33
|
+
require 'terminitor/cores/cmd_core/windows_console'
|
34
|
+
autoload :CmdCore, 'terminitor/cores/cmd_core/cmd_core'
|
24
35
|
end
|
25
36
|
end
|
@@ -4,6 +4,7 @@ module Terminitor
|
|
4
4
|
attr_accessor :terminal, :windows, :working_dir, :termfile
|
5
5
|
|
6
6
|
# set the terminal object, windows, and load the Termfile.
|
7
|
+
# @param [String] path to termfile
|
7
8
|
def initialize(path)
|
8
9
|
@termfile = load_termfile(path)
|
9
10
|
end
|
@@ -26,6 +27,9 @@ module Terminitor
|
|
26
27
|
|
27
28
|
# this command will run commands in the designated window
|
28
29
|
# run_in_window 'window1', {:tab1 => ['ls','ok']}
|
30
|
+
# @param [String] name of window
|
31
|
+
# @param [Hash] Hash of window's content extracted from Termfile
|
32
|
+
# @param [Hash] Hash of options
|
29
33
|
def run_in_window(window_name, window_content, options = {})
|
30
34
|
window_options = window_content[:options]
|
31
35
|
first_tab = true
|
@@ -44,19 +48,22 @@ module Terminitor
|
|
44
48
|
else
|
45
49
|
tab = ( tab_key == 'default' ? active_window : open_tab(tab_options) ) # give us the current window if its default, else open a tab.
|
46
50
|
end
|
47
|
-
|
48
|
-
tab_content[:commands].insert(0,
|
49
|
-
|
51
|
+
# append our before block commands.
|
52
|
+
tab_content[:commands].insert(0, window_content[:before]).flatten! if window_content[:before]
|
53
|
+
# clean up prompt
|
54
|
+
tab_content[:commands].insert(0, 'clear') if tab_name || !@working_dir.to_s.empty?
|
55
|
+
# add title to tab
|
56
|
+
tab_content[:commands].insert(0, "PS1=$PS1\"\\e]2;#{tab_name}\\a\"") if tab_name
|
50
57
|
tab_content[:commands].insert(0, "cd \"#{@working_dir}\"") unless @working_dir.to_s.empty?
|
51
|
-
tab_content[:commands].each
|
52
|
-
execute_command(cmd, :in => tab)
|
53
|
-
end
|
58
|
+
tab_content[:commands].each { |cmd| execute_command(cmd, :in => tab) }
|
54
59
|
end
|
55
60
|
set_delayed_options
|
56
61
|
end
|
57
62
|
|
58
63
|
# Loads commands via the termfile and returns them as a hash
|
59
64
|
# if it matches legacy yaml, parse as yaml, else use new dsl
|
65
|
+
# @param [String] path to termfile
|
66
|
+
# @return [Hash] returns a hash containing termfile details
|
60
67
|
def load_termfile(path)
|
61
68
|
File.extname(path) == '.yml' ? Terminitor::Yaml.new(path).to_hash : Terminitor::Dsl.new(path).to_hash
|
62
69
|
end
|
@@ -67,11 +74,14 @@ module Terminitor
|
|
67
74
|
|
68
75
|
# Executes the Command
|
69
76
|
# should use the :in key to interact with terminal object.
|
77
|
+
# @param [String] command to be ran.
|
78
|
+
# @param [Hash] options hash
|
70
79
|
# execute_command 'cd /path/to', {:in => #<TerminalObject>}
|
71
80
|
def execute_command(cmd, options = {})
|
72
81
|
end
|
73
82
|
|
74
83
|
# Opens a new tab and returns itself.
|
84
|
+
# @param [Hash] options hash.
|
75
85
|
def open_tab(options = nil)
|
76
86
|
@working_dir = Dir.pwd # pass in current directory.
|
77
87
|
end
|
@@ -81,6 +91,7 @@ module Terminitor
|
|
81
91
|
end
|
82
92
|
|
83
93
|
# Opens a new window and returns the tab object.
|
94
|
+
# @param [Hahs] options hash.
|
84
95
|
def open_window(options = nil)
|
85
96
|
@working_dir = Dir.pwd # pass in current directory.
|
86
97
|
end
|
data/lib/terminitor/cli.rb
CHANGED
@@ -29,14 +29,14 @@ module Terminitor
|
|
29
29
|
desc "list", "lists all terminitor scripts"
|
30
30
|
def list
|
31
31
|
say "Global scripts: \n"
|
32
|
-
Dir.glob("#{
|
32
|
+
Dir.glob("#{TERM_PATH}/*").each do |file|
|
33
33
|
say " * #{File.basename(file, '.term')} #{grab_comment_for_file(file)}"
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
37
|
desc "init", "create initial root terminitor folder"
|
38
38
|
def init
|
39
|
-
empty_directory
|
39
|
+
empty_directory TERM_PATH
|
40
40
|
end
|
41
41
|
|
42
42
|
desc "edit PROJECT_NAME", "open termitor script"
|
@@ -91,5 +91,16 @@ module Terminitor
|
|
91
91
|
remove_file path
|
92
92
|
end
|
93
93
|
|
94
|
+
desc "update", "update Terminitor to new global path(.config/.terminitor)"
|
95
|
+
def update
|
96
|
+
if File.exists?(old_path = File.join(ENV['HOME'],'.terminitor/'))
|
97
|
+
FileUtils.cp_r "#{old_path}/.", TERM_PATH
|
98
|
+
FileUtils.rm_r old_path
|
99
|
+
say "Terminitor has updated your global folder to ~/.config/terminitor/ !"
|
100
|
+
else
|
101
|
+
say "Old .terminitor/ global path doesn't exist. cool."
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
94
105
|
end
|
95
106
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Terminitor
|
2
|
+
class CmdCore < AbstractCore
|
3
|
+
attr_reader :current_window
|
4
|
+
|
5
|
+
CMD_XLT = {
|
6
|
+
'clear' => 'cls'
|
7
|
+
}
|
8
|
+
|
9
|
+
def initialize(path)
|
10
|
+
@current_window = CurrentWindowsConsole.new
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute_command(cmd, options = {})
|
15
|
+
cmd = CMD_XLT[cmd] || cmd
|
16
|
+
cmd += "\n" if (cmd =~ /\n\Z/).nil?
|
17
|
+
(options[:in] || current_window).send_command(cmd)
|
18
|
+
end
|
19
|
+
|
20
|
+
def open_tab(options = nil)
|
21
|
+
create_window
|
22
|
+
end
|
23
|
+
|
24
|
+
def open_window(options = nil)
|
25
|
+
create_window
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_window
|
29
|
+
WindowsConsole.new :name=>'cmd'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
|
@@ -0,0 +1,273 @@
|
|
1
|
+
module Terminitor
|
2
|
+
#
|
3
|
+
# Thanks win32/autogui!
|
4
|
+
#
|
5
|
+
module Input
|
6
|
+
|
7
|
+
# MSDN virtual key codes
|
8
|
+
VK_LBUTTON = 0x01
|
9
|
+
VK_RBUTTON = 0x02
|
10
|
+
|
11
|
+
VK_CANCEL = 0x03
|
12
|
+
VK_BACK = 0x08
|
13
|
+
VK_TAB = 0x09
|
14
|
+
VK_CLEAR = 0x0c
|
15
|
+
VK_RETURN = 0x0d
|
16
|
+
VK_SHIFT = 0x10
|
17
|
+
VK_CONTROL = 0x11
|
18
|
+
VK_MENU = 0x12
|
19
|
+
VK_PAUSE = 0x13
|
20
|
+
VK_ESCAPE = 0x1b
|
21
|
+
VK_SPACE = 0x20
|
22
|
+
VK_PRIOR = 0x21
|
23
|
+
VK_NEXT = 0x22
|
24
|
+
VK_END = 0x23
|
25
|
+
VK_HOME = 0x24
|
26
|
+
VK_LEFT = 0x25
|
27
|
+
VK_UP = 0x26
|
28
|
+
VK_RIGHT = 0x27
|
29
|
+
VK_DOWN = 0x28
|
30
|
+
VK_SELECT = 0x29
|
31
|
+
VK_EXECUTE = 0x2b
|
32
|
+
VK_SNAPSHOT = 0x2c
|
33
|
+
VK_INSERT = 0x2d
|
34
|
+
VK_DELETE = 0x2e
|
35
|
+
VK_HELP = 0x2f
|
36
|
+
|
37
|
+
VK_0 = 0x30
|
38
|
+
VK_1 = 0x31
|
39
|
+
VK_2 = 0x32
|
40
|
+
VK_3 = 0x33
|
41
|
+
VK_4 = 0x34
|
42
|
+
VK_5 = 0x35
|
43
|
+
VK_6 = 0x36
|
44
|
+
VK_7 = 0x37
|
45
|
+
VK_8 = 0x38
|
46
|
+
VK_9 = 0x39
|
47
|
+
VK_A = 0x41
|
48
|
+
VK_B = 0x42
|
49
|
+
VK_C = 0x43
|
50
|
+
VK_D = 0x44
|
51
|
+
VK_E = 0x45
|
52
|
+
VK_F = 0x46
|
53
|
+
VK_G = 0x47
|
54
|
+
VK_H = 0x48
|
55
|
+
VK_I = 0x49
|
56
|
+
VK_J = 0x4a
|
57
|
+
VK_K = 0x4b
|
58
|
+
VK_L = 0x4c
|
59
|
+
VK_M = 0x4d
|
60
|
+
VK_N = 0x4e
|
61
|
+
VK_O = 0x4f
|
62
|
+
VK_P = 0x50
|
63
|
+
VK_Q = 0x51
|
64
|
+
VK_R = 0x52
|
65
|
+
VK_S = 0x53
|
66
|
+
VK_T = 0x54
|
67
|
+
VK_U = 0x55
|
68
|
+
VK_V = 0x56
|
69
|
+
VK_W = 0x57
|
70
|
+
VK_X = 0x58
|
71
|
+
VK_Y = 0x59
|
72
|
+
VK_Z = 0x5a
|
73
|
+
|
74
|
+
VK_LWIN = 0x5b
|
75
|
+
VK_RWIN = 0x5c
|
76
|
+
VK_APPS = 0x5d
|
77
|
+
|
78
|
+
VK_NUMPAD0 = 0x60
|
79
|
+
VK_NUMPAD1 = 0x61
|
80
|
+
VK_NUMPAD2 = 0x62
|
81
|
+
VK_NUMPAD3 = 0x63
|
82
|
+
VK_NUMPAD4 = 0x64
|
83
|
+
VK_NUMPAD5 = 0x65
|
84
|
+
VK_NUMPAD6 = 0x66
|
85
|
+
VK_NUMPAD7 = 0x67
|
86
|
+
VK_NUMPAD8 = 0x68
|
87
|
+
VK_NUMPAD9 = 0x69
|
88
|
+
VK_MULTIPLY = 0x6a
|
89
|
+
VK_ADD = 0x6b
|
90
|
+
VK_SEPARATOR = 0x6c
|
91
|
+
VK_SUBTRACT = 0x6d
|
92
|
+
VK_DECIMAL = 0x6e
|
93
|
+
VK_DIVIDE = 0x6f
|
94
|
+
|
95
|
+
VK_F1 = 0x70
|
96
|
+
VK_F2 = 0x71
|
97
|
+
VK_F3 = 0x72
|
98
|
+
VK_F4 = 0x73
|
99
|
+
VK_F5 = 0x74
|
100
|
+
VK_F6 = 0x75
|
101
|
+
VK_F7 = 0x76
|
102
|
+
VK_F8 = 0x77
|
103
|
+
VK_F9 = 0x78
|
104
|
+
VK_F10 = 0x79
|
105
|
+
VK_F11 = 0x7a
|
106
|
+
VK_F12 = 0x7b
|
107
|
+
|
108
|
+
VK_NUMLOCK = 0x90
|
109
|
+
VK_SCROLL = 0x91
|
110
|
+
VK_OEM_EQU = 0x92
|
111
|
+
VK_LSHIFT = 0xa0
|
112
|
+
VK_RSHIFT = 0xa1
|
113
|
+
VK_LCONTROL = 0xa2
|
114
|
+
VK_RCONTROL = 0xa3
|
115
|
+
VK_LMENU = 0xa4
|
116
|
+
VK_RMENU = 0xa5
|
117
|
+
|
118
|
+
VK_OEM_1 = 0xba # US ";:"
|
119
|
+
VK_OEM_PLUS = 0xbb
|
120
|
+
VK_OEM_COMMA = 0xbc
|
121
|
+
VK_OEM_MINUS = 0xbd
|
122
|
+
VK_OEM_PERIOD = 0xbe
|
123
|
+
VK_OEM_2 = 0xbf # US "/?"
|
124
|
+
VK_OEM_3 = 0xc0 # US '`~'
|
125
|
+
VK_OEM_4 = 0xdb # US "[{"
|
126
|
+
VK_OEM_5 = 0xdc # US '\|'
|
127
|
+
VK_OEM_6 = 0xdd # US ']}'
|
128
|
+
VK_OEM_7 = 0xde # US quotes
|
129
|
+
VK_OEM_8 = 0xdf # none
|
130
|
+
|
131
|
+
# delay in seconds between keystrokes
|
132
|
+
KEYBD_KEYDELAY = 0
|
133
|
+
|
134
|
+
# keybd_event
|
135
|
+
KEYBD_EVENT_KEYUP = 2
|
136
|
+
KEYBD_EVENT_KEYDOWN = 0
|
137
|
+
|
138
|
+
Windows::API.auto_namespace = 'Terminitor::Input'
|
139
|
+
Windows::API.auto_constant = true
|
140
|
+
Windows::API.auto_method = true
|
141
|
+
Windows::API.auto_unicode = false
|
142
|
+
|
143
|
+
Windows::API.new('keybd_event', 'IILL', 'V', 'user32')
|
144
|
+
Windows::API.new('mouse_event', 'LLLLL', 'V', 'user32')
|
145
|
+
|
146
|
+
# Send keystroke to the focused window, keystrokes are virtual keycodes
|
147
|
+
#
|
148
|
+
# @example send 2+2<CR>
|
149
|
+
#
|
150
|
+
# keystroke(VK_2, VK_ADD, VK_2, VK_RETURN)
|
151
|
+
#
|
152
|
+
def keystroke(*keys)
|
153
|
+
return if keys.empty?
|
154
|
+
|
155
|
+
keybd_event keys.first, 0, KEYBD_EVENT_KEYDOWN, 0
|
156
|
+
sleep KEYBD_KEYDELAY
|
157
|
+
keystroke *keys[1..-1]
|
158
|
+
sleep KEYBD_KEYDELAY
|
159
|
+
keybd_event keys.first, 0, KEYBD_EVENT_KEYUP, 0
|
160
|
+
end
|
161
|
+
|
162
|
+
# String together keystrokes, simulates the user typing.
|
163
|
+
#
|
164
|
+
# Note: This method can be slow for large strings. Consider using
|
165
|
+
# the clipboard instead.
|
166
|
+
#
|
167
|
+
# @see Clipboard
|
168
|
+
#
|
169
|
+
# @example send 2+2<CR>
|
170
|
+
#
|
171
|
+
# type_in("2+2\n")
|
172
|
+
#
|
173
|
+
# @param [String] string of characters to simulate typing
|
174
|
+
def type_in(string)
|
175
|
+
string.each_char do |char|
|
176
|
+
keystroke(*char_to_virtual_keycode(char))
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
private
|
181
|
+
|
182
|
+
# convert a single character to a virtual keycode
|
183
|
+
#
|
184
|
+
# @param [Char] char is the character to convert
|
185
|
+
#
|
186
|
+
# @return [Array] of virtual keycodes
|
187
|
+
def char_to_virtual_keycode(char)
|
188
|
+
|
189
|
+
unless char.size == 1
|
190
|
+
raise "virtual keycode conversion is for single characters only"
|
191
|
+
end
|
192
|
+
|
193
|
+
code = char.unpack('U')[0]
|
194
|
+
|
195
|
+
case char
|
196
|
+
when '0'..'9'
|
197
|
+
[code - ?0 + 0x30]
|
198
|
+
when 'A'..'Z'
|
199
|
+
[VK_SHIFT, code]
|
200
|
+
when 'a'..'z'
|
201
|
+
[code - ?a + ?A]
|
202
|
+
when ' '
|
203
|
+
[code]
|
204
|
+
when '+'
|
205
|
+
[VK_ADD]
|
206
|
+
when '='
|
207
|
+
[VK_OEM_PLUS]
|
208
|
+
when ','
|
209
|
+
[VK_OEM_COMMA]
|
210
|
+
when '.'
|
211
|
+
[VK_OEM_PERIOD]
|
212
|
+
when '-'
|
213
|
+
[VK_OEM_MINUS]
|
214
|
+
when '_'
|
215
|
+
[VK_SHIFT, VK_OEM_MINUS]
|
216
|
+
|
217
|
+
when ';'
|
218
|
+
[VK_OEM_1]
|
219
|
+
when ':'
|
220
|
+
[VK_SHIFT, VK_OEM_1]
|
221
|
+
when '/'
|
222
|
+
[VK_OEM_2]
|
223
|
+
when '?'
|
224
|
+
[VK_SHIFT, VK_OEM_2]
|
225
|
+
when '`'
|
226
|
+
[VK_OEM_3]
|
227
|
+
when '~'
|
228
|
+
[VK_SHIFT, VK_OEM_3]
|
229
|
+
when '['
|
230
|
+
[VK_OEM_4]
|
231
|
+
when '{'
|
232
|
+
[VK_SHIFT, VK_OEM_4]
|
233
|
+
when '\\'
|
234
|
+
[VK_OEM_5]
|
235
|
+
when '|'
|
236
|
+
[VK_SHIFT, VK_OEM_5]
|
237
|
+
when ']'
|
238
|
+
[VK_OEM_6]
|
239
|
+
when '}'
|
240
|
+
[VK_SHIFT, VK_OEM_6]
|
241
|
+
when "'"
|
242
|
+
[VK_OEM_7]
|
243
|
+
when '"'
|
244
|
+
[VK_SHIFT, VK_OEM_7]
|
245
|
+
|
246
|
+
when '!'
|
247
|
+
[VK_SHIFT, VK_1]
|
248
|
+
when '@'
|
249
|
+
[VK_SHIFT, VK_2]
|
250
|
+
when '#'
|
251
|
+
[VK_SHIFT, VK_3]
|
252
|
+
when '$'
|
253
|
+
[VK_SHIFT, VK_4]
|
254
|
+
when '%'
|
255
|
+
[VK_SHIFT, VK_5]
|
256
|
+
when '^'
|
257
|
+
[VK_SHIFT, VK_6]
|
258
|
+
when '&'
|
259
|
+
[VK_SHIFT, VK_7]
|
260
|
+
when '*'
|
261
|
+
[VK_SHIFT, VK_8]
|
262
|
+
when '('
|
263
|
+
[VK_SHIFT, VK_9]
|
264
|
+
when ')'
|
265
|
+
[VK_SHIFT, VK_0]
|
266
|
+
when "\n"
|
267
|
+
[VK_RETURN]
|
268
|
+
else
|
269
|
+
raise "No conversion exists for character #{char}"
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|