win 0.0.4 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/lib/win/window.rb CHANGED
@@ -5,6 +5,12 @@ module Win
5
5
  # Contains constants, functions and wrappers related to Windows manipulation
6
6
  #
7
7
  module Window
8
+ # Internal constants:
9
+
10
+ # Windows keyboard-related Constants:
11
+ # ? move to keyboard.rb?
12
+ KEY_DELAY = 0.00001
13
+
8
14
  include Win::Library
9
15
 
10
16
  #General constants:
@@ -16,6 +22,70 @@ module Win
16
22
  # Sys Command Close
17
23
  SC_CLOSE = 0xF060
18
24
 
25
+ # Key down keyboard event (the key is being depressed)
26
+ KEYEVENTF_KEYDOWN = 0
27
+ # Key up keyboard event (the key is being released)
28
+ KEYEVENTF_KEYUP = 2
29
+ # Extended kb event. If specified, the scan code was preceded by a prefix byte having the value 0xE0 (224).
30
+ KEYEVENTF_EXTENDEDKEY = 1
31
+
32
+ # Virtual key codes:
33
+
34
+ # Control-break processing
35
+ VK_CANCEL = 0x03
36
+ # Backspace? key
37
+ VK_BACK = 0x08
38
+ # Tab key
39
+ VK_TAB = 0x09
40
+ # Shift key
41
+ VK_SHIFT = 0x10
42
+ # Ctrl key
43
+ VK_CONTROL = 0x11
44
+ # ENTER key
45
+ VK_RETURN = 0x0D
46
+ # ALT key
47
+ VK_ALT = 0x12
48
+ # ALT key alias
49
+ VK_MENU = 0x12
50
+ # PAUSE key
51
+ VK_PAUSE = 0x13
52
+ # CAPS LOCK key
53
+ VK_CAPITAL = 0x14
54
+ # ESC key
55
+ VK_ESCAPE = 0x1B
56
+ # SPACEBAR
57
+ VK_SPACE = 0x20
58
+ # PAGE UP key
59
+ VK_PRIOR = 0x21
60
+ # PAGE DOWN key
61
+ VK_NEXT = 0x22
62
+ # END key
63
+ VK_END = 0x23
64
+ # HOME key
65
+ VK_HOME = 0x24
66
+ # LEFT ARROW key
67
+ VK_LEFT = 0x25
68
+ # UP ARROW key
69
+ VK_UP = 0x26
70
+ # RIGHT ARROW key
71
+ VK_RIGHT = 0x27
72
+ # DOWN ARROW key
73
+ VK_DOWN = 0x28
74
+ # SELECT key
75
+ VK_SELECT = 0x29
76
+ # PRINT key
77
+ VK_PRINT = 0x2A
78
+ # EXECUTE key
79
+ VK_EXECUTE = 0x2B
80
+ # PRINT SCREEN key
81
+ VK_SNAPSHOT = 0x2C
82
+ # INS key
83
+ VK_INSERT = 0x2D
84
+ # DEL key
85
+ VK_DELETE = 0x2E
86
+ # HELP key
87
+ VK_HELP = 0x2F
88
+
19
89
  # ShowWindow constants:
20
90
 
21
91
  # Hides the window and activates another window.
@@ -51,6 +121,50 @@ module Win
51
121
  # flag when minimizing windows from a different thread.
52
122
  SW_FORCEMINIMIZE = 11
53
123
 
124
+ class << self
125
+ # Def_block that calls API function expecting EnumWindowsProc callback (EnumWindows, EnumChildWindows, ...).
126
+ # Default callback just pushes all passed handles into Array that is returned if Enum function call was successful.
127
+ # If runtime block is given it is added to the end of default callback (handles Array is still collected/returned).
128
+ # If Enum function call failed, method returns nil, otherwise an Array of window handles.
129
+ #
130
+ def return_enum #:nodoc:
131
+ lambda do |api, *args, &block|
132
+ args.push 0 if args.size == api.prototype.size - 2 # If value is missing, it defaults to 0
133
+ handles = []
134
+
135
+ # Insert callback proc into appropriate place of args Array
136
+ args[api.prototype.find_index(:enum_callback), 0] =
137
+ proc do |handle, message|
138
+ handles << handle
139
+ block ? block[handle, message] : true
140
+ end
141
+ handles if api.call *args
142
+ end
143
+ end
144
+
145
+ # Helper method that creates def_block returning (possibly encoded) string as a result of
146
+ # api function call or nil if zero characters was returned by api call
147
+ #
148
+ def return_string( encode = nil ) #:nodoc:
149
+ lambda do |api, *args|
150
+ namespace.enforce_count( args, api.prototype, -2)
151
+ buffer = FFI::MemoryPointer.new :char, 1024
152
+ buffer.put_string(0, "\x00" * 1023)
153
+ args += [buffer, 1024]
154
+ num_chars = api.call(*args)
155
+ return nil if num_chars == 0
156
+ if encode
157
+ string = buffer.get_bytes(0, num_chars*2)
158
+ string = string.force_encoding('utf-16LE').encode(encode)
159
+ else
160
+ string = buffer.get_bytes(0, num_chars)
161
+ end
162
+ string.rstrip
163
+ end
164
+ end
165
+
166
+ private :return_enum, :return_string
167
+ end
54
168
 
55
169
  # Windows GUI API definitions:
56
170
 
@@ -71,7 +185,7 @@ module Win
71
185
  # WS_VISIBLE style, it may be true even if the window is totally obscured by other windows.
72
186
  #
73
187
  # :call-seq:
74
- # visible?( win_handle ), window_visible?( win_handle )
188
+ # [window_]visible?( win_handle )
75
189
  #
76
190
  function 'IsWindowVisible', 'L', 'L', aliases: :visible?
77
191
 
@@ -148,20 +262,6 @@ module Win
148
262
  #
149
263
  function 'FindWindowEx', 'LLPP', 'L', zeronil: true
150
264
 
151
- # Helper method that creates def_block returning (possibly encoded) string as a result of
152
- # api function call or nil if zero characters was returned by api call
153
- # TODO: should be private
154
- def self.return_string( encode = nil ) #:nodoc:
155
- lambda do |api, *args|
156
- namespace.enforce_count( args, api.prototype, -2)
157
- args += [string = buffer, string.length]
158
- num_chars = api.call(*args)
159
- return nil if num_chars == 0
160
- string = string.force_encoding('utf-16LE').encode(encode) if encode
161
- string.rstrip
162
- end
163
- end
164
-
165
265
  ##
166
266
  # Returns the text of the specified window's title bar (if it has one).
167
267
  # If the specified window is a control, the text of the control is copied. However, GetWindowText
@@ -195,7 +295,7 @@ module Win
195
295
  # of calling GetWindowText.
196
296
  #
197
297
  #:call-seq:
198
- # text = get_window_text( win_handle )
298
+ # text = [get_]window_text( win_handle )
199
299
  #
200
300
  function 'GetWindowText', 'LPI', 'L', &return_string
201
301
 
@@ -204,7 +304,7 @@ module Win
204
304
  # API improved to require only win_handle and return rstripped string
205
305
  #
206
306
  #:call-seq:
207
- # text = get_window_text_w( win_handle )
307
+ # text = [get_]window_text_w( win_handle )
208
308
  #
209
309
  function 'GetWindowTextW', 'LPI', 'L', &return_string('utf-8')
210
310
 
@@ -227,7 +327,7 @@ module Win
227
327
  # Returns: Name of the class or NIL if function fails. For extended error information, call GetLastError.
228
328
  #
229
329
  #:call-seq:
230
- # text = get_class_name( win_handle )
330
+ # text = [get_]class_name( win_handle )
231
331
  #
232
332
  function 'GetClassName', 'LPI', 'I', &return_string
233
333
 
@@ -236,7 +336,7 @@ module Win
236
336
  # API improved to require only win_handle and return rstripped string
237
337
  #
238
338
  #:call-seq:
239
- # text = get_class_name_w( win_handle )
339
+ # text = [get_]class_name_w( win_handle )
240
340
  #
241
341
  function 'GetClassNameW', 'LPI', 'I', &return_string('utf-8')
242
342
 
@@ -265,12 +365,6 @@ module Win
265
365
  show_window(win_handle, SW_HIDE)
266
366
  end
267
367
 
268
- return_thread_process = lambda do |api, *args|
269
- namespace.enforce_count( args, api.prototype, -1)
270
- thread = api.call(args.first, process = [1].pack('L'))
271
- nonzero_array(thread, *process.unpack('L'))
272
- end
273
-
274
368
  ##
275
369
  # Retrieves the identifier of the thread that created the specified window
276
370
  # and, optionally, the identifier of the process that created the window.
@@ -287,16 +381,15 @@ module Win
287
381
  # Returns: Pair of identifiers of the thread and process_id that created the window.
288
382
  #
289
383
  #:call-seq:
290
- # thread, process_id = get_window_tread_process_id( win_handle )
384
+ # thread, process_id = [get_]window_tread_process_id( win_handle )
291
385
  #
292
- function 'GetWindowThreadProcessId', 'LP', 'L', &return_thread_process
293
-
294
- return_rect = lambda do |api, *args|
295
- namespace.enforce_count( args, api.prototype, -1)
296
- rectangle = [0, 0, 0, 0].pack('L*')
297
- res = api.call args.first, rectangle
298
- res == 0 ? [nil, nil, nil, nil] : rectangle.unpack('L*')
299
- end
386
+ function 'GetWindowThreadProcessId', [:long, :pointer], :long, &->(api, *args) {
387
+ namespace.enforce_count( args, api.prototype, -1)
388
+ process = FFI::MemoryPointer.new(:long)
389
+ process.write_long(1)
390
+ thread = api.call(args.first, process)
391
+ thread == 0 ? [nil, nil] : [thread, process.read_long()] }
392
+ # weird lambda literal instead of block is needed because RDoc goes crazy if block is attached to meta-definition
300
393
 
301
394
  ##
302
395
  # Retrieves the dimensions of the specified window bounding rectangle.
@@ -318,91 +411,128 @@ module Win
318
411
  # are exclusive. In other words, the pixel at (right, bottom) lies immediately outside the rectangle.
319
412
  #
320
413
  #:call-seq:
321
- # rect = get_window_rect( win_handle )
322
- #
323
- function 'GetWindowRect', 'LP', 'I', &return_rect
324
-
325
- # # Procedure that calls api function expecting a callback. If runtime block is given
326
- # # it is converted into callback, otherwise procedure returns an array of all handles
327
- # # pushed into callback by api enumeration
328
- # # TODO: should be private
329
- # #
330
- # def self.return_enum #:nodoc:
331
- # lambda do |api, *args, &block|
332
- # namespace.enforce_count( args, api.prototype, -1)
333
- # handles = []
334
- # cb = if block
335
- # callback('LP', 'I', &block)
336
- # else
337
- # callback('LP', 'I') do |handle, message|
338
- # handles << handle
339
- # true
340
- # end
341
- # end
342
- # args[api.prototype.find_index('K'), 0] = cb # Insert callback into appropriate place of args Array
343
- # api.call *args
344
- # handles
345
- # end
346
- # end
347
- #
348
- # ##
349
- # # The EnumWindows function enumerates all top-level windows on the screen by passing the handle to
350
- # # each window, in turn, to an application-defined callback function. EnumWindows continues until
351
- # # the last top-level window is enumerated or the callback function returns FALSE.
352
- # #
353
- # # Original Parameters:
354
- # # callback [K] - Pointer to an application-defined callback function (see EnumWindowsProc).
355
- # # message [P] - Specifies an application-defined value(message) to be passed to the callback function.
356
- # # Original Return: Nonzero if the function succeeds, zero if the function fails. GetLastError for error info.
357
- # # If callback returns zero, the return value is also zero. In this case, the callback function should
358
- # # call SetLastError to obtain a meaningful error code to be returned to the caller of EnumWindows.
359
- # #
360
- # # API improved to accept blocks (instead of callback objects) and message as a single arg
361
- # #
362
- # # New Parameters:
363
- # # message [P] - Specifies an application-defined value(message) to be passed to the callback function.
364
- # # block given to method invocation serves as an application-defined callback function (see EnumWindowsProc).
365
- # # Returns: True if the function succeeds, false if the function fails. GetLastError for error info.
366
- # # If callback returns zero, the return value is also zero. In this case, the callback function should
367
- # # call SetLastError to obtain a meaningful error code to be returned to the caller of EnumWindows.
368
- # #
369
- # # Remarks: The EnumWindows function does not enumerate child windows, with the exception of a few top-level
370
- # # windows owned by the system that have the WS_CHILD style. This function is more reliable than calling
371
- # # the GetWindow function in a loop. An application that calls GetWindow to perform this task risks being
372
- # # caught in an infinite loop or referencing a handle to a window that has been destroyed.
373
- # #
374
- # #:call-seq:
375
- # # status = enum_windows( message ) {|win_handle, message| callback procedure }
376
- # #
377
- # function'EnumWindows', 'KP', 'L', boolean: true, &return_enum
378
- #
379
- # ##
380
- # # Enumerates child windows to a given window.
381
- # #
382
- # # Original Parameters:
383
- # # parent (L) - Handle to the parent window whose child windows are to be enumerated.
384
- # # callback [K] - Pointer to an application-defined callback function (see EnumWindowsProc).
385
- # # message [P] - Specifies an application-defined value(message) to be passed to the callback function.
386
- # # Original Return: Not used (?!)
387
- # # If callback returns zero, the return value is also zero. In this case, the callback function should
388
- # # call SetLastError to obtain a meaningful error code to be returned to the caller of EnumWindows.
389
- # # If it is nil, this function is equivalent to EnumWindows. Windows 95/98/Me: parent cannot be NULL.
390
- # #
391
- # # API improved to accept blocks (instead of callback objects) and two args: parent handle and message.
392
- # # New Parameters:
393
- # # parent (L) - Handle to the parent window whose child windows are to be enumerated.
394
- # # message (P) - Specifies an application-defined value(message) to be passed to the callback function.
395
- # # block given to method invocation serves as an application-defined callback function (see EnumChildProc).
396
- # #
397
- # # Remarks:
398
- # # If a child window has created child windows of its own, EnumChildWindows enumerates those windows as well.
399
- # # A child window that is moved or repositioned in the Z order during the enumeration process will be properly enumerated.
400
- # # The function does not enumerate a child window that is destroyed before being enumerated or that is created during the enumeration process.
401
- # #
402
- # #:call-seq:
403
- # # enum_windows( parent_handle, message ) {|win_handle, message| callback procedure }
404
- # #
405
- # function 'EnumChildWindows', 'LKP', 'L', &return_enum
414
+ # rect = [get_]window_rect( win_handle )
415
+ #
416
+ function 'GetWindowRect', 'LP', 'I', &->(api, *args) {
417
+ namespace.enforce_count( args, api.prototype, -1)
418
+ rect = FFI::MemoryPointer.new(:long, 4)
419
+ rect.write_array_of_long([0, 0, 0, 0])
420
+ res = api.call args.first, rect
421
+ res == 0 ? [nil, nil, nil, nil] : rect.read_array_of_long(4) }
422
+ # weird lambda literal instead of block is needed because RDoc goes crazy if block is attached to meta-definition
423
+
424
+ # This is an application-defined callback function that receives top-level window handles as a result of a call
425
+ # to the EnumWindows, EnumChildWindows or EnumDesktopWindows function.
426
+ #
427
+ # Syntax: BOOL CALLBACK EnumWindowsProc( HWND hwnd, LPARAM lParam );
428
+ #
429
+ # Parameters:
430
+ # hwnd (L) - [out] Handle to a top-level window.
431
+ # lParam (L) - [in] Specifies the application-defined value given in EnumWindows or EnumDesktopWindows.
432
+ # Return Values:
433
+ # TRUE continues enumeration. FALSE stops enumeration.
434
+ #
435
+ # Remarks: An application must register this callback function by passing its address to EnumWindows or EnumDesktopWindows.
436
+ callback :enum_callback, 'LL', :bool
437
+
438
+ ##
439
+ # The EnumWindows function enumerates all top-level windows on the screen by passing the handle to
440
+ # each window, in turn, to an application-defined callback function. EnumWindows continues until
441
+ # the last top-level window is enumerated or the callback function returns FALSE.
442
+ #
443
+ # Original Parameters:
444
+ # callback [K] - Pointer to an application-defined callback function (see EnumWindowsProc).
445
+ # value [P] - Specifies an application-defined value(message) to be passed to the callback function.
446
+ # Original Return: Nonzero if the function succeeds, zero if the function fails. GetLastError for error info.
447
+ # If callback returns zero, the return value is also zero. In this case, the callback function should
448
+ # call SetLastError to obtain a meaningful error code to be returned to the caller of EnumWindows.
449
+ #
450
+ # API improved to accept blocks (instead of callback objects) and message as a single arg
451
+ #
452
+ # New Parameters:
453
+ # message [P] - Specifies an application-defined value(message) to be passed to the callback function.
454
+ # block given to method invocation serves as an application-defined callback function (see EnumWindowsProc).
455
+ # Returns: True if the function succeeds, false if the function fails. GetLastError for error info.
456
+ # If callback returns zero, the return value is also zero. In this case, the callback function should
457
+ # call SetLastError to obtain a meaningful error code to be returned to the caller of EnumWindows.
458
+ #
459
+ # Remarks: The EnumWindows function does not enumerate child windows, with the exception of a few top-level
460
+ # windows owned by the system that have the WS_CHILD style. This function is more reliable than calling
461
+ # the GetWindow function in a loop. An application that calls GetWindow to perform this task risks being
462
+ # caught in an infinite loop or referencing a handle to a window that has been destroyed.
463
+ #
464
+ #:call-seq:
465
+ # handles = enum_windows( [value] ) {|handle, message| your callback procedure }
466
+ #
467
+ function'EnumWindows', [:enum_callback, :long], :bool, &return_enum
468
+
469
+ ##
470
+ #EnumDesktopWindows Function
471
+ #
472
+ #Enumerates all top-level windows associated with the specified desktop. It passes the handle to each window, in turn, to an application-defined callback function.
473
+ #
474
+ #
475
+ #Syntax
476
+ #BOOL WINAPI EnumDesktopWindows(
477
+ # __in_opt HDESK hDesktop,
478
+ # __in WNDENUMPROC lpfn,
479
+ # __in LPARAM lParam
480
+ #);
481
+ #
482
+ #Parameters
483
+ #hDesktop
484
+ #A handle to the desktop whose top-level windows are to be enumerated. This handle is returned by the CreateDesktop, GetThreadDesktop, OpenDesktop, or OpenInputDesktop function, and must have the DESKTOP_ENUMERATE access right. For more information, see Desktop Security and Access Rights.
485
+ #
486
+ #If this parameter is NULL, the current desktop is used.
487
+ #
488
+ #lpfn
489
+ #A pointer to an application-defined EnumWindowsProc callback function.
490
+ #
491
+ #lParam
492
+ #An application-defined value to be passed to the callback function.
493
+ #
494
+ #Return Value
495
+ #If the function fails or is unable to perform the enumeration, the return value is zero.
496
+ #
497
+ #To get extended error information, call GetLastError.
498
+ #
499
+ #You must ensure that the callback function sets SetLastError if it fails.
500
+ #
501
+ #Windows Server 2003 and Windows XP/2000: If there are no windows on the desktop, GetLastError returns ERROR_INVALID_HANDLE.
502
+ #Remarks
503
+ #The EnumDesktopWindows function repeatedly invokes the lpfn callback function until the last top-level window is enumerated or the callback function returns FALSE.
504
+ #
505
+ #Requirements
506
+ #Client Requires Windows Vista, Windows XP, or Windows 2000 Professional.
507
+ function'EnumDesktopWindows', [:ulong, :enum_callback, :long], :bool, &return_enum
508
+
509
+ ##
510
+ # Enumerates child windows to a given window.
511
+ #
512
+ # Original Parameters:
513
+ # parent (L) - Handle to the parent window whose child windows are to be enumerated.
514
+ # callback [K] - Pointer to an application-defined callback function (see EnumWindowsProc).
515
+ # message [P] - Specifies an application-defined value(message) to be passed to the callback function.
516
+ # Original Return: Not used (?!)
517
+ # If callback returns zero, the return value is also zero. In this case, the callback function should
518
+ # call SetLastError to obtain a meaningful error code to be returned to the caller of EnumWindows.
519
+ # If it is nil, this function is equivalent to EnumWindows. Windows 95/98/Me: parent cannot be NULL.
520
+ #
521
+ # API improved to accept blocks (instead of callback objects) and parent handle (value is optional, default 0)
522
+ # New Parameters:
523
+ # parent (L) - Handle to the parent window whose child windows are to be enumerated.
524
+ # value (P) - Specifies an application-defined value(message) to be passed to the callback function.
525
+ # block given to method invocation serves as an application-defined callback function (see EnumChildProc).
526
+ #
527
+ # Remarks:
528
+ # If a child window has created child windows of its own, EnumChildWindows enumerates those windows as well.
529
+ # A child window that is moved or repositioned in the Z order during the enumeration process will be properly enumerated.
530
+ # The function does not enumerate a child window that is destroyed before being enumerated or that is created during the enumeration process.
531
+ #
532
+ #:call-seq:
533
+ # handles = enum_child_windows( parent_handle, [value = 0] ) {|handle, message| your callback procedure }
534
+ #
535
+ function 'EnumChildWindows', [:ulong, :enum_callback, :long], :bool, &return_enum
406
536
 
407
537
  ##
408
538
  # GetForegroundWindow function returns a handle to the foreground window (the window with which the user
@@ -415,10 +545,13 @@ module Win
415
545
  # certain circumstances, such as when a window is losing activation.
416
546
  #
417
547
  #:call-seq:
418
- # win_handle = (get_)foreground_window()
548
+ # win_handle = [get_]foreground_window()
419
549
  #
420
550
  function 'GetForegroundWindow', [], 'L'
421
551
 
552
+ ##
553
+ # Tests if given window handle points to foreground (topmost) window
554
+ #
422
555
  def foreground?(win_handle)
423
556
  win_handle == foreground_window
424
557
  end
@@ -436,115 +569,40 @@ module Win
436
569
  # To get the window handle to the active window in the message queue for another thread, use GetGUIThreadInfo.
437
570
  #
438
571
  #:call-seq:
439
- # win_handle = (get_)active_window()
572
+ # win_handle = [get_]active_window()
440
573
  #
441
574
  function 'GetActiveWindow', [], 'L'
442
575
 
576
+ ##
577
+ # The keybd_event function synthesizes a keystroke. The system can use such a synthesized keystroke to generate
578
+ # a WM_KEYUP or WM_KEYDOWN message. The keyboard driver's interrupt handler calls the keybd_event function.
579
+ #
580
+ # !!!! Windows NT/2000/XP/Vista:This function has been superseded. Use SendInput instead.
581
+ #
582
+ # Syntax: VOID keybd_event( BYTE bVk, BYTE bScan, DWORD dwFlags, PTR dwExtraInfo);
583
+ #
584
+ # Parameters:
585
+ # bVk [C] - [in] Specifies a virtual-key code. The code must be a value in the range 1 to 254.
586
+ # For a complete list, see Virtual-Key Codes.
587
+ # bScan [C] - [in] Specifies a hardware scan code for the key.
588
+ # dwFlags [L] - [in] Specifies various aspects of function operation. This parameter can be
589
+ # one or more of the following values:
590
+ # KEYEVENTF_EXTENDEDKEY, KEYEVENTF_KEYUP, KEYEVENTF_KEYDOWN
591
+ # dwExtraInfo [L] -[in] Specifies an additional value associated with the key stroke.
592
+ #
593
+ # Return Value: none
594
+ #
595
+ # Remarks: An application can simulate a press of the PRINTSCRN key in order to obtain a screen snapshot and save
596
+ # it to the clipboard. To do this, call keybd_event with the bVk parameter set to VK_SNAPSHOT.
597
+ #
598
+ # Windows NT/2000/XP: The keybd_event function can toggle the NUM LOCK, CAPS LOCK, and SCROLL LOCK keys.
599
+ # Windows 95/98/Me: The keybd_event function can toggle only the CAPS LOCK and SCROLL LOCK keys.
600
+ #
443
601
  function 'keybd_event', 'IILL', 'V'
602
+
444
603
  function 'PostMessage', 'LLLL', 'L'
445
604
  function 'SendMessage', 'LLLP', 'L'
446
605
  function 'GetDlgItem', 'LL', 'L'
447
606
 
448
-
449
- # Convenience wrapper methods:
450
-
451
- # emulates combinations of keys pressed (Ctrl+Alt+P+M, etc)
452
- def keystroke(*keys)
453
- return if keys.empty?
454
- keybd_event keys.first, 0, KEYEVENTF_KEYDOWN, 0
455
- sleep WG_KEY_DELAY
456
- keystroke *keys[1..-1]
457
- sleep WG_KEY_DELAY
458
- keybd_event keys.first, 0, KEYEVENTF_KEYUP, 0
459
- end
460
-
461
- # types text message into window holding the focus
462
- def type_in(message)
463
- message.scan(/./m) do |char|
464
- keystroke(*char.to_vkeys)
465
- end
466
- end
467
-
468
- # finds top-level dialog window by title and yields it to given block
469
- def dialog(title, seconds=3)
470
- d = begin
471
- win = Window.top_level(title, seconds)
472
- yield(win) ? win : nil
473
- rescue TimeoutError
474
- end
475
- d.wait_for_close if d
476
- return d
477
- end
478
-
479
- # Thin wrapper around window handle
480
- class Window
481
- include Win::Window
482
- extend Win::Window
483
-
484
- attr_reader :handle
485
-
486
- # find top level window by title, return wrapped Window object
487
- def self.top_level(title, seconds=3)
488
- @handle = timeout(seconds) do
489
- sleep WG_SLEEP_DELAY while (h = find_window nil, title) == nil; h
490
- end
491
- Window.new @handle
492
- end
493
-
494
- def initialize(handle)
495
- @handle = handle
496
- end
497
-
498
- # find child window (control) by title, window class, or control ID:
499
- def child(id)
500
- result = case id
501
- when String
502
- by_title = find_window_ex @handle, 0, nil, id.gsub('_' , '&' )
503
- by_class = find_window_ex @handle, 0, id, nil
504
- by_title ? by_title : by_class
505
- when Fixnum
506
- get_dlg_item @handle, id
507
- when nil
508
- find_window_ex @handle, 0, nil, nil
509
- else
510
- nil
511
- end
512
- raise "Control '#{id}' not found" unless result
513
- Window.new result
514
- end
515
-
516
- def children
517
- enum_child_windows(@handle,'Msg').map{|child_handle| Window.new child_handle}
518
- end
519
-
520
- # emulate click of the control identified by id
521
- def click(id)
522
- h = child(id).handle
523
- rectangle = [0, 0, 0, 0].pack 'LLLL'
524
- get_window_rect h, rectangle
525
- left, top, right, bottom = rectangle.unpack 'LLLL'
526
- center = [(left + right) / 2, (top + bottom) / 2]
527
- set_cursor_pos *center
528
- mouse_event MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0
529
- mouse_event MOUSEEVENTF_LEFTUP, 0, 0, 0, 0
530
- end
531
-
532
- def close
533
- post_message @handle, WM_SYSCOMMAND, SC_CLOSE, 0
534
- end
535
-
536
- def wait_for_close
537
- timeout(WG_CLOSE_TIMEOUT) do
538
- sleep WG_SLEEP_DELAY while window_visible?(@handle)
539
- end
540
- end
541
-
542
- def text
543
- buffer = "\x0" * 2048
544
- length = send_message @handle, WM_GETTEXT, buffer.length, buffer
545
- length == 0 ? '' : buffer[0..length - 1]
546
- end
547
- end
548
-
549
607
  end
550
608
  end
data/spec/spec_helper.rb CHANGED
@@ -3,20 +3,27 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
3
  require 'spec'
4
4
  require 'spec/autorun'
5
5
 
6
+ $debug = true
7
+
6
8
  # Customize RSpec with my own extensions
7
9
  module SpecMacros
8
10
 
9
11
  # wrapper for it method that extracts description from example source code, such as:
10
12
  # spec { use{ function(arg1 = 4, arg2 = 'string') }}
11
13
  def spec &block
12
- it description_from(*block.source_location), &block
14
+ # p (block.methods-Object.methods).sort; exit
15
+ if RUBY_PLATFORM =~ /java/
16
+ it 'dummy JRuby description', &block
17
+ else
18
+ it description_from(*block.source_location), &block
19
+ end
13
20
  end
14
21
 
15
22
  # reads description line from source file and drops external brackets (like its{}, use{}
16
23
  def description_from(file, line)
17
- File.open(file) do |f|
18
- f.lines.to_a[line-1].gsub( /(spec.*?{)|(use.*?{)|}/, '' ).strip
19
- end
24
+ File.open(file) do |f|
25
+ f.lines.to_a[line-1].gsub( /(spec.*?{)|(use.*?{)|}/, '' ).strip
26
+ end
20
27
  end
21
28
  end
22
29
 
@@ -24,6 +31,7 @@ Spec::Runner.configure { |config| config.extend(SpecMacros) }
24
31
 
25
32
  module WinTest
26
33
 
34
+ TEST_KEY_DELAY = 0.001
27
35
  TEST_IMPOSSIBLE = 'Impossible'
28
36
  TEST_CONVERSION_ERROR = /Can.t convert/
29
37
  TEST_SLEEP_DELAY = 0.01
@@ -32,14 +40,15 @@ module WinTest
32
40
  TEST_WIN_TITLE = 'LockNote - Steganos LockNote'
33
41
  TEST_WIN_CLASS = 'ATL:00434098'
34
42
  TEST_WIN_RECT = [710, 400, 1210, 800]
43
+ TEST_STATUSBAR_CLASS = 'msctls_statusbar32'
35
44
  TEST_TEXTAREA_CLASS = 'ATL:00434310'
36
45
 
37
46
  def use
38
- lambda {yield}.should_not raise_error
47
+ lambda{yield}.should_not raise_error
39
48
  end
40
49
 
41
50
  def any_block
42
- lambda {|*args| args}
51
+ lambda{|*args| args}
43
52
  end
44
53
 
45
54
  def any_handle
@@ -53,5 +62,4 @@ module WinTest
53
62
  def not_a_handle
54
63
  123
55
64
  end
56
-
57
65
  end