te3270 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ require 'te3270/emulators/extra'
2
+ require 'te3270/emulators/quick3270'
3
+ require 'te3270/emulators/x3270'
4
+
5
+ module TE3270
6
+ #
7
+ # Provides a mapping between a key used in the +emulator_for+ method
8
+ # and the class that implements the access to the emulator.
9
+ #
10
+ module EmulatorFactory
11
+
12
+ EMULATORS = {
13
+ extra: TE3270::Emulators::Extra,
14
+ quick3270: TE3270::Emulators::Quick3270,
15
+ x3270: TE3270::Emulators::X3270
16
+ }
17
+
18
+ def self.emulator_for(platform)
19
+ EMULATORS[platform]
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,227 @@
1
+ module TE3270
2
+ module Emulators
3
+ #
4
+ # This class has the code necessary to communicate with the terminal emulator called EXTRA! X-treme.
5
+ # You can use this emulator by providing the +:extra+ parameter to the constructor of your screen
6
+ # object or by passing the same value to the +emulator_for+ method on the +TE3270+ module.
7
+ #
8
+ class Extra
9
+
10
+ attr_writer :session_file, :visible, :window_state, :max_wait_time
11
+
12
+
13
+ def initialize
14
+ if jruby?
15
+ require 'jruby-win32ole'
16
+ require 'java'
17
+ include_class 'java.awt.Dimension'
18
+ include_class 'java.awt.Rectangle'
19
+ include_class 'java.awt.Robot'
20
+ include_class 'java.awt.Toolkit'
21
+ include_class 'java.awt.event.InputEvent'
22
+ include_class 'java.awt.image.BufferedImage'
23
+ include_class 'javax.imageio.ImageIO'
24
+ else
25
+ require 'win32ole'
26
+ require 'win32/screenshot'
27
+ end
28
+ end
29
+
30
+ #
31
+ # Creates a method to connect to Extra System. This method expects a block in which certain
32
+ # platform specific values can be set. Extra can take the following parameters.
33
+ #
34
+ # * session_file - this value is required and should be the filename of the session.
35
+ # * visible - determines if the emulator is visible or not. If not set it will default to +true+.
36
+ # * window_state - determines the state of the session window. Valid values are +:minimized+,
37
+ # +:normal+, and +:maximized+. If not set it will default to +:normal+.
38
+ #
39
+ # @example Example calling screen object constructor with a block
40
+ # screen_object = MyScreenObject.new(:extra)
41
+ # screen_object.connect do |emulator|
42
+ # emulator.session_file = 'path_to_session_file'
43
+ # emulator.visible = true
44
+ # emulator.window_state = :maximized
45
+ # end
46
+ #
47
+ def connect
48
+ start_extra_system
49
+
50
+ yield self if block_given?
51
+ raise 'The session file must be set in a block when calling connect with the Extra emulator.' if @session_file.nil?
52
+ open_session
53
+ @screen = session.Screen
54
+ @area = screen.SelectAll
55
+ end
56
+
57
+ #
58
+ # Disconnects the Extra System connection
59
+ #
60
+ def disconnect
61
+ session.Close
62
+ end
63
+
64
+ #
65
+ # Extracts text of specified length from a start point.
66
+ #
67
+ # @param [Fixnum] row the x coordinate of location on the screen.
68
+ # @param [Fixnum] column the y coordinate of location on the screen.
69
+ # @param [Fixnum] length the length of string to extract
70
+ # @return [String]
71
+ #
72
+ def get_string(row, column, length)
73
+ screen.GetString(row, column, length)
74
+ end
75
+
76
+ #
77
+ # Puts string at the coordinates specified.
78
+ #
79
+ # @param [String] str the string to set
80
+ # @param [Fixnum] row the x coordinate of the location on the screen.
81
+ # @param [Fixnum] column the y coordinate of the location on the screen.
82
+ #
83
+ def put_string(str, row, column)
84
+ screen.PutString(str, row, column)
85
+ quiet_period
86
+ end
87
+
88
+ #
89
+ # Sends keystrokes to the host, including function keys.
90
+ #
91
+ # @param [String] keys keystokes up to 255 in length
92
+ #
93
+ def send_keys(keys)
94
+ screen.SendKeys(keys)
95
+ quiet_period
96
+ end
97
+
98
+ #
99
+ # Wait for the string to appear at the specified location
100
+ #
101
+ # @param [String] str the string to wait for
102
+ # @param [Fixnum] row the x coordinate of location
103
+ # @param [Fixnum] column the y coordinate of location
104
+ #
105
+ def wait_for_string(str, row, column)
106
+ wait_for do
107
+ screen.WaitForString(str, row, column)
108
+ end
109
+ end
110
+
111
+ #
112
+ # Waits for the host to not send data for a specified number of seconds
113
+ #
114
+ # @param [Fixnum] seconds the maximum number of seconds to wait
115
+ #
116
+ def wait_for_host(seconds)
117
+ wait_for(seconds) do
118
+ screen.WaitHostQuiet
119
+ end
120
+ end
121
+
122
+ #
123
+ # Waits until the cursor is at the specified location.
124
+ #
125
+ # @param [Fixnum] row the x coordinate of the location
126
+ # @param [Fixnum] column the y coordinate of the location
127
+ #
128
+ def wait_until_cursor_at(row, column)
129
+ wait_for do
130
+ screen.WaitForCursor(row, column)
131
+ end
132
+ end
133
+
134
+ #
135
+ # Creates a method to take screenshot of the active screen. If you have set the +:visible+
136
+ # property to false it will be made visible prior to taking the screenshot and then changed
137
+ # to invisible after.
138
+ #
139
+ # @param [String] filename the path and name of the screenshot file to be saved
140
+ #
141
+ def screenshot(filename)
142
+ File.delete(filename) if File.exists?(filename)
143
+ session.Visible = true unless visible
144
+
145
+ if jruby?
146
+ toolkit = Toolkit::getDefaultToolkit()
147
+ screen_size = toolkit.getScreenSize()
148
+ rect = Rectangle.new(screen_size)
149
+ robot = Robot.new
150
+ image = robot.createScreenCapture(rect)
151
+ f = java::io::File.new(filename)
152
+ ImageIO::write(image, "png", f)
153
+ else
154
+ hwnd = session.WindowHandle
155
+ Win32::Screenshot::Take.of(:window, hwnd: hwnd).write(filename)
156
+ end
157
+
158
+ session.Visible = false unless visible
159
+ end
160
+
161
+ #
162
+ # Returns the text of the active screen
163
+ #
164
+ # @return [String]
165
+ #
166
+ def text
167
+ area.Value
168
+ end
169
+
170
+ private
171
+
172
+ attr_reader :system, :sessions, :session, :screen, :area
173
+
174
+ WINDOW_STATES = {
175
+ minimized: 0,
176
+ normal: 1,
177
+ maximized: 2
178
+ }
179
+
180
+ def wait_for(seconds = system.TimeoutValue / 1000)
181
+ wait_collection = yield
182
+ wait_collection.Wait(seconds * 1000)
183
+ end
184
+
185
+ def quiet_period
186
+ wait_for_host(max_wait_time)
187
+ end
188
+
189
+ def max_wait_time
190
+ @max_wait_time ||= 1
191
+ end
192
+
193
+ def window_state
194
+ @window_state.nil? ? 1 : WINDOW_STATES[@window_state]
195
+ end
196
+
197
+ def visible
198
+ @visible.nil? ? true : @visible
199
+ end
200
+
201
+ def hide_splash_screen
202
+ version = system.Version
203
+ sessions.VisibleOnStartup = true if version.to_i >= 9
204
+ end
205
+
206
+ def open_session
207
+ @sessions = system.Sessions
208
+ hide_splash_screen
209
+ @session = sessions.Open @session_file
210
+ @session.WindowState = window_state
211
+ @session.Visible = visible
212
+ end
213
+
214
+ def start_extra_system
215
+ begin
216
+ @system = WIN32OLE.new('EXTRA.System')
217
+ rescue Exception => e
218
+ $stderr.puts e
219
+ end
220
+ end
221
+
222
+ def jruby?
223
+ RUBY_PLATFORM == 'java'
224
+ end
225
+ end
226
+ end
227
+ end
@@ -0,0 +1,180 @@
1
+ if Gem.win_platform?
2
+ require 'win32ole'
3
+ require 'win32/screenshot'
4
+ end
5
+
6
+ module TE3270
7
+ module Emulators
8
+
9
+ #
10
+ # This class has the code necessary to communicate with the terminal emulator called Quick3270.
11
+ # You can use this emulator by providing the +:quick+ parameter to the constructor of your screen
12
+ # object or by passing the same value to the +emulator_for+ method on the +TE3270+ module.
13
+ #
14
+
15
+ class Quick3270
16
+
17
+ attr_writer :session_file, :visible, :max_wait_time
18
+
19
+ #
20
+ # Creates a method to connect to Quick System. This method expects a block in which certain
21
+ # platform specific values can be set. Quick can take the following parameters.
22
+ #
23
+ # * session_file - this value is required and should be the filename of the session.
24
+ # * visible - determines if the emulator is visible or not. If not set it will default to +true+.
25
+ #
26
+ # @example Example calling screen object constructor with a block
27
+ # screen_object = MyScreenObject.new(:quick3270)
28
+ # screen_object.connect do |emulator|
29
+ # emulator.session_file = 'path_to_session_file'
30
+ # emulator.visible = true
31
+ # end
32
+ #
33
+ def connect
34
+ start_quick_system
35
+ yield self if block_given?
36
+ raise "The session file must be set in a block when calling connect with the Quick3270 emulator." if @session_file.nil?
37
+ establish_session
38
+ end
39
+
40
+ #
41
+ # Disconnects the Quick System connection
42
+ #
43
+ def disconnect
44
+ session.Disconnect
45
+ system.Application.Quit
46
+ end
47
+
48
+ #
49
+ # Extracts text of specified length from a start point.
50
+ #
51
+ # @param [Fixnum] row the x coordinate of location on the screen.
52
+ # @param [Fixnum] column the y coordinate of location on the screen.
53
+ # @param [Fixnum] length the length of string to extract
54
+ # @return [String]
55
+ #
56
+ def get_string(row, column, length)
57
+ screen.GetString(row, column, length)
58
+ end
59
+
60
+ #
61
+ # Puts string at the coordinates specified.
62
+ #
63
+ # @param [String] str the string to set
64
+ # @param [Fixnum] row the x coordinate of the location on the screen.
65
+ # @param [Fixnum] column the y coordinate of the location on the screen.
66
+ #
67
+ def put_string(str, row, column)
68
+ screen.MoveTo(row, column)
69
+ screen.PutString(str)
70
+ quiet_period
71
+ end
72
+
73
+ #
74
+ # Sends keystrokes to the host, including function keys.
75
+ #
76
+ # @param [String] keys keystokes up to 255 in length
77
+ #
78
+ def send_keys(keys)
79
+ screen.SendKeys(keys)
80
+ quiet_period
81
+ end
82
+
83
+ #
84
+ # Wait for the string to appear at the specified location
85
+ #
86
+ # @param [String] str the string to wait for
87
+ # @param [Fixnum] row the x coordinate of location
88
+ # @param [Fixnum] column the y coordinate of location
89
+ #
90
+ def wait_for_string(str, row, column)
91
+ screen.WaitForString(str, row, column)
92
+ end
93
+
94
+ #
95
+ # Waits for the host to not send data for a specified number of seconds
96
+ #
97
+ # @param [Fixnum] seconds the maximum number of seconds to wait
98
+ #
99
+ def wait_for_host(seconds)
100
+ screen.WaitHostQuiet(seconds * 1000)
101
+ end
102
+
103
+ #
104
+ # Waits until the cursor is at the specified location.
105
+ #
106
+ # @param [Fixnum] row the x coordinate of the location
107
+ # @param [Fixnum] column the y coordinate of the location
108
+ #
109
+ def wait_until_cursor_at(row, column)
110
+ screen.WaitForCursor(row, column)
111
+ end
112
+
113
+ #
114
+ # Creates a method to take screenshot of the active screen. If you have set the +:visible+
115
+ # property to false it will be made visible prior to taking the screenshot and then changed
116
+ # to invisible after.
117
+ #
118
+ # @param [String] filename the path and name of the screenshot file to be saved
119
+ #
120
+ def screenshot(filename)
121
+ File.delete(filename) if File.exists?(filename)
122
+ system.Visible = true unless visible
123
+ title = system.WindowTitle
124
+ Win32::Screenshot::Take.of(:window, title: title).write(filename)
125
+ system.Visible = false unless visible
126
+ end
127
+
128
+ #
129
+ # Returns the text of the active screen
130
+ #
131
+ # @return [String]
132
+ #
133
+ def text
134
+ rows = screen.Rows
135
+ columns = screen.Cols
136
+ result = ''
137
+ rows.times { |row| result += "#{screen.GetString(row+1, 1, columns)}\\n" }
138
+ result
139
+ end
140
+
141
+ private
142
+
143
+ attr_reader :system, :session, :screen
144
+
145
+ def quiet_period
146
+ screen.WaitHostQuiet(max_wait_time)
147
+ end
148
+
149
+ def max_wait_time
150
+ @max_wait_time ||= 3000
151
+ end
152
+
153
+ def visible
154
+ @visible.nil? ? true : @visible
155
+ end
156
+
157
+ def start_quick_system
158
+ begin
159
+ @system = WIN32OLE.new('Quick3270.Application')
160
+ rescue Exception => e
161
+ $stderr.puts e
162
+ end
163
+ end
164
+
165
+ def establish_session
166
+ system.Visible = visible
167
+ @session = system.ActiveSession
168
+ session.Open @session_file
169
+ @screen = session.Screen
170
+ session.Connect
171
+ connected = session.Connected
172
+ while not connected
173
+ screen.WaitHostQuiet(1000)
174
+ connected = session.Connected
175
+ end
176
+ end
177
+
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,185 @@
1
+ require 'open3'
2
+
3
+ module TE3270
4
+ module Emulators
5
+ #
6
+ # This class has the code necessary to communicate with the terminal emulator called EXTRA! X-treme.
7
+ # You can use this emulator by providing the +:extra+ parameter to the constructor of your screen
8
+ # object or by passing the same value to the +emulator_for+ method on the +TE3270+ module.
9
+ #
10
+ class X3270
11
+
12
+ attr_writer :executable_command, :host, :max_wait_time, :trace
13
+
14
+ #
15
+ # Creates a method to connect to x3270. This method expects a block in which certain
16
+ # platform specific values can be set. Extra can take the following parameters.
17
+ #
18
+ # * executable_command - this value is required and should be the name of the ws3270 executable
19
+ # * host - this is required and is the (DNS) name of the host to connect to
20
+ # * max_wait_time - max time to wait in wait_for_string (defaults to 10 if not specified)
21
+ #
22
+ # @example Example x3270 object constructor with a block
23
+ # screen_object = MyScreenObject.new(:x3270)
24
+ # screen_object.connect do |emulator|
25
+ # emulator.executable_command = 'path_to_executable'
26
+ # emulator.host = 'host.example.com'
27
+ # emulator.max_wait_time = 5
28
+ # end
29
+ #
30
+ def connect
31
+ @max_wait_time = 10
32
+ @trace = false
33
+ yield self if block_given?
34
+ raise 'The executable command must be set in a block when calling connect with the X3270 emulator.' if @executable_command.nil?
35
+ raise 'The host must be set in a block when calling connect with the X3270 emulator.' if @host.nil?
36
+ start_x3270_system
37
+ end
38
+
39
+ #
40
+ # Disconnects the x3270 System connection
41
+ #
42
+ def disconnect
43
+ @x3270_input.close
44
+ @x3270_output.close
45
+ end
46
+
47
+ #
48
+ # Extracts text of specified length from a start point.
49
+ #
50
+ # @param [Fixnum] row the x coordinate of location on the screen.
51
+ # @param [Fixnum] column the y coordinate of location on the screen.
52
+ # @param [Fixnum] length the length of string to extract
53
+ # @return [String]
54
+ #
55
+ def get_string row, column, length
56
+ x_send "ascii(#{row-1},#{column-1},#{length})"
57
+ result_string = ""
58
+ while line = x_read do
59
+ break if line == 'ok'
60
+ result_string = result_string + line[6..-1] if line[0..5] == 'data: '
61
+ end
62
+ result_string
63
+ end
64
+
65
+ #
66
+ # Puts string at the coordinates specified.
67
+ #
68
+ # @param [String] str the string to set
69
+ # @param [Fixnum] row the x coordinate of the location on the screen.
70
+ # @param [Fixnum] column the y coordinate of the location on the screen.
71
+ #
72
+ def put_string(str, row, column)
73
+ x_send_no_rsp "MoveCursor(#{row-1},#{column-1})"
74
+ x_send_no_rsp 'string "' + str.gsub('"', '\\"') + '"'
75
+ end
76
+
77
+ #
78
+ # Sends keystrokes to the host, including function keys.
79
+ #
80
+ # @param [String] keys keystokes up to 255 in length
81
+ #
82
+ def send_keys(keys)
83
+ key = keys[1..-2]
84
+ if m=/^(Pf|Pa)(\d+)$/.match(key)
85
+ key = "#{m[1]}(#{m[2]})"
86
+ end
87
+ x_send_no_rsp key
88
+ x_send_no_rsp "wait(output)"
89
+ end
90
+
91
+ #
92
+ # Wait for the string to appear at the specified location
93
+ #
94
+ # @param [String] str the string to wait for
95
+ # @param [Fixnum] row the x coordinate of location
96
+ # @param [Fixnum] column the y coordinate of location
97
+ #
98
+ def wait_for_string(str, row, column)
99
+ total_time = 0.0
100
+ sleep_time = 0.5
101
+ while get_string(row, column, str.length) != str do
102
+ sleep sleep_time
103
+ total_time = total_time + sleep_time
104
+ break if total_time >= @max_wait_time
105
+ end
106
+ end
107
+
108
+ #
109
+ # Waits for the host to not send data for a specified number of seconds
110
+ #
111
+ # @param [Fixnum] seconds the maximum number of seconds to wait
112
+ #
113
+ def wait_for_host(seconds)
114
+ x_send_no_rsp "Wait(#{seconds},Output)"
115
+ end
116
+
117
+ #
118
+ # Waits until the cursor is at the specified location.
119
+ #
120
+ # @param [Fixnum] row the x coordinate of the location
121
+ # @param [Fixnum] column the y coordinate of the location
122
+ #
123
+ def wait_until_cursor_at(row, column)
124
+ x_send_no_rsp "MoveCursor(#{row-1},#{column-1})"
125
+ end
126
+
127
+ #
128
+ # Creates a method to take screenshot of the active screen. If you have set the +:visible+
129
+ # property to false it will be made visible prior to taking the screenshot and then changed
130
+ # to invisible after.
131
+ #
132
+ # @param [String] filename the path and name of the screenshot file to be saved
133
+ #
134
+ def screenshot(filename)
135
+ File.delete(filename) if File.exists?(filename)
136
+ x_send_no_rsp "printtext(file,#{filename})"
137
+ end
138
+
139
+ #
140
+ # Returns the text of the active screen
141
+ #
142
+ # @return [String]
143
+ #
144
+ def text
145
+ get_string(1,1,24*80)
146
+ end
147
+
148
+ private
149
+
150
+ attr_reader :x3270_input, :x3270_output
151
+
152
+ def x_read
153
+ line = @x3270_output.gets.chomp
154
+ puts "x_read: '#{line}'" if @trace
155
+ line
156
+ end
157
+
158
+ def x_send cmd
159
+ puts "x_send: #{cmd}" if @trace
160
+ @x3270_input.print "#{cmd}\n"
161
+ @x3270_input.flush
162
+ end
163
+
164
+ def x_send_no_rsp cmd
165
+ x_send cmd
166
+ while line = x_read do
167
+ break if line == 'ok'
168
+ end
169
+ end
170
+
171
+ def start_x3270_system
172
+ begin
173
+ args = [
174
+ "-model", "2",
175
+ ""
176
+ ]
177
+ cmd = "#{@executable_command} #{args.join " "} #{@host}"
178
+ @x3270_input, @x3270_output, @x3270_thr = Open3.popen2e(cmd)
179
+ rescue Exception => e
180
+ raise "Could not start x3270 '#{@executable_command}': #{e}"
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end