win 0.0.4 → 0.0.6

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/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