Module: Calabash::Cucumber::KeyboardHelpers

Includes:
TestsHelpers
Included in:
Operations
Defined in:
lib/calabash-cucumber/keyboard_helpers.rb

Constant Summary collapse

KEYPLANE_NAMES =
{
    :small_letters => 'small-letters',
    :capital_letters => 'capital-letters',
    :numbers_and_punctuation => 'numbers-and-punctuation',
    :first_alternate => 'first-alternate',
    :numbers_and_punctuation_alternate => 'numbers-and-punctuation-alternate'
}
UIA_SUPPORTED_CHARS =
{
      'Delete' => '\b',
      'Return' => '\n'
      # these are not supported yet and I am pretty sure that they
      # cannot be touched by passing an escaped character and instead
      # the must be found using UIAutomation calls.  -jmoody
      #'Dictation' => nil,
      #'Shift' => nil,
      #'International' => nil,
      #'More' => nil,
}

Instance Method Summary collapse

Methods included from TestsHelpers

#check_element_does_not_exist, #check_element_exists, #check_view_with_mark_exists, #classes, #each_cell, #each_cell_and_back, #element_does_not_exist, #element_exists, #navigation_path, #query_map, #view_with_mark_exists

Methods included from FailureHelpers

#fail, #screenshot, #screenshot_and_raise, #screenshot_embed

Instance Method Details

#_current_keyplaneObject

returns the current keyplane



327
328
329
330
331
332
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 327

def _current_keyplane
  kp_arr = _do_keyplane(
      lambda { query("view:'UIKBKeyplaneView'", 'keyplane', 'componentName') },
      lambda { query("view:'UIKBKeyplaneView'", 'keyplane', 'name') })
  kp_arr.first.downcase
end

#_do_keyplane(kbtree_proc, keyplane_proc) ⇒ Object

process a keyplane

raises an error if there is not visible keyplane



386
387
388
389
390
391
392
393
394
395
396
397
398
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 386

def _do_keyplane(kbtree_proc, keyplane_proc)
  desc = query("view:'UIKBKeyplaneView'", 'keyplane')
  fail('No keyplane (UIKBKeyplaneView keyplane)') if desc.empty?
  fail('Several keyplanes (UIKBKeyplaneView keyplane)') if desc.count > 1
  kp_desc = desc.first
  if /^<UIKBTree/.match(kp_desc)
    #ios5+
    kbtree_proc.call
  elsif /^<UIKBKeyplane/.match(kp_desc)
    #ios4
    keyplane_proc.call
  end
end

#_ensure_can_enter_text(opts = {}) ⇒ Object

ensures that there is a keyboard to enter text

IMPORTANT will always raise an error when the keyboard is split and there is no run_loop i.e. UIAutomation is not available

the default options are

:screenshot +true+ raise with a screenshot
:skip +false+ skip any checking (a nop) - used when iterating over
keyplanes for keys


165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 165

def _ensure_can_enter_text(opts={})
  default_opts = {:screenshot => true,
                  :skip => false}
  opts = default_opts.merge(opts)
  return if opts[:skip]

  screenshot = opts[:screenshot]
  unless keyboard_visible?
    msg = 'no visible keyboard'
    if screenshot
      screenshot_and_raise msg
    else
      raise msg
    end
  end

  if split_keyboard_visible? and uia_not_available?
    msg = 'cannot type on a split keyboard without launching with Instruments'
    if screenshot
      screenshot_and_raise msg
    else
      raise msg
    end
  end
end

#_ipad_keyboard_modesObject

returns an array of possible ipad keyboard modes



120
121
122
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 120

def _ipad_keyboard_modes
  [:docked, :undocked, :split]
end

#_point_for_ipad_keyboard_mode_keyObject

returns the activation point of the iPad keyboard mode key.

the mode key is also known as the Hide keyboard key.

raises an error when

  • the device is not an iPad

  • the app was not launched with instruments i.e. there is no run_loop



432
433
434
435
436
437
438
439
440
441
442
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 432

def _point_for_ipad_keyboard_mode_key
  raise 'the keyboard mode does not exist on the on the iphone' if device_family_iphone?
  raise 'cannot detect keyboard mode key without launching with instruments' unless uia_available?
  res = send_uia_command({:command => "#{_query_uia_hide_keyboard_button}.rect()"})
  origin = res['value']['origin']
  {:x => origin['x'], :y => origin['y']}

  # this did not work.
  #size = res['value']['size']
  #{:x => (origin['x'] + (size['width']/2)), :y => (origin['y'] + (size['height']/2))}
end

#_qstr_for_keyboardObject

returns a query string for detecting a keyboard



34
35
36
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 34

def _qstr_for_keyboard
  "view:'UIKBKeyplaneView'"
end

#_query_for_keyboard_mode_keyObject

returns a query for touching the iPad keyboard mode key.

the mode key is also know as the Hide keyboard key.

use _point_for_keyboard_mode_key if there is a run_loop available

raises an error when

  • the device is not an iPad

  • the app was launched with Instruments i.e. there is a run_loop



498
499
500
501
502
503
504
505
506
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 498

def _query_for_keyboard_mode_key
  raise 'cannot detect keyboard mode key on iphone' if device_family_iphone?
  if uia_available?
    raise "UIA is available, use '_point_for_keyboard_mode_key' instead"
  end
  qstr = "view:'UIKBKeyView'"
  idx = query(qstr).count - 1
  "#{qstr} index:#{idx}"
end

#_query_for_touch_for_keyboard_mode_option(top_or_bottom, mode) ⇒ Object

returns a query string for touching one of the options that appears when the iPad mode key is touched and held.

the mode key is also know as the Hide keyboard key.

valid arguments are:

top_or_bottom :top | :bottom
mode :docked | :undocked | :skipped

use _point_for_keyboard_mode_key if there is a run_loop available

raises an error when

  • the device is not an iPad

  • the app was launched with Instruments i.e. there is a run_loop

  • it is passed invalid arguments



461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 461

def _query_for_touch_for_keyboard_mode_option(top_or_bottom, mode)
  raise 'the keyboard mode does not exist on the iphone' if device_family_iphone?

  if uia_available?
    raise "UIA is available, use '_point_for_keyboard_mode_key' instead"
  end

  valid = [:top, :bottom]
  unless valid.include? top_or_bottom
    raise "expected '#{top_or_bottom}' to be one of '#{valid}'"
  end

  valid = [:split, :undocked, :docked]
  unless valid.include? mode
    raise "expected '#{mode}' to be one of '#{valid}'"
  end

  hash = {:split => {:top => 'Merge',
                     :bottom => 'Dock and Merge'},
          :undocked => {:top => 'Dock',
                        :bottom => 'Split'},
          :docked => {:top => 'Undock',
                      :bottom => 'Split'}}
  mark = hash[mode][top_or_bottom]
  "label marked:'#{mark}'"
end

#_query_uia_hide_keyboard_buttonObject

returns a query string for finding the iPad ‘Hide keyboard’ button



401
402
403
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 401

def _query_uia_hide_keyboard_button
  "uia.keyboard().buttons()['Hide keyboard']"
end

#_search_keyplanes_and_enter_char(chr, visited = Set.new) ⇒ Object

searches the available keyplanes for chr and if it is found, types it

this is a recursive function

IMPORTANT: use the KEYPLANE_SEARCH_STEP_PAUSE variable to control how quickly the next keyplane is searched. increase this value if you encounter problems with missed keystrokes.

raises an error if the chr cannot be found



343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 343

def _search_keyplanes_and_enter_char(chr, visited=Set.new)
  cur_kp = _current_keyplane
  begin
    keyboard_enter_char(chr, {:should_screenshot => false})
    return true #found
  rescue
    pause = (ENV['KEYPLANE_SEARCH_STEP_PAUSE'] || 0.2).to_f
    sleep (pause) if pause > 0

    visited.add(cur_kp)

    #figure out keyplane alternates
    props = _do_keyplane(
        lambda { query("view:'UIKBKeyplaneView'", 'keyplane', 'properties') },
        lambda { query("view:'UIKBKeyplaneView'", 'keyplane', 'attributes', 'dict') }
    ).first

    known = KEYPLANE_NAMES.values

    found = false
    keyplane_selection_keys = ['shift', 'more']
    keyplane_selection_keys.each do |key|
      sleep (pause) if pause > 0
      plane = props["#{key}-alternate"]
      if known.member?(plane) and (not visited.member?(plane))
        keyboard_enter_char(key.capitalize, {:should_screenshot => false})
        found = _search_keyplanes_and_enter_char(chr, visited)
        return true if found
        #not found => try with other keyplane selection key
        keyplane_selection_keys.delete(key)
        other_key = keyplane_selection_keys.last
        keyboard_enter_char(other_key.capitalize, {:should_screenshot => false})
        found = _search_keyplanes_and_enter_char(chr, visited)
        return true if found
      end
    end
    return false
  end
end

#_touch_bottom_keyboard_mode_rowObject

touches the bottom option on the popup dialog that is presented when the the iPad keyboard mode key is touched and held.

the mode key is also know as the Hide keyboard key.

the mode key allows the user to undock, dock, or split the keyboard.



514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 514

def _touch_bottom_keyboard_mode_row
  mode = ipad_keyboard_mode
  if uia_available?
    start_pt = _point_for_ipad_keyboard_mode_key
    # there are 10 pt btw the key and the popup and the row is 50 pt
    y_offset = 10 + 25
    end_pt = {:x => (start_pt[:x] - 40), :y => (start_pt[:y] - y_offset)}
    uia_pan_offset(start_pt, end_pt, {})
  else
    pan(_query_for_keyboard_mode_key, nil, {:duration => 1.0})
    touch(_query_for_touch_for_keyboard_mode_option(:bottom, mode))
    sleep(0.5)
  end
  2.times { sleep(0.5) }
end

#_touch_top_keyboard_mode_rowObject

touches the top option on the popup dialog that is presented when the the iPad keyboard mode key is touched and held.

the mode key is also know as the Hide keyboard key.

the mode key allows the user to undock, dock, or split the keyboard.



536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 536

def _touch_top_keyboard_mode_row
  mode = ipad_keyboard_mode
  if uia_available?
    start_pt = _point_for_ipad_keyboard_mode_key
    # there are 10 pt btw the key and the popup and each row is 50 pt
    # NB: no amount of offsetting seems to allow touching the top row
    #     when the keyboard is split
    y_offset = 10 + 50 + 25
    end_pt = {:x => (start_pt[:x] - 40), :y => (start_pt[:y] - y_offset)}
    uia_pan_offset(start_pt, end_pt, {:duration => 1.0})
  else
    pan(_query_for_keyboard_mode_key, nil, {})
    touch(_query_for_touch_for_keyboard_mode_option(:top, mode))
    sleep(0.5)
  end
  2.times { sleep(0.5) }
end

#_wait_for_keyboard_in_mode(mode, opts = {}) ⇒ Object



668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 668

def _wait_for_keyboard_in_mode(mode, opts={})
  default_opts = {:post_timeout => 1.0}
  opts = default_opts.merge(opts)
  begin
    wait_for(opts) do
      case mode
        when :split then
          split_keyboard_visible?
        when :undocked
          undocked_keyboard_visible?
        when :docked
          docked_keyboard_visible?
        else
          screenshot_and_raise "expected '#{mode}' to be one of #{_ipad_keyboard_modes}"
      end
    end
  rescue
    actual = ipad_keyboard_mode
    o = status_bar_orientation
    screenshot_and_raise "expected keyboard to be '#{mode}' but found '#{actual}' in orientation '#{o}'"
  end
end

#await_keyboardObject

DEPRECATED: Use wait_for_keyboard instead.



114
115
116
117
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 114

def await_keyboard
  _deprecated('0.9.163', "use 'wait_for_keyboard' instead", :warn)
  wait_for_keyboard
end

#dismiss_ipad_keyboardObject

dismisses a iPad keyboard by touching the ‘Hide keyboard’ button and waits for the keyboard to disappear

raises an error if the device is not an iPad. the dismiss keyboard key does not exist on the iPhone or iPod



410
411
412
413
414
415
416
417
418
419
420
421
422
423
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 410

def dismiss_ipad_keyboard
  screenshot_and_raise 'cannot dismiss keyboard on iphone' if device_family_iphone?

  if uia_available?
    send_uia_command({:command =>  "#{_query_uia_hide_keyboard_button}.tap()"})
  else
    touch(_query_for_keyboard_mode_key)
  end

  opts = {:timeout_message => 'keyboard did not disappear'}
  wait_for(opts) do
    not keyboard_visible?
  end
end

#docked_keyboard_visible?Boolean

returns true if a docked keyboard is visible.

a docked keyboard is pinned to the bottom of the view.

keyboards on the iPhone and iPod are docked.

Returns:

  • (Boolean)


43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 43

def docked_keyboard_visible?
  res = query(_qstr_for_keyboard).first
  return false if res.nil?

  return true if device_family_iphone?

  # ipad
  rect = res['rect']
  o = status_bar_orientation.to_sym
  case o
    when :left then
      rect['center_x'] == 592 and rect['center_y'] == 512
    when :right then
      rect['center_x'] == 176 and rect['center_y'] == 512
    when :up then
      rect['center_x'] == 384 and rect['center_y'] == 132
    when :down then
      rect['center_x'] == 384 and rect['center_y'] == 892
    else
      false
  end

end

#doneObject

touches the keyboard action key

the action key depends on the keyboard.

some examples include:

  • Return

  • Next

  • Go

  • Join

  • Search

not all keyboards have an action key raises an error if the key cannot be entered



322
323
324
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 322

def done
  tap_keyboard_action_key
end

#ensure_docked_keyboardObject

ensures that the iPad keyboard is docked

docked means the keyboard is pinned to bottom of the view

if the device is not an iPad, this is behaves like a call to wait_for_keyboard

raises an error when

  • there is no visible keyboard or

  • the docked keyboard cannot be achieved



564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 564

def ensure_docked_keyboard
  wait_for_keyboard

  return if device_family_iphone?

  mode = ipad_keyboard_mode
  case mode
    when :split then
      _touch_bottom_keyboard_mode_row
    when :undocked then
      _touch_top_keyboard_mode_row
    when :docked then
      # already docked
    else
    screenshot_and_raise "expected '#{mode}' to be one of #{_ipad_keyboard_modes}"
  end

  begin
    wait_for({:post_timeout => 1.0}) do
      docked_keyboard_visible?
    end
  rescue
    mode = ipad_keyboard_mode
    o = status_bar_orientation
    screenshot_and_raise "expected keyboard to be ':docked' but found '#{mode}' in orientation '#{o}'"
  end
end

#ensure_split_keyboardObject

ensures that the iPad keyboard is split

split means the keyboard is floating in the middle of the view and is split into two sections to enable faster thumb typing.

if the device is not an iPad, this is behaves like a call to wait_for_keyboard

raises an error when

  • there is no visible keyboard or

  • the an undocked keyboard cannot be achieved



648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 648

def ensure_split_keyboard
  wait_for_keyboard

  return if device_family_iphone?

  mode = ipad_keyboard_mode
  case mode
    when :split then
      # already split
    when :undocked then
      _touch_bottom_keyboard_mode_row
    when :docked then
      _touch_bottom_keyboard_mode_row
    else
      screenshot_and_raise "expected '#{mode}' to be one of #{_ipad_keyboard_modes}"
  end

  _wait_for_keyboard_in_mode(:split)
end

#ensure_undocked_keyboardObject

ensures that the iPad keyboard is undocked

undocked means the keyboard is floating in the middle of the view

if the device is not an iPad, this is behaves like a call to wait_for_keyboard

raises an error when

  • there is no visible keyboard or

  • the an undocked keyboard cannot be achieved



603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 603

def ensure_undocked_keyboard
  wait_for_keyboard()

  return if device_family_iphone?

  mode = ipad_keyboard_mode
  case mode
    when :split then
      # keep these condition separate because even though they do the same
      # thing, the else condition is a hack
      if ios5?
        # iOS 5 has no 'Merge' feature in split keyboard, so dock first then
        # undock from docked mode
        _touch_bottom_keyboard_mode_row
        _wait_for_keyboard_in_mode(:docked)
      else
        # in iOS > 5, it seems to be impossible consistently touch the
        # the top keyboard mode popup button, so we punt
        _touch_bottom_keyboard_mode_row
        _wait_for_keyboard_in_mode(:docked)
      end
      _touch_top_keyboard_mode_row
    when :undocked then
      # already undocked
    when :docked then
      _touch_top_keyboard_mode_row
    else
      screenshot_and_raise "expected '#{mode}' to be one of #{_ipad_keyboard_modes}"
  end

  _wait_for_keyboard_in_mode(:undocked)
end

#ipad_keyboard_mode(opts = {}) ⇒ Object

returns the keyboard mode

                keyboard is pinned to bottom of the view #=> :docked
          keyboard is floating in the middle of the view #=> :undocked
                          keyboard is floating and split #=> :split
no keyboard and :raise_on_no_visible_keyboard == +false+ #=> :unknown

raises an error if the device is not an iPad

raises an error if the :raise_on_no_visible_keyboard is true (default) and no keyboard is visible

set :raise_on_no_visible_keyboard to false to use in wait functions



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 138

def ipad_keyboard_mode(opts = {})
  raise 'the keyboard mode does not exist on the iphone or ipod' if device_family_iphone?

  default_opts = {:raise_on_no_visible_keyboard => true}
  opts = default_opts.merge(opts)
  if opts[:raise_on_no_visible_keyboard]
    screenshot_and_raise 'there is no visible keyboard' unless keyboard_visible?
    return :docked if docked_keyboard_visible?
    return :undocked if undocked_keyboard_visible?
    :split
  else
    return :docked if docked_keyboard_visible?
    return :undocked if undocked_keyboard_visible?
    return :split if split_keyboard_visible?
    :unknown
  end
end

#keyboard_enter_char(chr, opts = {}) ⇒ Object

use keyboard to enter chr

IMPORTANT: use the POST_ENTER_KEYBOARD environmental variable to slow down the typing; adds a wait after each character is touched. this can fix problems where the typing is too fast and characters are skipped.

there are several special ‘characters’, some of which do not appear on all keyboards:

  • ‘Delete’

  • ‘Return’

raises error if there is no visible keyboard or the keyboard is not supported

use the should_screenshot to control whether or not to raise an error if chr is not found



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 208

def keyboard_enter_char(chr, opts={})
  unless opts.is_a?(Hash)
   msg = "you should no longer pass a boolean as the second arg; pass {:should_screenshot => '#{opts}'}  hash instead"
   _deprecated('0.9.163', msg, :warn)
   opts = {:should_screenshot => opts}
  end

  default_opts = {:should_screenshot => true,
                  # introduce a small wait to avoid skipping characters
                  # keep this as short as possible
                  :wait_after_char => (ENV['POST_ENTER_KEYBOARD'] || 0.05).to_f}

  opts = default_opts.merge(opts)

  should_screenshot = opts[:should_screenshot]
  _ensure_can_enter_text({:screenshot => should_screenshot,
                          :skip => (not should_screenshot)})

  if uia_available?
    if chr.length == 1
      uia_type_string chr
    else
      code = UIA_SUPPORTED_CHARS[chr]

      unless code
        raise "Char #{chr} is not yet supported in when typing with Instruments"
      end

      # on iOS 6, the char code is _not_ \b
      #
      # as an aside, on iOS 7, the same approach (tap the 'Delete' key) also works
      if ios6? and code.eql?(UIA_SUPPORTED_CHARS['Delete'])
        uia("uia.keyboard().keys().firstWithName('Delete').tap()")
      else
        uia_type_string(code)
      end
    end
    res = {'results' => []}
  else
    res = http({:method => :post, :path => 'keyboard'},
               {:key => chr, :events => load_playback_data('touch_done')})
    res = JSON.parse(res)
    if res['outcome'] != 'SUCCESS'
      msg = "Keyboard enter failed failed because: #{res['reason']}\n#{res['details']}"
      if should_screenshot
        screenshot_and_raise msg
      else
        raise msg
      end
    end
  end

  if ENV['POST_ENTER_KEYBOARD']
    w = ENV['POST_ENTER_KEYBOARD'].to_f
    if w > 0
      sleep(w)
    end
  end
  pause = opts[:wait_after_char]
  sleep(pause) if pause > 0
  res['results']
end

#keyboard_enter_text(text) ⇒ Object

uses the keyboard to enter text

raises an error if the text cannot be entered



274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 274

def keyboard_enter_text(text)
  _ensure_can_enter_text
  if uia_available?
    uia_type_string(text)
  else
    text.each_char do |ch|
      begin
        keyboard_enter_char(ch, {:should_screenshot => false})
      rescue
        _search_keyplanes_and_enter_char(ch)
      end
    end
  end
end

#keyboard_visible?Boolean

returns true if there is a visible keyboard

Returns:

  • (Boolean)


96
97
98
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 96

def keyboard_visible?
  docked_keyboard_visible? or undocked_keyboard_visible? or split_keyboard_visible?
end

#split_keyboard_visible?Boolean

returns true if a split keyboard is visible.

a split keyboard is floats in the middle of the view and is split to allow faster thumb typing

returns false if the device is not an iPad; all keyboards on the iPhone and iPod are docked

Returns:

  • (Boolean)


89
90
91
92
93
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 89

def split_keyboard_visible?
  return false if device_family_iphone?
  query("view:'UIKBKeyView'").count > 0 and
        element_does_not_exist(_qstr_for_keyboard)
end

#tap_keyboard_action_keyObject

touches the keyboard action key

the action key depends on the keyboard. some examples include:

  • Return

  • Next

  • Go

  • Join

  • Search

not all keyboards have an action key raises an error if the key cannot be entered



301
302
303
304
305
306
307
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 301

def tap_keyboard_action_key
  if uia_available?
    uia_type_string '\n'
  else
    keyboard_enter_char 'Return'
  end
end

#uia_keyboard_visible?Boolean

used for detecting keyboards that are not normally visible to calabash e.g. the keyboard on ‘z’

IMPORTANT this should only be used when the app does not respond to keyboard_visible?

raises an error if the there is no run_loop

Returns:

  • (Boolean)


698
699
700
701
702
703
704
705
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 698

def uia_keyboard_visible?
  unless uia_available?
    screenshot_and_raise 'only available if there is a run_loop i.e. the app was launched with Instruments'
  end
  # TODO refactor keyboard detection to use uia() function conventions (instead of UIATarget...)
  res = uia('UIATarget.localTarget().frontMostApp().keyboard()')['value']
  not res.eql?(':nil')
end

#uia_wait_for_keyboard(opts = {}) ⇒ Object

waits for a keyboard that is not normally visible to calabash e.g. the keyboard on MFMailComposeViewController

IMPORTANT this should only be used when the app does not respond to keyboard_visible?

raises an error if the there is no run_loop



714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 714

def uia_wait_for_keyboard(opts={})
  unless uia_available?
    screenshot_and_raise 'only available if there is a run_loop i.e. the app was launched with Instruments'
  end
  default_opts = {:timeout => 10,
                  :retry_frequency => 0.1,
                  :post_timeout => 0.5}
  opts = default_opts.merge(opts)
  unless opts[:timeout_message]
    msg = "waited for '#{opts[:timeout]}' for keyboard"
    opts[:timeout_message] = msg
  end

  wait_for(opts) do
    uia_keyboard_visible?
  end
end

#undocked_keyboard_visible?Boolean

returns true if an undocked keyboard is visible.

a undocked keyboard is floats in the middle of the view

returns false if the device is not an iPad; all keyboards on the iPhone and iPod are docked

Returns:

  • (Boolean)


73
74
75
76
77
78
79
80
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 73

def undocked_keyboard_visible?
  return false if device_family_iphone?

  res = query(_qstr_for_keyboard).first
  return false if res.nil?

  not docked_keyboard_visible?
end

#wait_for_keyboard(opts = {}) ⇒ Object

waits for a keyboard to appear and once it does appear waits for 0.3 seconds

raises an error if no keyboard appears



104
105
106
107
108
109
110
111
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 104

def wait_for_keyboard(opts={})
  default_opts = {:timeout_message => 'keyboard did not appear',
                  :post_timeout => 0.3}
  opts = default_opts.merge(opts)
  wait_for(opts) do
    keyboard_visible?
  end
end