11# -*- coding: utf-8 -*-
22'''
3- Copyright (C) 2012-2019 Diego Torres Milano
3+ Copyright (C) 2012-2022 Diego Torres Milano
44Created on oct 6, 2014
55
66Licensed under the Apache License, Version 2.0 (the "License");
3131from com .dtmilano .android .common import profileEnd
3232from com .dtmilano .android .common import profileStart
3333from com .dtmilano .android .concertina import Concertina
34+ from com .dtmilano .android .keyevent import KEY_EVENT
3435from com .dtmilano .android .viewclient import ViewClient , View
3536
3637__version__ = '21.3.0'
@@ -130,6 +131,7 @@ class Operation:
130131 OPEN_QUICK_SETTINGS = 'open_quick_settings'
131132 TYPE = 'type'
132133 PRESS = 'press'
134+ PRESS_UI_AUTOMATOR_HELPER = 'press_ui_automator_helper'
133135 PRESS_BACK = 'press_back'
134136 PRESS_BACK_UI_AUTOMATOR_HELPER = 'press_back_ui_automator_helper'
135137 PRESS_HOME = 'press_home'
@@ -144,6 +146,8 @@ class Operation:
144146 SWIPE_UI_AUTOMATOR_HELPER = 'swipe_ui_automator_helper'
145147 TRAVERSE = 'traverse'
146148 VIEW_SNAPSHOT = 'view_snapshot'
149+ WAIT_FOR_IDLE_UI_AUTOMATOR_HELPER = 'wait_for_idle_ui_automator_helper'
150+ WAIT_FOR_WINDOW_UPDATE_UI_AUTOMATOR_HELPER = 'wait_for_window_update_ui_automator_helper'
147151 WAKE = 'wake'
148152
149153 COMMAND_NAME_OPERATION_MAP = {'flingBackward' : FLING_BACKWARD , 'flingForward' : FLING_FORWARD ,
@@ -167,6 +171,7 @@ class Culebron:
167171
168172 KEYSYM_TO_KEYCODE_MAP = {
169173 'Home' : 'HOME' ,
174+ 'abovedot' : 'HOME' , # Option+H on macOS
170175 'BackSpace' : 'BACK' ,
171176 'Left' : 'DPAD_LEFT' ,
172177 'Right' : 'DPAD_RIGHT' ,
@@ -252,6 +257,7 @@ def __init__(self, vc, device, serialno, printOperation, scale=1, concertina=Fal
252257 '''
253258
254259 self .vc = vc
260+ self .dump = None
255261 if 'CONCERTINA' in self .vc .debug :
256262 global DEBUG_CONCERTINA
257263 DEBUG_CONCERTINA = self .vc .debug ['CONCERTINA' ] is not None
@@ -605,15 +611,15 @@ def populateViewTree(self, view):
605611 parent_unique_id = parent .getUniqueId ()
606612 except AttributeError :
607613 vuid = view .unique_id
608- #FIXME
609- #is_target = view.is_target
614+ # FIXME
615+ # is_target = view.is_target
610616 is_target = False
611617 text = view .text
612618 parent = view .parent
613619 if parent :
614- #FIXME:
620+ # FIXME:
615621 # parent is an int
616- #parent_unique_id = parent.unique_id
622+ # parent_unique_id = parent.unique_id
617623 parent_unique_id = 0
618624 if parent is None :
619625 self .viewTree .insert ('' , tkinter .END , vuid , text = text )
@@ -646,7 +652,8 @@ def findTargets(self):
646652 window = - 1
647653 if self .vc :
648654 dump = self .vc .dump (window = window , sleep = 0.1 )
649- self .printOperation (None , Operation .DUMP , window , dump )
655+ if not self .vc .uiAutomatorHelper :
656+ self .printOperation (None , Operation .DUMP , window , dump )
650657 else :
651658 dump = []
652659 self .dump = dump
@@ -676,7 +683,7 @@ def findTargets(self):
676683
677684 # FIXME: we are not populating the view tree now
678685 # there are some problems with culebratester2
679- #if self.vc:
686+ # if self.vc:
680687 # self.vc.traverse(transform=self.populateViewTree)
681688
682689 def getViewContainingPointAndGenerateTestCondition (self , x , y ):
@@ -787,7 +794,10 @@ def findBestCandidate(view):
787794 candidate = candidates [0 ]
788795 self .touchView (candidate , v if candidate != v else None )
789796
790- self .printOperation (None , Operation .SLEEP , Operation .DEFAULT )
797+ if self .vc .uiAutomatorHelper :
798+ self .printOperation (None , Operation .WAIT_FOR_WINDOW_UPDATE_UI_AUTOMATOR_HELPER , Operation .DEFAULT )
799+ else :
800+ self .printOperation (None , Operation .SLEEP , Operation .DEFAULT )
791801 self .vc .sleep (5 )
792802 self .takeScreenshotAndShowItOnWindow ()
793803
@@ -975,47 +985,65 @@ def onButton3Pressed(self, event):
975985 print ("onButton3Pressed((" , event .x , ", " , event .y , "))" , file = sys .stderr )
976986 self .showPopupMenu (event )
977987
978- def command (self , keycode ) :
979- '''
988+ def command (self , keycode : str ) -> None :
989+ """
980990 Presses a key.
981991 Generates the actual key press on the device and prints the line in the script.
982- '''
983992
984- self .device .press (keycode )
985- self .printOperation (None , Operation .PRESS , keycode )
993+ :param keycode the keycode name
994+ """
995+
996+ if self .vc .uiAutomatorHelper :
997+ try :
998+ if not keycode .startswith ('KEYCODE_' ):
999+ keycode = f'KEYCODE_{ keycode } '
1000+ self .vc .uiAutomatorHelper .ui_device .press_key_code (KEY_EVENT [f'{ keycode } ' ])
1001+ self .printOperation (None , Operation .PRESS_UI_AUTOMATOR_HELPER , keycode )
1002+ except Exception as e :
1003+ print (e , file = sys .stderr )
1004+ else :
1005+ self .device .press (keycode )
1006+ self .printOperation (None , Operation .PRESS , keycode )
9861007
9871008 def onKeyPressed (self , event ):
9881009 if DEBUG_KEY :
9891010 print ("onKeyPressed(" , repr (event ), ")" , file = sys .stderr )
990- print (" event" , type (event .char ), len (event .char ), repr (
991- event . char ), " keysym=" , event .keysym , " keycode=" , event .keycode , event .type , " state=" , event .state ,
1011+ print (f' char: type= { type (event .char )} len= { len (event .char )} repr= { repr ( event . char ) } \n ' +
1012+ f' keysym={ event .keysym } , keycode={ event .keycode } , type= { event .type } , state={ event .state } ' ,
9921013 file = sys .stderr )
9931014 print (" events disabled:" , self .areEventsDisabled , file = sys .stderr )
9941015 if self .areEventsDisabled :
9951016 if DEBUG_KEY :
996- print ("ignoring event" , file = sys .stderr )
1017+ print (" ignoring event" , file = sys .stderr )
9971018 self .canvas .update_idletasks ()
9981019 return
9991020
10001021 char = event .char
10011022 keysym = event .keysym
1023+ state = event .state
1024+
1025+ # Manual way to get the modifiers
1026+ # https://stackoverflow.com/a/34482048/236465
1027+ ctrl = (state & 0x4 ) != 0
1028+ alt = (state & 0x8 ) != 0 or (state & 0x80 ) != 0
1029+ shift = (state & 0x1 ) != 0
1030+
1031+ if ctrl :
1032+ try :
1033+ return getattr (self , f'onCtrl{ keysym .upper ()} ' )(event )
1034+ except AttributeError :
1035+ pass
10021036
10031037 if len (char ) == 0 and not (
10041038 keysym in Culebron .KEYSYM_TO_KEYCODE_MAP or keysym in Culebron .KEYSYM_CULEBRON_COMMANDS ):
10051039 if DEBUG_KEY :
1006- print (" returning because len(char) == 0" , file = sys .stderr )
1040+ print (f' returning because len(char) == 0 keysym= { keysym } ' , file = sys .stderr )
10071041 return
10081042
10091043 ###
10101044 ### internal commands: no output to generated script
10111045 ###
1012- try :
1013- handler = getattr (self , 'onCtrl%s' % self .UPPERCASE_CHARS [ord (char ) - 1 ])
1014- except :
1015- handler = None
1016- if handler :
1017- return handler (event )
1018- elif keysym == 'F1' :
1046+ if keysym == 'F1' :
10191047 self .showHelp ()
10201048 return
10211049 elif keysym == 'F5' :
@@ -1056,7 +1084,7 @@ def onKeyPressed(self, event):
10561084 else :
10571085 self .command (Culebron .KEYSYM_TO_KEYCODE_MAP [keysym ])
10581086 # ALT-M
1059- elif keysym == 'm' and event . state == 24 :
1087+ elif keysym == 'm' and alt :
10601088 if DEBUG_KEY :
10611089 print ("Sending MENU" , file = sys .stderr )
10621090 self .command ('MENU' )
@@ -1072,8 +1100,6 @@ def onKeyPressed(self, event):
10721100 pass
10731101 else :
10741102 self .command (char )
1075- # commented out (profile)
1076- # time.sleep(1)
10771103 self .takeScreenshotAndShowItOnWindow ()
10781104
10791105 def wake (self ):
@@ -1152,7 +1178,8 @@ def saveViewSnapshot(self, view):
11521178
11531179 if not view :
11541180 raise ValueError ("view must be provided to take snapshot" )
1155- filename = self .snapshotDir + os .sep + '${serialno}-' + View .variableNameFromId (view ) + '-${timestamp}' + '.' + self .snapshotFormat .lower ()
1181+ filename = self .snapshotDir + os .sep + '${serialno}-' + View .variableNameFromId (
1182+ view ) + '-${timestamp}' + '.' + self .snapshotFormat .lower ()
11561183 d = FileDialog (self , self .device .substituteDeviceTemplate (filename ))
11571184 saveAsFilename = d .askSaveAsFilename ()
11581185 if saveAsFilename :
@@ -2306,7 +2333,7 @@ def buttonBox(self):
23062333 self .bind ("<Return>" , self .onDismiss )
23072334 self .bind ("<Escape>" , self .onDismiss )
23082335
2309- box .grid (row = 1 , column = 1 )
2336+ box .grid (row = 2 , column = 1 )
23102337
23112338 def onDismiss (self , event = None ):
23122339 # put focus back to the parent window's canvas
0 commit comments