2019-01-21 18:16:41 -05:00
|
|
|
#!/bin/python
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
# Fenrir TTY screen reader
|
|
|
|
# By Chrys, Storm Dragon, and contributers.
|
|
|
|
|
|
|
|
from fenrirscreenreader.core import debug
|
2019-02-04 13:05:31 -05:00
|
|
|
from fenrirscreenreader.utils import module_utils
|
2019-02-08 07:39:42 -05:00
|
|
|
import os, inspect, time
|
2019-02-04 13:05:31 -05:00
|
|
|
|
2019-02-04 13:39:36 -05:00
|
|
|
currentdir = os.path.dirname(os.path.realpath(os.path.abspath(inspect.getfile(inspect.currentframe()))))
|
|
|
|
fenrirPath = os.path.dirname(currentdir)
|
2019-01-21 18:16:41 -05:00
|
|
|
|
|
|
|
class vmenuManager():
|
|
|
|
def __init__(self):
|
2019-01-21 18:37:07 -05:00
|
|
|
self.menuDict = {}
|
|
|
|
self.currIndex = None
|
2019-01-22 18:33:11 -05:00
|
|
|
self.currMenu = ''
|
2019-01-21 18:37:07 -05:00
|
|
|
self.active = False
|
2019-02-12 16:33:16 -05:00
|
|
|
self.reset = True
|
|
|
|
self.useTimeout = True
|
2019-02-08 07:39:42 -05:00
|
|
|
self.searchText = ''
|
|
|
|
self.lastSearchTime = time.time()
|
2019-01-21 18:16:41 -05:00
|
|
|
def initialize(self, environment):
|
|
|
|
self.env = environment
|
2019-02-12 14:04:46 -05:00
|
|
|
# use default path
|
2019-02-04 15:56:36 -05:00
|
|
|
self.defaultVMenuPath = fenrirPath+ "/commands/vmenu-profiles/" + self.env['runtime']['inputManager'].getShortcutType()
|
2019-02-12 14:04:46 -05:00
|
|
|
# if there is no user configuration
|
|
|
|
if self.env['runtime']['settingsManager'].getSetting('menu', 'vmenuPath') != '':
|
|
|
|
self.defaultVMenuPath = self.env['runtime']['settingsManager'].getSetting('menu', 'vmenuPath')
|
|
|
|
if not self.defaultVMenuPath.endswith('/'):
|
|
|
|
self.defaultVMenuPath += '/'
|
|
|
|
self.defaultVMenuPath += self.env['runtime']['inputManager'].getShortcutType()
|
|
|
|
|
2019-02-04 16:49:56 -05:00
|
|
|
self.createMenuTree()
|
2019-02-06 17:51:14 -05:00
|
|
|
self.closeAfterAction = False
|
2019-01-21 18:16:41 -05:00
|
|
|
def shutdown(self):
|
2019-01-21 18:37:07 -05:00
|
|
|
pass
|
2019-02-12 16:33:16 -05:00
|
|
|
def clearSearchText(self):
|
|
|
|
self.searchText = ''
|
|
|
|
def searchEntry(self, value, forceReset = False):
|
2019-02-08 07:39:42 -05:00
|
|
|
if self.currIndex == None:
|
2019-02-12 16:33:16 -05:00
|
|
|
return ''
|
|
|
|
if self.reset or forceReset:
|
|
|
|
self.clearSearchText()
|
|
|
|
else:
|
|
|
|
if self.useTimeout:
|
|
|
|
if time.time() - self.lastSearchTime > 1:
|
|
|
|
self.clearSearchText()
|
2019-02-12 17:18:16 -05:00
|
|
|
self.searchText += value.upper()
|
2019-02-08 07:39:42 -05:00
|
|
|
self.lastSearchTime = time.time()
|
2019-02-12 16:33:16 -05:00
|
|
|
startIndex = self.getCurrIndex()
|
2019-02-08 07:39:42 -05:00
|
|
|
while True:
|
2019-02-12 16:33:16 -05:00
|
|
|
if not self.nextIndex():
|
|
|
|
return ''
|
2019-02-08 07:39:42 -05:00
|
|
|
entry = self.getCurrentEntry()
|
2019-02-12 17:18:16 -05:00
|
|
|
if entry.upper().startswith(self.searchText):
|
2019-02-12 16:33:16 -05:00
|
|
|
return entry
|
|
|
|
if startIndex == self.getCurrIndex():
|
|
|
|
return ''
|
|
|
|
|
2019-01-28 17:29:49 -05:00
|
|
|
def setCurrMenu(self, currMenu = ''):
|
2019-02-04 16:45:12 -05:00
|
|
|
self.currIndex = None
|
|
|
|
self.currMenu = ''
|
|
|
|
if currMenu != '':
|
2019-02-04 17:11:45 -05:00
|
|
|
currMenu += ' ' + _('Menu')
|
2019-02-04 16:32:48 -05:00
|
|
|
try:
|
|
|
|
t = self.menuDict[currMenu]
|
2019-02-04 17:11:45 -05:00
|
|
|
l = list(self.menuDict.keys())
|
|
|
|
self.currIndex = [l.index(currMenu)]
|
|
|
|
except Exception as e:
|
|
|
|
print(e)
|
|
|
|
self.currMenu = ''
|
|
|
|
self.currIndex = None
|
2019-02-04 16:32:48 -05:00
|
|
|
return
|
2019-02-04 16:45:12 -05:00
|
|
|
if self.incLevel():
|
|
|
|
self.currMenu = currMenu
|
2019-02-04 17:11:45 -05:00
|
|
|
else:
|
|
|
|
self.currMenu = ''
|
|
|
|
self.currIndex = None
|
2019-01-28 17:29:49 -05:00
|
|
|
def getCurrMenu(self):
|
|
|
|
return self.currMenu
|
2019-01-21 18:37:07 -05:00
|
|
|
def getActive(self):
|
|
|
|
return self.active
|
2019-02-06 17:51:14 -05:00
|
|
|
def togglelVMenuMode(self, closeAfterAction = True):
|
|
|
|
self.setActive(not self.getActive(), closeAfterAction)
|
|
|
|
def setActive(self, active, closeAfterAction = True):
|
2019-02-12 16:33:16 -05:00
|
|
|
if self.env['runtime']['helpManager'].isTutorialMode():
|
|
|
|
return
|
2019-01-21 18:37:07 -05:00
|
|
|
self.active = active
|
2019-02-03 18:19:21 -05:00
|
|
|
if self.active:
|
2019-02-06 17:51:14 -05:00
|
|
|
self.closeAfterAction = closeAfterAction
|
2019-02-04 16:49:56 -05:00
|
|
|
try:
|
|
|
|
self.createMenuTree()
|
|
|
|
except Exception as e:
|
|
|
|
print(e)
|
|
|
|
try:
|
|
|
|
if self.currMenu != '':
|
|
|
|
self.setCurrMenu(self.currMenu)
|
2019-02-04 17:11:45 -05:00
|
|
|
if self.currIndex == None:
|
|
|
|
if len(self.menuDict) > 0:
|
|
|
|
self.currIndex = [0]
|
2019-02-04 16:49:56 -05:00
|
|
|
except Exception as e:
|
|
|
|
print(e)
|
2019-02-03 18:19:21 -05:00
|
|
|
try:
|
2019-02-12 16:33:16 -05:00
|
|
|
# navigation
|
2019-02-03 18:19:21 -05:00
|
|
|
self.env['bindings'][str([1, ['KEY_ESC']])] = 'TOGGLE_VMENU_MODE'
|
|
|
|
self.env['bindings'][str([1, ['KEY_UP']])] = 'PREV_VMENU_ENTRY'
|
|
|
|
self.env['bindings'][str([1, ['KEY_DOWN']])] = 'NEXT_VMENU_ENTRY'
|
|
|
|
self.env['bindings'][str([1, ['KEY_SPACE']])] = 'CURR_VMENU_ENTRY'
|
|
|
|
self.env['bindings'][str([1, ['KEY_LEFT']])] = 'DEC_LEVEL_VMENU'
|
|
|
|
self.env['bindings'][str([1, ['KEY_RIGHT']])] = 'INC_LEVEL_VMENU'
|
|
|
|
self.env['bindings'][str([1, ['KEY_ENTER']])] = 'EXEC_VMENU_ENTRY'
|
2019-02-12 16:33:16 -05:00
|
|
|
# search
|
|
|
|
self.env['bindings'][str([1, ['KEY_A']])] = 'SEARCH_A'
|
|
|
|
self.env['bindings'][str([1, ['KEY_B']])] = 'SEARCH_B'
|
|
|
|
self.env['bindings'][str([1, ['KEY_C']])] = 'SEARCH_C'
|
|
|
|
self.env['bindings'][str([1, ['KEY_D']])] = 'SEARCH_D'
|
|
|
|
self.env['bindings'][str([1, ['KEY_E']])] = 'SEARCH_E'
|
|
|
|
self.env['bindings'][str([1, ['KEY_F']])] = 'SEARCH_F'
|
|
|
|
self.env['bindings'][str([1, ['KEY_G']])] = 'SEARCH_G'
|
|
|
|
self.env['bindings'][str([1, ['KEY_H']])] = 'SEARCH_H'
|
|
|
|
self.env['bindings'][str([1, ['KEY_I']])] = 'SEARCH_I'
|
|
|
|
self.env['bindings'][str([1, ['KEY_J']])] = 'SEARCH_J'
|
|
|
|
self.env['bindings'][str([1, ['KEY_K']])] = 'SEARCH_K'
|
|
|
|
self.env['bindings'][str([1, ['KEY_L']])] = 'SEARCH_L'
|
|
|
|
self.env['bindings'][str([1, ['KEY_M']])] = 'SEARCH_M'
|
|
|
|
self.env['bindings'][str([1, ['KEY_N']])] = 'SEARCH_N'
|
|
|
|
self.env['bindings'][str([1, ['KEY_O']])] = 'SEARCH_O'
|
|
|
|
self.env['bindings'][str([1, ['KEY_P']])] = 'SEARCH_P'
|
|
|
|
self.env['bindings'][str([1, ['KEY_Q']])] = 'SEARCH_Q'
|
|
|
|
self.env['bindings'][str([1, ['KEY_R']])] = 'SEARCH_R'
|
|
|
|
self.env['bindings'][str([1, ['KEY_S']])] = 'SEARCH_S'
|
|
|
|
self.env['bindings'][str([1, ['KEY_T']])] = 'SEARCH_T'
|
|
|
|
self.env['bindings'][str([1, ['KEY_U']])] = 'SEARCH_U'
|
|
|
|
self.env['bindings'][str([1, ['KEY_V']])] = 'SEARCH_V'
|
|
|
|
self.env['bindings'][str([1, ['KEY_W']])] = 'SEARCH_W'
|
|
|
|
self.env['bindings'][str([1, ['KEY_X']])] = 'SEARCH_X'
|
|
|
|
self.env['bindings'][str([1, ['KEY_Y']])] = 'SEARCH_Y'
|
|
|
|
self.env['bindings'][str([1, ['KEY_Z']])] = 'SEARCH_Z'
|
2019-02-03 18:19:21 -05:00
|
|
|
except Exception as e:
|
|
|
|
print(e)
|
2019-01-21 18:16:41 -05:00
|
|
|
else:
|
|
|
|
try:
|
2019-01-22 18:33:11 -05:00
|
|
|
self.currIndex = None
|
2019-02-12 17:44:57 -05:00
|
|
|
self.env['bindings'] = self.env['runtime']['settingsManager'].getBindingBackup()
|
2019-01-21 18:16:41 -05:00
|
|
|
except:
|
2019-02-03 18:19:21 -05:00
|
|
|
pass
|
2019-04-23 05:54:05 -04:00
|
|
|
def createMenuTree(self, resetIndex = True):
|
|
|
|
if resetIndex:
|
|
|
|
self.currIndex = None
|
2019-02-04 13:39:36 -05:00
|
|
|
menu = self.fs_tree_to_dict( self.defaultVMenuPath)
|
2019-02-03 18:19:21 -05:00
|
|
|
if menu:
|
|
|
|
self.menuDict = menu
|
2019-04-23 05:54:05 -04:00
|
|
|
# index still valid?
|
|
|
|
if self.currIndex != None:
|
|
|
|
try:
|
|
|
|
r = self.getValueByPath(self.menuDict, self.currIndex)
|
|
|
|
if r == {}:
|
|
|
|
self.currIndex = None
|
|
|
|
except:
|
|
|
|
self.currIndex = None
|
2019-01-22 18:33:11 -05:00
|
|
|
def executeMenu(self):
|
|
|
|
if self.currIndex == None:
|
2019-02-03 18:19:21 -05:00
|
|
|
return
|
2019-02-04 13:39:36 -05:00
|
|
|
try:
|
2019-02-04 15:21:10 -05:00
|
|
|
command = self.getValueByPath(self.menuDict, self.currIndex)
|
|
|
|
if not command == None:
|
|
|
|
command.run()
|
2019-02-06 17:51:14 -05:00
|
|
|
if self.closeAfterAction:
|
|
|
|
self.setActive(False)
|
2019-02-04 15:56:36 -05:00
|
|
|
except Exception as e:
|
2019-02-04 16:36:35 -05:00
|
|
|
try:
|
|
|
|
self.incLevel()
|
|
|
|
text = self.getCurrentEntry()
|
|
|
|
self.env['runtime']['outputManager'].presentText(text, interrupt=True)
|
|
|
|
except:
|
|
|
|
print(e)
|
|
|
|
|
2019-01-22 18:33:11 -05:00
|
|
|
def incLevel(self):
|
|
|
|
if self.currIndex == None:
|
2019-02-04 16:45:12 -05:00
|
|
|
return False
|
2019-01-22 18:33:11 -05:00
|
|
|
try:
|
2019-01-29 17:19:49 -05:00
|
|
|
r = self.getValueByPath(self.menuDict, self.currIndex +[0])
|
2019-01-22 18:33:11 -05:00
|
|
|
if r == {}:
|
2019-02-04 16:45:12 -05:00
|
|
|
return False
|
2019-01-22 18:33:11 -05:00
|
|
|
except:
|
2019-02-04 16:45:12 -05:00
|
|
|
return False
|
2019-01-22 18:33:11 -05:00
|
|
|
self.currIndex.append(0)
|
2019-02-04 16:45:12 -05:00
|
|
|
return True
|
2019-01-22 18:33:11 -05:00
|
|
|
def decLevel(self):
|
2019-01-21 18:37:07 -05:00
|
|
|
if self.currIndex == None:
|
2019-02-04 16:45:12 -05:00
|
|
|
return False
|
2019-02-04 16:32:48 -05:00
|
|
|
if self.currMenu != '':
|
2019-02-04 16:36:35 -05:00
|
|
|
if len(self.currIndex) <= 2:
|
2019-02-04 16:45:12 -05:00
|
|
|
return False
|
2019-02-04 16:32:48 -05:00
|
|
|
elif len(self.currIndex) == 1:
|
2019-02-04 16:45:12 -05:00
|
|
|
return False
|
2019-02-04 16:26:51 -05:00
|
|
|
self.currIndex = self.currIndex[:len(self.currIndex) - 1]
|
2019-02-04 16:45:12 -05:00
|
|
|
return True
|
2019-01-21 18:16:41 -05:00
|
|
|
def nextIndex(self):
|
2019-01-21 18:37:07 -05:00
|
|
|
if self.currIndex == None:
|
2019-02-04 16:45:12 -05:00
|
|
|
return False
|
2019-02-04 13:39:36 -05:00
|
|
|
if self.currIndex[len(self.currIndex) - 1] + 1 >= len(self.getNestedByPath(self.menuDict, self.currIndex[:-1])):
|
2019-01-22 18:33:11 -05:00
|
|
|
self.currIndex[len(self.currIndex) - 1] = 0
|
2019-02-04 13:39:36 -05:00
|
|
|
else:
|
|
|
|
self.currIndex[len(self.currIndex) - 1] += 1
|
2019-02-04 16:45:12 -05:00
|
|
|
return True
|
2019-02-12 16:33:16 -05:00
|
|
|
def getCurrIndex(self):
|
|
|
|
if self.currIndex == None:
|
|
|
|
return 0
|
|
|
|
return self.currIndex[len(self.currIndex) - 1]
|
2019-01-21 18:16:41 -05:00
|
|
|
def prevIndex(self):
|
2019-01-21 18:37:07 -05:00
|
|
|
if self.currIndex == None:
|
2019-02-04 16:45:12 -05:00
|
|
|
return False
|
2019-02-04 13:39:36 -05:00
|
|
|
if self.currIndex[len(self.currIndex) - 1] == 0:
|
2019-01-22 18:33:11 -05:00
|
|
|
self.currIndex[len(self.currIndex) - 1] = len(self.getNestedByPath(self.menuDict, self.currIndex[:-1])) - 1
|
2019-02-04 13:39:36 -05:00
|
|
|
else:
|
|
|
|
self.currIndex[len(self.currIndex) - 1] -= 1
|
2019-02-04 16:45:12 -05:00
|
|
|
return True
|
2019-02-04 13:39:36 -05:00
|
|
|
|
2019-01-28 18:03:31 -05:00
|
|
|
def getCurrentEntry(self):
|
|
|
|
return self.getKeysByPath(self.menuDict, self.currIndex)[self.currIndex[-1]]
|
2019-01-22 15:29:55 -05:00
|
|
|
def fs_tree_to_dict(self, path_):
|
|
|
|
for root, dirs, files in os.walk(path_):
|
2019-02-04 16:26:51 -05:00
|
|
|
tree = {d + ' ' + _('Menu'): self.fs_tree_to_dict(os.path.join(root, d)) for d in dirs if not d.startswith('__')}
|
2019-02-04 15:21:10 -05:00
|
|
|
for f in files:
|
|
|
|
try:
|
2019-02-04 16:26:51 -05:00
|
|
|
fileName, fileExtension = os.path.splitext(f)
|
|
|
|
fileName = fileName.split('/')[-1]
|
|
|
|
if fileName.startswith('__'):
|
|
|
|
continue
|
2019-02-04 15:21:10 -05:00
|
|
|
command = self.env['runtime']['commandManager'].loadFile(root + '/' + f)
|
2019-02-04 16:26:51 -05:00
|
|
|
tree.update({fileName + ' ' + _('Action'): command})
|
2019-02-04 15:21:10 -05:00
|
|
|
except Exception as e:
|
|
|
|
print(e)
|
2019-01-22 15:29:55 -05:00
|
|
|
return tree # note we discontinue iteration trough os.walk
|
2019-02-04 13:39:36 -05:00
|
|
|
def getNestedByPath(self, complete, path):
|
|
|
|
path = path.copy()
|
|
|
|
if path != []:
|
|
|
|
index = list(complete.keys())[path[0]]
|
2019-02-04 15:21:10 -05:00
|
|
|
nested = self.getNestedByPath(complete[index], path[1:])
|
2019-02-04 13:39:36 -05:00
|
|
|
return nested
|
|
|
|
else:
|
|
|
|
return complete
|
|
|
|
|
|
|
|
|
2019-01-22 18:33:11 -05:00
|
|
|
def getKeysByPath(self, complete, path):
|
|
|
|
if not isinstance(complete, dict):
|
|
|
|
return[]
|
|
|
|
d = complete
|
|
|
|
for i in path[:-1]:
|
|
|
|
d = d[list(d.keys())[i]]
|
|
|
|
return list(d.keys())
|
|
|
|
|
|
|
|
def getValueByPath(self, complete, path):
|
|
|
|
if not isinstance(complete, dict):
|
2019-02-04 16:26:51 -05:00
|
|
|
return complete
|
2019-01-22 18:33:11 -05:00
|
|
|
d = complete.copy()
|
|
|
|
for i in path:
|
|
|
|
d = d[list(d.keys())[i]]
|
|
|
|
return d
|