OptionAction.py 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246
  1. # -*- coding:utf-8 -*-
  2. import os
  3. from enum import Enum
  4. from BaseLog import CBaseLog
  5. from ExtraData import CExtraData
  6. from OptionExcel import COptionExcel
  7. from OptionConfig import COptionConfig
  8. from OptionFocus import COptionFocus
  9. from OptionOCR import COptionOCR
  10. from ssat_sdk.tv_detect import *
  11. from ssat_sdk.device_manage.capturecard_manager import CCardManager
  12. from ssat_sdk.utils.string_util import strcmp
  13. g_level = ['First', 'Second', 'Third', 'Fourth', 'Fifth', 'Sixth',
  14. 'Seventh', 'Eighth', 'Ninth', 'Tenth', 'Eleventh', 'Twelfth']
  15. def strSplit(text):
  16. ret = []
  17. str_int = ''
  18. str_ch = ''
  19. ch_last = ' '
  20. for ch in text:
  21. if 47 < ord(ch) < 58:
  22. str_int += ch
  23. if str_ch.__len__():
  24. ret.append(str_ch)
  25. str_ch = ''
  26. else:
  27. if 47 < ord(ch_last) < 58 and ch == '.':
  28. str_int += ch
  29. if str_ch.__len__():
  30. ret.append(str_ch)
  31. str_ch = ''
  32. else:
  33. str_ch += ch
  34. if str_int.__len__():
  35. ret.append(str_int)
  36. str_int = ''
  37. ch_last = ch
  38. if str_ch.__len__():
  39. ret.append(str_ch)
  40. if str_int.__len__():
  41. ret.append(str_int)
  42. return ret
  43. # 枚举:value类型
  44. class VType(Enum):
  45. SelectType = 0
  46. InputType = 1
  47. RangeType = 2
  48. # 注意:所有不对外暴露的变量和函数需要私有化,以明确哪些接口和参数是对外的。
  49. # 这样便于后期维护时,根据对外的变量和函数来做处理。
  50. class COptionAction(CBaseLog):
  51. # ==============设备对象============== #
  52. # 红老鼠遥控对象;
  53. __redRat3 = TvOperator()
  54. # 创建视频采集对象
  55. __captureCard = CCardManager()
  56. # 图片切割对象
  57. __imgCMP = ImageCMP()
  58. def __init__(self, optionName, optionValue, optionConfig, optionExcel):
  59. CBaseLog.__init__(self)
  60. # 层级位置;
  61. self.__pos = 0
  62. # 目标option;
  63. self.__optionName = optionName
  64. # __optionValue可空;
  65. self.__optionValue = optionValue
  66. self.__optionExcel = optionExcel
  67. self.__optionConfig = optionConfig
  68. # 焦点定位及文字识别;
  69. self.__optionFocus = COptionFocus(optionConfig)
  70. self.__optionOCR = COptionOCR(optionConfig, optionExcel)
  71. if self.__optionExcel is None:
  72. self.error(u"表格对象空")
  73. # ==============常用对象数据==============;
  74. self.__optionPaths = self.__optionExcel.getOptionPaths(self.__optionName)
  75. # 如果__optionValue空则不取value表任何内容;
  76. if self.__optionValue != "" or self.__optionValue is not None:
  77. self.__optionValueInfo = self.__optionExcel.getOptionValueInfo(self.__optionName, self.__optionValue)
  78. self.__optionInfo = self.__optionExcel.getOptionInfo(self.__optionName)
  79. # 当前状态下的变量,与__pos对应;
  80. self.__curOptionName = ''
  81. self.__curOptionInfo = None
  82. self.__prevOptionName = ''
  83. self.__prevOptionInfo = None
  84. # 到达value节点后,记录value值(一般只用于range() 数值记录,其他值无意义);
  85. self.__optionValueText = ""
  86. # 获取一次当前层级信息;
  87. self.getCurOptionInfo()
  88. # 相关返回操作;
  89. self.__isEnterKeyInValue = False # 节点在value表时,是否发送enter key.
  90. self.__valueType = VType.SelectType # 节点在value表时,value值的类型(0:选择型, 1:输入型,2:range()数值型。)
  91. # 是否在Value层
  92. self.__isOnValueSheet = False
  93. @property
  94. def pos(self):
  95. return self.__pos
  96. @property
  97. def optionName(self):
  98. return self.__optionName
  99. @property
  100. def optionValue(self):
  101. return self.__optionValue
  102. @property
  103. def curOptionName(self):
  104. return self.__curOptionName
  105. @property
  106. def curOptionInfo(self):
  107. return self.__curOptionInfo
  108. @property
  109. def optionValueText(self):
  110. return self.__optionValueText
  111. @property
  112. def optionValueInfo(self):
  113. return self.__optionValueInfo
  114. @property
  115. def optionPaths(self):
  116. return self.__optionPaths
  117. '''
  118. 函数:截图并返回截图路径,如果当前option/optionValue含有layout坐标参数,则返回坐标截图;
  119. 参数:无
  120. 返回:截图路径;
  121. '''
  122. def takePicture(self):
  123. img = os.path.join(getSATTmpDIR(), "menutree_runpath.png")
  124. COptionAction.__captureCard.takePicture(img)
  125. if not os.path.exists(img):
  126. self.error(u"截图失败:%s" % img)
  127. retImg = img
  128. # 判断当前处于option层还是value层
  129. if self.__pos >= self.__optionPaths.__len__():
  130. curInfo = self.__optionValueInfo
  131. else:
  132. curInfo = self.__curOptionInfo
  133. # 判断当前层是否存在layout参数
  134. if "layout" in curInfo and 'bounds' in curInfo['layout']:
  135. if curInfo['layout']['bounds'] is ['']:
  136. self.info("当前option未配置layout参数")
  137. elif curInfo['layout']['bounds'].__len__() != 4:
  138. self.info("当前option的layout坐标配置异常:%s" % str(curInfo['layout']['bounds']))
  139. else:
  140. self.info("当前option的layout坐标为:%s" % str(curInfo['layout']['bounds']))
  141. retImg = os.path.join(getSATTmpDIR(), "menutree_runpath_layout.png")
  142. COptionAction.__imgCMP.saveCropPic(img, retImg, curInfo['layout']['bounds'])
  143. return retImg
  144. '''
  145. 函数:调用根节点快捷键(中间节点不需要快捷键;);
  146. 参数:无
  147. 返回:无
  148. '''
  149. def callFirstOptionShortCutKey(self):
  150. # 获取父节点等待时间(如果没找到,getParentWaitTime默认返回1)。
  151. waitTime = self.__optionConfig.getParentWaitTime(self.__optionPaths['First']['parent'])
  152. # 是否有另配置快捷按键代替根节点按键;
  153. '''
  154. 由于NT72561的source区分了tv信源与非tv信源,为了统一脚本,故others(first_key)新增逻辑:
  155. 1、优先读取option的others(first_key)信息;
  156. 2、options的others信息没有的情况下,读取parent的others(first_key)信息
  157. '''
  158. if 'shortcut_key' in self.__optionPaths['First']:
  159. self.sendKey(self.__optionPaths['First']['shortcut_key'], 1, waitTime)
  160. elif self.__optionPaths['First']['option_others'] != "":
  161. others = json.loads(self.__optionPaths['First']['option_others'])
  162. if 'first_key' in others:
  163. self.info(u"option:%s包含first_key信息,将使用first_key进入。\noption first_key:%s"%(self.__optionPaths['First']['option'], others['first_key']))
  164. keyList = others['first_key']
  165. for key in keyList:
  166. self.sendKey(key, 1, waitTime)
  167. elif self.__optionPaths['First']['others'] != "":
  168. others = json.loads(self.__optionPaths['First']['others'])
  169. if 'first_key' in others:
  170. self.info(u"parent:%s包含first_key信息,将使用first_key进入。\nparent first_key:%s"%(self.__optionPaths['First']['parent'], others['first_key']))
  171. keyList = others['first_key']
  172. for key in keyList:
  173. self.sendKey(key, 1, waitTime)
  174. else:
  175. self.sendKey(self.__optionPaths['First']['parent'], 1, waitTime)
  176. self.warn(u"表格没有shortcut_key字段,执行默认的parent按键:%s" % self.__optionPaths['First']['parent'])
  177. '''
  178. 函数:调用当前结点的toparent_key(叫back_key会简单点)
  179. 参数:
  180. curOptionName 当前层级的目标节点.
  181. 返回:无
  182. '''
  183. def callCurOptionBackKey(self, curOptionName):
  184. curOptionInfo = self.__optionExcel.getOptionInfo(curOptionName)
  185. if 'toparent_key' in self.__optionPaths[curOptionInfo['level']]:
  186. self.sendKey(self.__optionPaths[curOptionInfo['level']]['toparent_key'])
  187. else:
  188. self.error(u"表格没有toparent_key字段,执行默认按键return")
  189. self.sendKey('return')
  190. '''
  191. 函数:
  192. 参数:
  193. 返回:
  194. '''
  195. def inputUnlock(self, stdText, password=''):
  196. # 如果锁住,按ok会弹出输入密码框;
  197. self.sendKey("ok")
  198. # 获取密码;
  199. if password.__len__() == 0:
  200. password = self.__optionConfig.getSuperPassword("Password", "super")
  201. # 发送按键;
  202. for key in list(password):
  203. self.sendKey(key, 1, 0.2)
  204. time.sleep(1)
  205. # 发送ok键;
  206. self.sendKey('ok')
  207. # 判断是否成功输入密码;
  208. textPic = self.takePicture()
  209. # 遍历ocr类型;
  210. found = False
  211. ocrDict = [{"lan": "ChinesePRC+English", "type": 4}, {"lan": "ChinesePRC+English", "type": 253},
  212. {"lan": "ChinesePRC+English", "type": 10001}]
  213. for item in ocrDict:
  214. # 识别ocr;
  215. ocrText = self.__optionOCR.getImageText(textPic, item, {})
  216. ocrText = unicode(ocrText).lower()
  217. self.info("lan=%s,type=%d,ocr=%s" % (item["lan"], item["type"], ocrText))
  218. if ocrText in stdText or stdText == ocrText:
  219. found = True
  220. break
  221. return not found
  222. '''
  223. 函数:处理弹出密码框.
  224. 参数:
  225. 返回:Boolean, Boolean。
  226. 如何没有密码框处理,返回False,False。
  227. 如果有,且成功输入密码后密码框消失,返回True, True
  228. 注意:对应以前的dealOthers函数。
  229. '''
  230. def dealPasswordBox(self):
  231. parentOption = ''
  232. if self.isOnValueSheet():
  233. if self.__optionValueInfo is None or self.__optionValueInfo.__len__() == 0:
  234. self.error(u"当前value[%s]信息空" % str(self.__optionValue))
  235. return False, False
  236. others = self.__optionValueInfo['others']
  237. if others is None or others.__len__() == 0:
  238. self.info(u"[%s]others字段空" % str(self.__curOptionName))
  239. return False, False
  240. # 获取父节点
  241. parentOption = self.__optionValueInfo['option']
  242. else:
  243. getStatus, nextOptionInfo = self.getNextOptionInfo()
  244. if self.__curOptionInfo is None or self.__curOptionInfo.__len__() == 0:
  245. self.error(u"当前option[%s]信息空" % str(self.__curOptionName))
  246. return False, False
  247. others = self.__curOptionInfo['others']
  248. if others is None or others.__len__() == 0:
  249. self.info(u"[%s]others字段空" % str(self.__curOptionName))
  250. return False, False
  251. # 获取父节点;
  252. parentOption = self.__curOptionInfo['parent']
  253. # 转换为字典;
  254. others = json.loads(others)
  255. if "password" not in others:
  256. self.info(u"[%s]others没有密码框处理" % str(self.__curOptionName))
  257. return False, False
  258. password = self.__optionConfig.get_value("Password", others["password"])
  259. # 发送密码前,停2秒(因为像6586机芯响应很慢,密码框还没弹出就完成了密码输入的操作);
  260. time.sleep(2)
  261. # 发送按键;
  262. for key in list(password):
  263. self.sendKey(key, 1, 0.2)
  264. time.sleep(1)
  265. # 发送ok键;
  266. if not strcmp(others["enter_key"], "default"):
  267. self.sendKey(others["enter_key"])
  268. # 判断是否成功输入密码;
  269. current_uiPic = self.takePicture()
  270. # 此处findRectByIcon参数3传递的不是first_parent,而是当前option的parent;
  271. found, contourRect = self.__optionFocus.findFocusByIcon(current_uiPic, parentOption)
  272. return True, not found
  273. '''
  274. 函数:是否在父节点菜单上。一般在执行了callFirstOptionShortCutKey后调用;
  275. 参数:无
  276. 返回:Boolean, 数组(坐标)。 如:True, [0,0,1920,1080]
  277. 注意:由于所有父节点上的子项都共用一个图片定位参数,所以只要随意一个父节点的子项option即可获取定位参数;
  278. 测试:。
  279. '''
  280. def isOnFirstOption(self):
  281. pic = self.takePicture()
  282. return self.__optionFocus.findFocusByIcon(pic, self.__optionPaths['First']['option'])[0]
  283. '''
  284. 函数:是否在当前节点(移动后,判断是否移动到下一目标节点)上.
  285. 说明:
  286. 每次移动到下一目标节点(option)上时,self.__pos + 1,表示移动到下一层路径。
  287. 当self.__pos >= self.__optionPaths.__len__()时,表示到达value表格;
  288. 所以,该类的重点在self.__pos的移动;
  289. 参数:
  290. staticPic 静态图片路径。
  291. 主要用于将截图和聚焦、ocr识别分离,然后可以截图和聚焦中间添加其他处理。
  292. 返回:Boolean, 识别的文本/数字;
  293. 示例:
  294. '''
  295. def isOnTargetNode(self, staticPic=None):
  296. # 是否在value表中;
  297. isValueSheet = self.isOnValueSheet()
  298. self.info(u"当前层级在:%s" % ("value表" if isValueSheet else "路径表"))
  299. # 析出参数;
  300. if isValueSheet:
  301. curLevel = 'value'
  302. curParent = self.__optionPaths[g_level[self.__pos - 1]]['parent']
  303. curOption = self.__optionValueInfo['option']
  304. curOthers = self.__optionValueInfo['others']
  305. else:
  306. curLevel = g_level[self.__pos]
  307. curParent = self.__optionPaths[curLevel]['parent']
  308. curOption = self.__optionPaths[curLevel]['option']
  309. curOthers = self.__optionPaths[curLevel]['others']
  310. self.info("当前[%s]others=[%s]" % (curOption, curOthers))
  311. if curOthers.__len__() == 0:
  312. curOthers = {}
  313. else:
  314. curOthers = json.loads(curOthers)
  315. firstParent = self.__optionPaths['First']['parent']
  316. # 获取文本识别的参数;
  317. ocrConfigList = self.__optionConfig.getOptionOCRConfig(curOption)
  318. ocrThreshold = self.__optionConfig.getThresholdDict(firstParent) # 注意,此处使用firstParent;
  319. # 获取当前option的ocr值/value name下所有ocr值;
  320. if isValueSheet:
  321. if curOption.lower() == self.__optionName.lower():
  322. optionTextList = self.__optionExcel.getOptionValueText(curOption, self.__optionValue)
  323. else:
  324. optionTextList = self.__optionExcel.getOptionValueText(curOption)
  325. else:
  326. optionTextList = self.__optionExcel.getOptionText(curOption)
  327. # 获取option下所有兄弟项的ocr:option字典内容;
  328. siblingTextDict = self.__optionExcel.getOptionAllSiblingItemDict(curOption, not isValueSheet)
  329. # 获取所有option兄弟项(包括自己)的ocr值;
  330. siblingTextList = list(siblingTextDict.keys())
  331. # 是否获取数值文本;
  332. isNumberText = False
  333. # 如果是value表,且兄弟项文本为range
  334. # 注:value表中的option实际并没有兄弟项,取的是所有value项
  335. if isValueSheet and siblingTextList.__len__():
  336. if siblingTextList[0].startswith('range('):
  337. self.info(u"识别的内容是value表数字内容(range(x,y)类型)")
  338. isNumberText = True
  339. # 清除之前的value值;
  340. self.__optionValueText = ""
  341. # 是否为静态焦点识别(动态则为跑马灯);
  342. if curOthers.__len__() and 'marquee' in curOthers:
  343. return self.__getDynamicPicText(curOption, optionTextList, siblingTextList, ocrConfigList,
  344. ocrThreshold, curOthers['marquee'],
  345. isNumberText, isValueSheet)
  346. else:
  347. isFocus, isTarget, text = self.__getStaticPicText(self.takePicture() if staticPic is None else staticPic,
  348. curOption,
  349. optionTextList,
  350. siblingTextList,
  351. ocrConfigList,
  352. ocrThreshold,
  353. isNumberText, isValueSheet)
  354. return isTarget, text
  355. # endif
  356. '''
  357. 函数:是否移到目标节点上(在isOnOption后,判断__pos位置是否在__paths最后);
  358. 参数:无
  359. 返回:Boolean.
  360. '''
  361. def isOnTargetOption(self):
  362. return True if self.__pos == (self.__optionPaths.__len__() - 1) else False
  363. '''
  364. 函数:当前节点是否在value sheet层级中;
  365. 参数:无
  366. 返回:Boolean
  367. '''
  368. def isOnValueSheet(self):
  369. if self.__optionValue == "": # 该值空,表明不会移动到value sheet中;
  370. return False
  371. else:
  372. return self.__isOnValueSheet
  373. '''
  374. 函数:移动到下一兄弟节点;
  375. 参数:无
  376. 返回:无
  377. 注意:
  378. sendKey的等待时间太短,会导致画面未响应,截图时还是截上一状态的,比如0.1秒就很经常出现这问题。
  379. 同时,按键等待时间,应该有所区分。
  380. 如果不截图,可以不考虑sendKey的等待时间.
  381. '''
  382. def move2NextSiblingNode(self):
  383. # 析出move key;
  384. if self.isOnValueSheet():
  385. valueMoveKey = self.__optionValueInfo['move_key']
  386. self.sendKey(valueMoveKey[1], 1, 1)
  387. else:
  388. optionMoveKey = self.__curOptionInfo['option_move_key']
  389. if optionMoveKey.__len__() == 0:
  390. self.sendKey(self.__curOptionInfo['move_key'][1], 1, 1)
  391. else:
  392. self.sendKey(optionMoveKey[1], 1, 1)
  393. '''
  394. 函数:移动到上一兄弟节点
  395. 参数:无
  396. 返回:无
  397. 注意:
  398. sendKey的等待时间太短,会导致画面未响应,截图时还是截上一状态的,比如0.1秒就很经常出现这问题。
  399. 同时,按键等待时间,应该有所区分。
  400. 如果不截图,可以不考虑sendKey的等待时间.
  401. '''
  402. def move2PrevSiblingNode(self):
  403. # 析出move key;
  404. if self.isOnValueSheet():
  405. valueMoveKey = self.__optionValueInfo['move_key']
  406. self.sendKey(valueMoveKey[0], 1, 1)
  407. else:
  408. optionMoveKey = self.__curOptionInfo['option_move_key']
  409. if optionMoveKey.__len__() == 0:
  410. self.sendKey(self.__curOptionInfo['move_key'][0], 1, 1)
  411. else:
  412. self.sendKey(optionMoveKey[0], 1, 1)
  413. '''
  414. 函数:返回到父节点
  415. 参数:
  416. 返回:无
  417. 注意:
  418. sendKey的等待时间太短,会导致画面未响应,截图时还是截上一状态的,比如0.1秒就很经常出现这问题。
  419. 同时,按键等待时间,应该有所区分。
  420. 如果不截图,可以不考虑sendKey的等待时间.
  421. '''
  422. def back2ParentNode(self):
  423. # 获取当前option信息;
  424. if self.isOnValueSheet():
  425. tKeyDict = self.__optionValueInfo['toparent_key']
  426. peKeyDict = self.__prevOptionInfo['enter_key']
  427. else:
  428. tKeyDict = self.__curOptionInfo['toparent_key']
  429. peKeyDict = self.__prevOptionInfo['enter_key']
  430. '''
  431. 说明:
  432. toparent_key由于旧menutree无此参数,分以下数种情况:
  433. 当toparent_key没有配时:
  434. 是否为value层:
  435. 如果为value层,上一父层的enter_key是否为default:
  436. 如果是default,则toparent_key也按default处理;
  437. 如果不是default,则toparent_key按照return处理;
  438. 如果不为value层:
  439. toparent_key统一按return处理。
  440. 如果配了toparent_key:
  441. toparent_key是否为default:
  442. 如果是,按照default处理:
  443. 如果不是,按照配置的key来处理。
  444. tKeyDict中是否包含tolevel字段;
  445. 如果不包含,执行完toparent_key后self.__pos自减1
  446. 如果包含,执行完toparent_key后self.__pos等于tolevel指定的层级
  447. '''
  448. # 当toparent_key没有配时;
  449. if tKeyDict == "" or tKeyDict['key'][0] == "":
  450. # 是否为value层:
  451. if self.isOnValueSheet():
  452. # 如果为value层,上一父层的enter_key是否为default
  453. if strcmp(peKeyDict["key"][0], "default"):
  454. # 如果是default,则toparent_key也按default处理;
  455. self.info("当前处于value层,未配toparent_key,且父层enter_key为default,默认toparent_key为default")
  456. tKeyDict = {'key': ["default", ]}
  457. else:
  458. self.info("当前处于value层,未配toparent_key,toparent_key为return")
  459. # 如果不是default,则toparent_key按照return处理;
  460. tKeyDict = {'key': ["return", ]}
  461. else:
  462. self.info("当前层未配toparent_key,toparent_key为return")
  463. # 如果不为value层,toparent_key统一按return处理。
  464. tKeyDict = {'key': ["return", ]}
  465. # 如果配了toparent_key
  466. else:
  467. # toparent_key是否为default
  468. if strcmp(tKeyDict['key'][0], "default"):
  469. # 如果是default,则toparent_key也按default处理;
  470. self.info("当前层toparent_key为default")
  471. else:
  472. self.info("当前层toparent_key为%s" % str(tKeyDict['key']))
  473. self.__executeToParentKey(tKeyDict)
  474. # 从value层执行完返回后,则不在valuesheet里了
  475. self.__isOnValueSheet = False
  476. '''
  477. 在忽略大小写的情况下,获取到该level对应的g_level的下标值
  478. '''
  479. def __getLevelIndex(self, level):
  480. s_level = []
  481. for lvStr in g_level:
  482. s_level.append(lvStr.lower())
  483. return s_level.index(level)
  484. '''
  485. 函数:进入当前节点,只对路径节点有效,value节点不处理;
  486. 参数:无
  487. 返回:无
  488. '''
  489. def enterNode(self):
  490. # 析出enter key;
  491. if self.isOnValueSheet():
  492. if not self.__isEnterKeyInValue:
  493. self.info(u"节点已在value上,且没有触发过enter key")
  494. enterKey = self.__optionValueInfo['enter_key']
  495. self.__executeEnterKey(enterKey)
  496. self.__isEnterKeyInValue = True
  497. else:
  498. self.info(u"节点已在value上,已触发过enter key")
  499. else:
  500. # 优先使用option本身的enter_key
  501. optionEnterKey = self.__curOptionInfo['option_enter_key']
  502. # 如果option本身的enter_key为空,则使用该层parent的enter_key
  503. if optionEnterKey['key'] == "":
  504. optionEnterKey = self.__curOptionInfo['enter_key']
  505. self.__executeEnterKey(optionEnterKey)
  506. '''
  507. 函数:设置当前节点位置;
  508. 参数:
  509. pos: 外部节点位置值。
  510. 返回:无
  511. 注意:此函数用于外部创建两个【路径具体子集关系】的COptionAction对象,才可以使用此函数。
  512. 假设, a对象路径{p,p1,p2,p3,p4, v1},b = {p, p1, p2, p3, p4, p5, p6, v2}, c = {p, p2, p5, p6, v3}
  513. 其中, v表示value值,不属于路径。那么,a和b具有子集关系, a与c或b与c都不具有子集关系。
  514. a移动到p4上,完成了v1设置后,a.back2ParentNode()后,此时如果要操作b并设置v2,就要b.SetCurPos(a.pos).
  515. '''
  516. def setCurPos(self, pos):
  517. if pos < 0 or pos > self.__optionPaths.__len__():
  518. self.error(u"pos值[%d]超出路径范围:[0-%d]" % (pos, self.__optionPaths.__len__()))
  519. return
  520. self.__pos = pos
  521. # 变更后要重新读一次当前option
  522. self.getCurOptionInfo()
  523. '''
  524. 函数:设置目标option的值, 只设置数值型value和输入型value(选择型value不需要此步骤).
  525. 参数:无
  526. 返回:无
  527. 注意:此函数必须是已聚焦在目标value节点上,否则无效。
  528. 重要:
  529. 在此函数enter后,UI是否返回到上一层父节点上,还是停留在本层节点不返回。
  530. 建议在excel中配置这个关键信息,以便此函数可以正确更改self.__pos的值。
  531. '''
  532. def setOptionValue(self):
  533. self.info(u"【在此函数enter后,UI是否返回到上一层父节点上,还是停留在本层节点不返回。\
  534. 建议在excel中配置这个关键信息,以便此函数可以正确更改self.__pos的值。】")
  535. if type(self.__optionValue) == str and self.__optionValue.__len__() == 0:
  536. self.error(u"[%s]的值为空,没有设置的值" % self.__optionName)
  537. return
  538. enterKey = self.__optionValueInfo['enter_key']
  539. moveKey = self.__optionValueInfo['move_key']
  540. valueText = self.__optionValueInfo['value_for_ocr']
  541. others = self.__optionValueInfo['others']
  542. if others.__len__():
  543. others = json.loads(others)
  544. else:
  545. others = {}
  546. # 是否有按键延时值;<注意:有些地方duration=0.1时,会变成长按的效果。>
  547. duration = float(others['duration']) if "duration" in others else 0.2
  548. # 值类型:
  549. # 0 表示默认选择类型.
  550. # 1 表示输入类型(有些输入完了,正确值会自动进入).
  551. # 2 表示进度条数据型.
  552. self.__valueType = VType.SelectType
  553. # 是否为数字文本(特指:range(0, 100));
  554. isNumberText = self.isNumberText(valueText)
  555. # 数值型value;
  556. if isNumberText:
  557. if moveKey[0] == 'input':
  558. # 标记值类型;
  559. self.__valueType = VType.InputType
  560. # 将数值转成字符;
  561. optionValue = self.__optionValue
  562. if type(optionValue) == int or type(optionValue) == float:
  563. optionValue = str(self.__optionValue)
  564. # 再将字符转成list;
  565. chList = list(optionValue)
  566. self.sendKey(chList, 1, duration)
  567. else:
  568. # 标记值类型;
  569. self.__valueType = VType.RangeType
  570. # 相差值;
  571. num = int(self.__optionValue) - int(self.__optionValueText)
  572. # 正->往右或下,负->往左或上;
  573. self.sendKey(moveKey[1] if num > 0 else moveKey[0], abs(num), duration)
  574. elif moveKey[0] == 'input':
  575. # 标记值类型;
  576. self.__valueType = VType.InputType
  577. # 将字符转成list;
  578. chList = list(self.__optionValue)
  579. self.sendKey(chList, 1, duration)
  580. # 最后,如果有进入键执行;
  581. if not strcmp(enterKey['key'][0], 'default') and enterKey['key'][0] != "":
  582. self.info(u"value节点具有enter key")
  583. self.__executeEnterKey(enterKey)
  584. '''
  585. 函数:获取当前层级的目标option详细信息.
  586. 参数:无
  587. 返回:Boolean, 获取成功返回True
  588. '''
  589. def getCurOptionInfo(self):
  590. if self.__optionPaths is None or self.__optionPaths.__len__() == 0:
  591. self.error(u"paths路径空")
  592. return False
  593. if 'First' not in self.__optionPaths:
  594. self.error(u"构建的paths不连续,路径存在断点")
  595. self.error(u"当前paths内容:%s"%self.__optionPaths)
  596. return False
  597. if self.__pos >= self.__optionPaths.__len__():
  598. # 有可能存在使用openOption打开某个option,但是下一层未到value层的情况。
  599. # 此时pos会等于整个路径,但是我们要取的数据又不在value层。需要返回该option下任意一个子option的参数
  600. outResult, parentData = self.__optionExcel.getParentInfo(self.__optionName)
  601. if outResult:
  602. for optionName in parentData['option']:
  603. outResult, outData = self.__optionExcel.getOptionInfo(optionName)
  604. if outResult:
  605. self.__curOptionInfo = outData
  606. self.info(u"当前使用openOption方式打开目标option:%s,下一层未到value层,将以其子option:%s的参数信息作为返回值"%(self.__optionName, optionName))
  607. break
  608. else:
  609. self.warn(u"获取到了目标option:%s在下一层存在parent配置,但无法获取到任何子option信息!"%self.__optionName)
  610. return False
  611. else:
  612. # self.__curOptionInfo = None # 是否需要在到达value层级后置空,可能保留值会有比较多用处!
  613. self.warn(u"已到达value节点,无法获取路径信息")
  614. self.__prevOptionName = self.__curOptionName
  615. self.__prevOptionInfo = self.__curOptionInfo
  616. self.__isOnValueSheet = True
  617. return False
  618. # 只有第一次或层级移动了才需要更新;
  619. if self.__curOptionInfo is None or self.__pos != self.__curOptionInfo['layers']:
  620. self.__curOptionName = self.__optionPaths[g_level[self.__pos]]['option']
  621. outResult, outData = self.__optionExcel.getOptionInfo(self.__curOptionName, self.__optionPaths)
  622. if outResult is False:
  623. return False
  624. self.__curOptionInfo = outData
  625. # 当处于第二层或以后的层级时,读取前一层的数据
  626. if self.__pos > 0:
  627. # 是否在value层
  628. if not self.isOnValueSheet():
  629. self.__prevOptionName = self.__optionPaths[g_level[self.__pos - 1]]['option']
  630. outResult, outData = self.__optionExcel.getOptionInfo(self.__prevOptionName, self.__optionPaths)
  631. if outResult is False:
  632. return False
  633. self.__prevOptionInfo = outData
  634. # 特殊情况:如果只一层且该层与value相同(信源source,要在value表中配置一份相同配置)。
  635. # if self.__curOptionInfo['first_parent'] == self.__curOptionName:
  636. # # 自动进入value表;
  637. # self.__pos += 1
  638. return True
  639. '''
  640. 函数:返回下一个option的详细信息;
  641. 参数:无
  642. 返回:Boolean、option info。
  643. '''
  644. def getNextOptionInfo(self):
  645. if self.__optionPaths is None or self.__optionPaths.__len__() == 0:
  646. self.error(u"paths路径空")
  647. return False, None
  648. if self.__pos + 1 >= self.__optionPaths.__len__():
  649. self.warn(u"已到达value节点,无法获取路径信息")
  650. return False, None
  651. nextOptionName = self.__optionPaths[g_level[self.__pos + 1]]['option']
  652. return self.__optionExcel.getOptionInfo(nextOptionName, self.__optionPaths)
  653. '''
  654. 函数:获取指定位置的option信息;
  655. 参数:
  656. pos 指定的层级位置;
  657. 返回:
  658. 成功返回option信息,失败返回None
  659. '''
  660. def getOptionInfo(self, pos):
  661. if pos > self.__optionPaths.__len__() and pos < 0:
  662. return None
  663. outResult, outData = self.__optionExcel.getOptionInfo(self.__optionPaths[g_level[pos]]['option'],
  664. self.__optionPaths)
  665. if outResult is False:
  666. return None
  667. return outData
  668. '''
  669. 函数:指定option是否存在该路径中;
  670. 参数:
  671. optionName 指定的option名称;
  672. 返回:
  673. 存在返回True+位置, 不存在返回False+位置;
  674. '''
  675. def isOptionInPaths(self, pos, optionNameOrValueName):
  676. bExist = False
  677. # 在路径表中;
  678. if 0 < pos < self.__optionPaths.__len__():
  679. posOptionName = self.__optionPaths[g_level[pos]]['option'].lower()
  680. siblingText = self.__optionExcel.getOptionAllSiblingItemName(posOptionName)
  681. for name in siblingText:
  682. if name.lower() == optionNameOrValueName.lower():
  683. bExist = True
  684. break
  685. # 在value表中;
  686. if self.isOnValueSheet():
  687. valueOptionName = self.__optionPaths[g_level[self.__optionPaths.__len__() - 1]]['option']
  688. valueNames = self.__optionExcel.getOptionAllValueName(valueOptionName)
  689. for name in valueNames:
  690. if name.lower() == optionNameOrValueName.lower():
  691. bExist = True
  692. break
  693. return bExist
  694. '''
  695. 函数:检测路径是否有效;
  696. 参数:无
  697. 返回:Boolean, 检测正常返回True
  698. '''
  699. def checkRunOptionPath(self):
  700. outData = self.__optionExcel.checkOptionPaths(self.__optionPaths)
  701. if str(outData[1]) == 'NoExit':
  702. self.error(u"表格中不存在到达Option:[%s]的路径,在表格中排查到达该Option路径" % self.__optionName)
  703. return False
  704. if str(outData[1]) == 'Fail':
  705. self.error(u"表格中到达Option:[%s]的路径出现数据断层找不到First层级,在表格中排查到达该Option路径" % self.__optionName)
  706. return False
  707. return True
  708. '''
  709. 函数:指定的value_for_ocr或option_for_ocr数组是否为range(xx,xx)类型。
  710. 参数:
  711. textList value_for_ocr或option_for_ocr数组,一般只可能会是value_for_ocr
  712. 返回:Boolean, 如果是range(xx,xx)类型返回True.
  713. '''
  714. def isNumberText(self, textList):
  715. # 是否获取数值文本;
  716. isNumberText = False
  717. # 如果是value表,且兄弟项文本为range
  718. # 注:value表中的option实际并没有兄弟项,取的是所有value项
  719. if self.isOnValueSheet() and textList.__len__():
  720. if textList[0].startswith('range('):
  721. self.info(u"识别的内容是value表数字内容(range(0,xx)类型)")
  722. isNumberText = True
  723. return isNumberText
  724. '''
  725. 函数:获取静态图片文本内容
  726. 参数:(略,请看调用函数)
  727. 注意:
  728. 返回:Boolean、Boolean、文本识别内容。
  729. 是否成功聚焦、是否聚焦在目标节点上、聚焦框识别的文本内容。
  730. '''
  731. def __getStaticPicText(self, pic, optionName, optionTextList, siblingTextList, ocrConfigList, ocrThreshold,
  732. isNumberText, isValueSheet, aliveKey=None):
  733. # 获取图片焦点框;
  734. found, focusBox = self.__optionFocus.findFocusByIcon(pic, optionName, isValueSheet)
  735. if found is False:
  736. self.debug(u"未找到[%s]聚集框" % optionName)
  737. return False, False, None
  738. # 如果有鲜活键;
  739. self.sendAliveKey(aliveKey)
  740. # 获取文本区域框;
  741. textBox = self.__optionFocus.getFocusTextBox(optionName, focusBox, isValueSheet)
  742. # 配置文本图片路径,保存文本区域截图;
  743. text_pic = os.path.join(getSATTmpDIR(), "menutree_area_text.png")
  744. self.__imgCMP.saveCropPic(pic, text_pic, textBox)
  745. if not os.path.exists(text_pic):
  746. self.error(u"%s截取文本图片失败:%s" % (optionName, text_pic))
  747. return False, False, None
  748. # 是否在某个兄弟项中;
  749. isOnSibling = False
  750. # 遍历所有ocr识别选项;
  751. for ocrConfig in ocrConfigList:
  752. # 如果有鲜活键;
  753. self.sendAliveKey(aliveKey)
  754. # 识别出当前聚焦文本;
  755. curFocusText = self.__optionOCR.getImageText(text_pic, ocrConfig, ocrThreshold)
  756. # 判断识别文本是来正常;
  757. if curFocusText == "ERR<Exp>" or curFocusText.__len__() == 0:
  758. continue
  759. # 转成小写;
  760. curFocusText = curFocusText.lower()
  761. self.info("[%s]当前识别出的文本=%s" % (optionName, curFocusText))
  762. # 是否取数字文本(肯定在value节点上);
  763. if isNumberText is True:
  764. # 特殊情况处理:某些情况下,会将包含数字以外的区域一起识别;
  765. curFocusText = curFocusText.strip('>')
  766. # 将数字分组
  767. numberTextList = strSplit(curFocusText)
  768. # 只判断最后一位是否为数字;
  769. if numberTextList.__len__() < 1:
  770. self.error(u"当前识别的文本不是数字文本:%s" % curFocusText)
  771. continue
  772. try:
  773. numberText = float(numberTextList[numberTextList.__len__() - 1])
  774. # 记录value值;
  775. self.__optionValueText = numberText
  776. return True, True, numberText
  777. except Exception:
  778. continue
  779. else:
  780. # 当前option识别的文本与所有兄弟项文本比较;
  781. for siblingText in siblingTextList:
  782. # 转为小写,保证所有比较都是小写;
  783. siblingText = siblingText.lower()
  784. # 兄弟项文本是否被包含在curFocusText中或相同;
  785. if siblingText.lower() in curFocusText.lower() or strcmp(siblingText, curFocusText):
  786. isOnSibling = True
  787. self.info(u"当前焦点在[%s], 目标焦点为[%s]" % (siblingText, optionName))
  788. self.info(u"optionTextList:%s" % optionTextList)
  789. # 再判断,该兄弟项是否为目标节点(curOption);
  790. for optionText in optionTextList:
  791. optionText = optionText.lower()
  792. # 若当前兄弟项为目标option返回True、文本;
  793. if strcmp(optionText, siblingText):
  794. return True, True, curFocusText
  795. # endif
  796. # endfor
  797. # 在兄弟项中,退出循环;
  798. break
  799. # endif
  800. # endfor
  801. if isOnSibling is False:
  802. self.error(u"未聚集到任何[%s]的兄弟项中" % optionName)
  803. else:
  804. self.info("未聚集到目标节点[%s],当前文本=%s" % (optionName, curFocusText))
  805. return found, False, curFocusText
  806. # endif
  807. # endfor
  808. # 默认返回;
  809. return found, False, 0 if isNumberText else curFocusText
  810. '''
  811. 函数:获取动态图片文本内容
  812. 参数:(略,请看调用函数)
  813. 注意:
  814. 返回:Boolean、文本识别内容。成功识别出文本,返回True及文本内容。
  815. '''
  816. def __getDynamicPicText(self, optionName, optionTextList, siblingTextList, ocrConfigList, ocrThreshold, marqueeDict,
  817. isNumberText, isValueSheet):
  818. # 判断图片是否动态:截图两次,判断两次文本内容是否相同;
  819. firstFocus, firstTarget, firstText = self.__getStaticPicText(self.takePicture(), optionName, optionTextList,
  820. siblingTextList,
  821. [{"lan": "ChinesePRC+English", "type": 10001}],
  822. ocrThreshold, isNumberText, isValueSheet)
  823. if firstFocus is False:
  824. self.error(u"[%s]第一次截图未识别出聚焦框" % optionName)
  825. return False, None
  826. # 目标option不是跑马灯,且已经聚焦到了目标option
  827. elif firstTarget is True:
  828. self.info(u"已聚焦到了目标option:%s" % optionName)
  829. return firstTarget, firstText
  830. # 发送鲜活键, 保证界面鲜活;
  831. self.sendAliveKey(marqueeDict['alive_key'])
  832. # 第二次截图;
  833. secondFocus, secondTarget, secondText = self.__getStaticPicText(self.takePicture(), optionName, optionTextList,
  834. siblingTextList,
  835. [{"lan": "ChinesePRC+English", "type": 10001}],
  836. ocrThreshold, isNumberText, isValueSheet)
  837. if secondFocus is False:
  838. self.error(u"[%s]第二次截图未识别出聚焦框" % optionName)
  839. return False, None
  840. # 发送鲜活键, 保证界面鲜活;
  841. self.sendAliveKey(marqueeDict['alive_key'])
  842. # 比较两文本是否相同;
  843. if firstText.__len__() and firstText == secondText:
  844. self.info(u"截图两次,文本(%s)识别相同,聚焦的不是跑马灯Option" % firstText)
  845. return False, firstText
  846. elif firstText.__len__() == 0:
  847. self.warn(u"未能识别出当前option")
  848. return False, firstText
  849. # 文本不相同,为动态图片;
  850. menuList = marqueeDict['menu']
  851. # 如果只有一项跑马灯,且目标option亦在跑马灯列表中,则直接返回成功结果
  852. if menuList.__len__() == 1 and (optionName in menuList):
  853. self.info(u"该层菜单只有一项跑马灯, 找到即成功返回")
  854. return True, firstText
  855. picList = []
  856. # 如果有多项同级option都是跑马灯, 要成功识别文本需要间隔截图5次(大概会成功截图到最全的文本);
  857. for i in range(0, 5):
  858. picList.append(self.takePicture())
  859. # 间隔多久截图;
  860. time.sleep(marqueeDict['sleep_time'])
  861. # 发送鲜活键;
  862. self.sendAliveKey(marqueeDict['alive_key'])
  863. ocrTextList = []
  864. # 对截图进行文本识别分析;
  865. for pic in picList:
  866. isFocus, isTarget, text = self.__getStaticPicText(pic, optionName, optionTextList, siblingTextList,
  867. ocrConfigList,
  868. ocrThreshold, isNumberText, isValueSheet,
  869. marqueeDict['alive_key'])
  870. if isTarget is True:
  871. ocrTextList.append(text)
  872. # 发送鲜活键;
  873. self.sendAliveKey(marqueeDict['alive_key'])
  874. # 过滤重复的字符;
  875. ocrTextList = self.__removeDuplicateString(ocrTextList)
  876. self.info(u"识别到的跑马灯ocr文字列表:%s" % ocrTextList)
  877. # 获取动态文本的option字典;
  878. dynamicOptionOcrDict = self.__getOptionInfoDict(menuList)
  879. self.info(u"获取到的跑马灯Option对应的ocr字典:%s" % dynamicOptionOcrDict)
  880. # 遍历:识别结果与xls结果进行比较;
  881. for dynamicOption in dynamicOptionOcrDict:
  882. dynamicOptionOcrList = dynamicOptionOcrDict[dynamicOption]
  883. for dynamicOptionOcr in dynamicOptionOcrList:
  884. # 只要有3张满足,判断找到option;
  885. count = 0
  886. for ocrText in ocrTextList:
  887. if ocrText.lower() in dynamicOptionOcr:
  888. count += 1
  889. if count >= 3 and optionName == dynamicOption:
  890. return True, ocrText
  891. else:
  892. self.info(u"当前聚焦的跑马灯实际为:%s" % dynamicOption)
  893. return False, ocrText
  894. # endfor
  895. # endfor
  896. self.info("未能识别到当前聚焦的跑马灯Option")
  897. return False, 0 if isNumberText else None
  898. '''
  899. 函数:获取option名称数组内所有option的详细信息.
  900. 参数:
  901. optionNameList option名称数组。
  902. 返回:字典。
  903. {
  904. "option1": {self.__optionExcel.getOptionInfo(option1)[1]},
  905. "option2": {self.__optionExcel.getOptionInfo(option2)[1]},
  906. "option3": {self.__optionExcel.getOptionInfo(option3)[1]},
  907. }
  908. '''
  909. def __getOptionInfoDict(self, optionNameList):
  910. OptionInfoDict = {}
  911. for optionName in optionNameList:
  912. found, optionDict = self.__optionExcel.getOptionInfo(optionName)
  913. if found:
  914. OptionInfoDict[optionName] = optionDict
  915. # endif
  916. # endfor
  917. return OptionInfoDict
  918. '''
  919. 函数:找到两个字符串左边或者右边相同的部分
  920. 参数:
  921. str1:
  922. str2:
  923. direction 方向,默认为right
  924. 返回:
  925. '''
  926. def __findDuplicateString(self, str1, str2, direction="right"):
  927. index = 0
  928. if direction == "right":
  929. while True:
  930. index -= 1
  931. if abs(index) > str1.__len__() or abs(index) > str2.__len__():
  932. break
  933. if not str1[index] == str2[index]:
  934. break
  935. if index == -1:
  936. self.info(u"没有找到重复文本")
  937. return ""
  938. return str1[index + 1:]
  939. elif direction == "left":
  940. while True:
  941. if abs(index) >= str1.__len__() or abs(index) >= str2.__len__():
  942. break
  943. if not str1[index] == str2[index]:
  944. break
  945. index += 1
  946. return str1[:index]
  947. '''
  948. 函数:获取路径长度。
  949. 参数:
  950. 返回:
  951. '''
  952. def getPathLength(self):
  953. if self.__optionPaths is None:
  954. self.error(u"路径空,返回0")
  955. return 0
  956. self.info(u"路径长度:%d" % self.__optionPaths.__len__())
  957. return self.__optionPaths.__len__()
  958. '''
  959. 函数:去掉字符串数组中每个字符串 左边或右边相同的部分
  960. 参数:
  961. strList
  962. 返回:
  963. '''
  964. def __removeDuplicateString(self, strList):
  965. finishedList = strList
  966. directionList = ["left", "right"]
  967. for direction in directionList:
  968. same_str = self.__findDuplicateString(strList[0], strList[1], direction)
  969. if same_str == "":
  970. continue
  971. else:
  972. for i in range(2, strList.__len__()):
  973. same_str = self.__findDuplicateString(same_str, strList[i], direction)
  974. if same_str == "":
  975. break
  976. if same_str != "":
  977. finishedList = []
  978. for text in strList:
  979. if direction == "left":
  980. text = str[same_str.__len__():]
  981. else:
  982. text = str[:-same_str.__len__()]
  983. finishedList.append(text)
  984. # endfor
  985. # endif
  986. # endif
  987. # endfor
  988. return finishedList
  989. '''
  990. 函数:发送红老鼠按键;
  991. 参数:
  992. key 1、如果是字符串时,当作单个按键; 2、如果是list时,当作多个按键;
  993. count 执行多少次key;
  994. wait 1、执行单个key后,等待时长(因为电视机响应遥控需要时间);
  995. 2、执行list多个key后,每个key的等待时间;
  996. 返回:无
  997. '''
  998. def sendKey(self, key, count=1, duration=1.0):
  999. if key is not None and key.__len__() > 0:
  1000. if type(key) == list:
  1001. for k in key:
  1002. # 清除前后空格;
  1003. k = k.lstrip()
  1004. k = k.rstrip()
  1005. COptionAction.__redRat3.sendKey(k, 1, duration)
  1006. else:
  1007. key = str(key)
  1008. # 清除前后空格;
  1009. key = key.lstrip()
  1010. key = key.rstrip()
  1011. COptionAction.__redRat3.sendKey(key, count, duration)
  1012. else:
  1013. self.error(u"error:按键内容空")
  1014. '''
  1015. 函数:发送鲜活键;
  1016. 参数:
  1017. aliveKey 鲜活按键;
  1018. 返回:无
  1019. 注意:鲜活键等待时间是0.1秒,因为不考虑截图。
  1020. '''
  1021. def sendAliveKey(self, aliveKey):
  1022. self.sendKey(aliveKey, 1, 0.1)
  1023. '''
  1024. 函数:按照新格式执行enter_key。
  1025. 参数:
  1026. eKeyDict 即enterKey的字典对象,包含的wait和duration等参数。
  1027. wait,duration是为了兼容旧menutree按照others配置参数的处理方法。
  1028. 如果others中有配waitTime和duration,优先采用others里的配置,否则则采用enterKey里的配置。
  1029. '''
  1030. def __executeEnterKey(self, eKeyDict):
  1031. # 先从config读取
  1032. wait = self.__optionConfig.getParentWaitTime(self.__curOptionInfo['parent'])
  1033. # config中读取不到则尝试从others中读取
  1034. if wait == 1.0:
  1035. try:
  1036. others = json.loads(self.__curOptionInfo['others'])
  1037. if "waitTime" in others:
  1038. if others['waitTime'] != "":
  1039. wait = float(others['waitTime'])
  1040. except Exception,e:
  1041. pass
  1042. # 读出来的enter_key,不为空或者default时,按格式执行enter_key
  1043. if not strcmp(eKeyDict['key'][0], 'default') and eKeyDict['key'][0] != "":
  1044. self.__executeKey(eKeyDict, wait=wait)
  1045. if eKeyDict['tolevel'] != "":
  1046. level = eKeyDict['tolevel']
  1047. else:
  1048. level = ""
  1049. # value层的enter_key存在特殊字段,isback。用于判断执行enter_key以后会不会返回父层。
  1050. # isback为0或为""时:
  1051. # 则认为不返回父层;
  1052. # 为1时:
  1053. # 如果enter_key中没有配tolevel,则默认返回上一层父层;
  1054. # 如果有,则默认返回到tolevel指定层级的父层。
  1055. # 非value层,则self.__pos默认进入下一层。
  1056. if self.isOnValueSheet():
  1057. if eKeyDict['isback'] == "" or int(eKeyDict['isback']) == 0:
  1058. pass
  1059. else:
  1060. if level == "":
  1061. self.__pos -= 1
  1062. else:
  1063. self.__pos = self.__getLevelIndex(level) + 1
  1064. else:
  1065. self.__pos += 1
  1066. # 重新获取次信息;
  1067. self.getCurOptionInfo()
  1068. def __executeToParentKey(self, tKeyDict):
  1069. self.__executeKey(tKeyDict)
  1070. # 层级变化
  1071. if 'tolevel' in tKeyDict and tKeyDict['tolevel'] != "":
  1072. level = tKeyDict['tolevel']
  1073. self.__pos = self.__getLevelIndex(level) + 1
  1074. else:
  1075. self.__pos -= 1
  1076. # 重新获取次信息;
  1077. self.getCurOptionInfo()
  1078. def __executeKey(self, keyDict, wait=1.0, duration=1.0):
  1079. if wait != 1.0 and keyDict['wait'] != "":
  1080. wait = float(keyDict['wait'])
  1081. if duration != 1.0 and keyDict['duration'] != "":
  1082. duration = float(keyDict['duration'])
  1083. for key in keyDict['key']:
  1084. self.sendKey(key, 1, duration)
  1085. time.sleep(wait)
  1086. def executeKey(self, keyDict, wait=1.0, duration=1.0):
  1087. self.__executeKey(keyDict, wait, duration)
  1088. def setValue(self, optionValue):
  1089. self.__optionValue = optionValue
  1090. if self.__optionValue != "" or self.__optionValue is not None:
  1091. self.__optionValueInfo = self.__optionExcel.getOptionValueInfo(self.__optionName, self.__optionValue)
  1092. return True if self.__optionValueInfo and self.__optionValueInfo.__len__() else False
  1093. if __name__ == "__main__":
  1094. exData = CExtraData()
  1095. optionExcel = COptionExcel(exData)
  1096. optionConfig = COptionConfig(exData, optionExcel)
  1097. optionAction = COptionAction('source', None, optionConfig, optionExcel)
  1098. # print optionAction.optionValueInfo
  1099. print optionAction.curOptionInfo
  1100. # ====================================== #
  1101. # optionAction.callFirstOptionShortCutKey()