From ad27496e3d42af36bbb19176dd70d2635171bd1f Mon Sep 17 00:00:00 2001 From: chrys Date: Fri, 25 Aug 2017 20:02:19 +0200 Subject: [PATCH 1/5] wait for the screen is complete --- src/fenrir/screenDriver/vcsaDriver.py | 21 +++++++++++++++------ src/fenrir/utils/screen_utils.py | 13 +++++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/fenrir/screenDriver/vcsaDriver.py b/src/fenrir/screenDriver/vcsaDriver.py index 56aab35b..5b47df29 100644 --- a/src/fenrir/screenDriver/vcsaDriver.py +++ b/src/fenrir/screenDriver/vcsaDriver.py @@ -128,8 +128,8 @@ class driver(): currScreen = str(tty.read()[3:-1]) oldScreen = currScreen watchdog = select.epoll() - watchdog.register(vcsa[currScreen], select.EPOLLPRI) - watchdog.register(tty, select.EPOLLPRI) + watchdog.register(vcsa[currScreen], select.POLLPRI | select.POLLERR) + watchdog.register(tty, select.POLLPRI | select.POLLERR) lastScreenContent = b'' while active.value == 1: changes = watchdog.poll(2) @@ -146,7 +146,7 @@ class driver(): except: pass try: - watchdog.register(vcsa[ currScreen ], select.EPOLLPRI) + watchdog.register(vcsa[ currScreen ], select.POLLPRI | select.POLLERR) except: pass oldScreen = currScreen @@ -158,9 +158,18 @@ class driver(): lastScreenContent = b'' else: self.env['runtime']['debug'].writeDebugOut('ScreenUpdate',debug.debugLevel.INFO) - vcsa[currScreen].seek(0) - screenContent = vcsa[currScreen].read() - if screenContent != lastScreenContent: + vcsa[currScreen].seek(0) + dirtyContent = vcsa[currScreen].read() + screenContent = b'' + timeout = time.time() + if dirtyContent != lastScreenContent: + while screenContent != dirtyContent: + screenContent = dirtyContent + if time.time() - timeout > 0.2: + break + vcsa[currScreen].seek(0) + dirtyContent = vcsa[currScreen].read() + time.sleep(0.01) eventQueue.put({"Type":fenrirEventType.ScreenUpdate,"Data":None}) lastScreenContent = screenContent except Exception as e: diff --git a/src/fenrir/utils/screen_utils.py b/src/fenrir/utils/screen_utils.py index 432f1aac..267bcdad 100644 --- a/src/fenrir/utils/screen_utils.py +++ b/src/fenrir/utils/screen_utils.py @@ -7,6 +7,9 @@ from core import debug from collections import Counter import string +from select import select +from select import epoll +import select def removeNonprintable(text): # Get the difference of all ASCII characters from the set of printable characters @@ -20,6 +23,16 @@ def insertNewlines(string, every=64): def splitEvery(toSplit, every=64): return list(toSplit[i:i+every] for i in range(0, len(toSplit), every)) +def hasMoreRead(fd): + r, w, e = select([fd], [], [], 0) + return (fd in r) + +def hasMorePollPri(fd): + p = epoll() + p.register(fd, select.POLLPRI | select.POLLERR) + r = p.poll(0) + return (fd in r) + def trackHighlights(oldAttr, newAttr, text, lenght): result = '' currCursor = None From f29ce653f1448d6e999cc98b5fa2d49f5ccb23eb Mon Sep 17 00:00:00 2001 From: chrys Date: Fri, 25 Aug 2017 20:04:25 +0200 Subject: [PATCH 2/5] increase watchdog timeout --- src/fenrir/screenDriver/vcsaDriver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fenrir/screenDriver/vcsaDriver.py b/src/fenrir/screenDriver/vcsaDriver.py index 5b47df29..5480dc21 100644 --- a/src/fenrir/screenDriver/vcsaDriver.py +++ b/src/fenrir/screenDriver/vcsaDriver.py @@ -165,7 +165,7 @@ class driver(): if dirtyContent != lastScreenContent: while screenContent != dirtyContent: screenContent = dirtyContent - if time.time() - timeout > 0.2: + if time.time() - timeout >= 0.3: break vcsa[currScreen].seek(0) dirtyContent = vcsa[currScreen].read() From 420103090595a61ba955d8c9093f7f0c210fc5f5 Mon Sep 17 00:00:00 2001 From: chrys Date: Fri, 25 Aug 2017 21:38:48 +0200 Subject: [PATCH 3/5] fix history, start cleaning up API --- .../onScreenUpdate/deactive/72000-history.py | 58 ------------------- src/fenrir/core/fenrirManager.py | 10 +++- src/fenrir/core/inputManager.py | 33 ++++++----- src/fenrir/screenDriver/vcsaDriver.py | 21 +++---- 4 files changed, 37 insertions(+), 85 deletions(-) delete mode 100644 src/fenrir/commands/onScreenUpdate/deactive/72000-history.py diff --git a/src/fenrir/commands/onScreenUpdate/deactive/72000-history.py b/src/fenrir/commands/onScreenUpdate/deactive/72000-history.py deleted file mode 100644 index 7cde4a06..00000000 --- a/src/fenrir/commands/onScreenUpdate/deactive/72000-history.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/python -# -*- coding: utf-8 -*- - -# Fenrir TTY screen reader -# By Chrys, Storm Dragon, and contributers. - -from core import debug - -class command(): - def __init__(self): - pass - def initialize(self, environment): - self.env = environment - def shutdown(self): - pass - def getDescription(self): - return '' - - def run(self): - if self.env['runtime']['inputManager'].noKeyPressed(): - return - if self.env['screen']['newAttribDelta'] != '': - return - if self.env['runtime']['screenManager'].isScreenChange(): - return - if self.env['runtime']['cursorManager'].isCursorVerticalMove(): - return - if len(self.env['input']['currInput']) != 1: - return - if not self.env['input']['currInput'][0] in ['KEY_UP','KEY_DOWN']: - return - prevLine = self.env['screen']['oldContentText'].split('\n')[self.env['screen']['newCursor']['y']] - currLine = self.env['screen']['newContentText'].split('\n')[self.env['screen']['newCursor']['y']] - if not currLine.isspace(): - currPrompt = currLine.find('$') - rootPrompt = currLine.find('#') - if currPrompt <= 0: - if rootPrompt > 0: - currPrompt = rootPrompt - else: - announce = currLine - if currPrompt > 0: - remove_digits = str.maketrans('0123456789', ' ') - if prevLine[:currPrompt].translate(remove_digits) == currLine[:currPrompt].translate(remove_digits): - announce = currLine[currPrompt+1:] - else: - announce = currLine - - if currLine.isspace(): - self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True, flush=False) - else: - self.env['runtime']['outputManager'].presentText(announce, interrupt=True, flush=False) - self.env['commandsIgnore']['onScreenUpdate']['CHAR_DELETE_ECHO'] = True - self.env['commandsIgnore']['onScreenUpdate']['CHAR_ECHO'] = True - self.env['commandsIgnore']['onScreenUpdate']['INCOMING_IGNORE'] = True - def setCallback(self, callback): - pass - diff --git a/src/fenrir/core/fenrirManager.py b/src/fenrir/core/fenrirManager.py index d6193199..4ac8ec97 100644 --- a/src/fenrir/core/fenrirManager.py +++ b/src/fenrir/core/fenrirManager.py @@ -51,6 +51,8 @@ class fenrirManager(): def handleInput(self, event): #startTime = time.time() eventReceived = self.environment['runtime']['inputManager'].getInputEvent() + if self.environment['runtime']['inputManager'].noKeyPressed(): + self.environment['runtime']['inputManager'].clearLastDeepInput() if eventReceived: if self.environment['runtime']['screenManager'].isSuspendingScreen(): @@ -106,11 +108,15 @@ class fenrirManager(): self.environment['runtime']['applicationManager'].getPrevApplication(), \ self.environment['runtime']['applicationManager'].getCurrentApplication()) ''' - # has cursor changed? + # timout for the last keypress + if time.time() - self.environment['runtime']['inputManager'].getLastInputTime() >= 0.3: + self.environment['runtime']['inputManager'].clearLastDeepInput() + # has cursor changed? if self.environment['runtime']['cursorManager'].isCursorVerticalMove() or \ self.environment['runtime']['cursorManager'].isCursorHorizontalMove(): self.environment['runtime']['commandManager'].executeDefaultTrigger('onCursorChange') self.environment['runtime']['commandManager'].executeDefaultTrigger('onScreenUpdate') + self.environment['runtime']['inputManager'].clearLastDeepInput() #print('handleScreenUpdate:',time.time() - startTime) def handlePlugInputDevice(self, event): @@ -128,7 +134,7 @@ class fenrirManager(): else: if not self.environment['runtime']['inputManager'].noKeyPressed(): if self.singleKeyCommand: - self.singleKeyCommand = len(self.environment['input']['prevDeepestInput']) == 1 + self.singleKeyCommand = len( self.environment['runtime']['inputManager'].getLastDeepestInput() ) == 1 # key is already released. we need the old one if not( self.singleKeyCommand and self.environment['runtime']['inputManager'].noKeyPressed()): shortcut = self.environment['runtime']['inputManager'].getCurrShortcut() diff --git a/src/fenrir/core/inputManager.py b/src/fenrir/core/inputManager.py index df82337e..2620eab0 100644 --- a/src/fenrir/core/inputManager.py +++ b/src/fenrir/core/inputManager.py @@ -22,7 +22,8 @@ class inputManager(): self.env['input']['oldCapsLock'] = self.env['input']['newCapsLock'] self.env['input']['newScrollLock'] = self.env['runtime']['inputDriver'].getLedState(2) self.env['input']['oldScrollLock'] = self.env['input']['newScrollLock'] - + self.lastDeepestInput = [] + self.lastInputTime = time.time() def shutdown(self): self.removeAllDevices() self.env['runtime']['settingsManager'].shutdownDriver('inputDriver') @@ -40,26 +41,25 @@ class inputManager(): if len(self.env['input']['currInput']) > 1: self.env['input']['currInput'] = sorted(self.env['input']['currInput']) elif len(self.env['input']['currInput']) == 0: - self.env['input']['prevDeepestInput'] = [] self.env['input']['shortcutRepeat'] = 1 self.setLedState = self.handleLedStates(mEvent) - self.env['input']['lastInputTime'] = time.time() + self.lastInputTime = time.time() elif mEvent['EventState'] == 1: if not mEvent['EventName'] in self.env['input']['currInput']: self.env['input']['currInput'].append(mEvent['EventName']) if len(self.env['input']['currInput']) > 1: self.env['input']['currInput'] = sorted(self.env['input']['currInput']) - if len(self.env['input']['prevDeepestInput']) < len(self.env['input']['currInput']): - self.env['input']['prevDeepestInput'] = self.env['input']['currInput'].copy() - elif self.env['input']['prevDeepestInput'] == self.env['input']['currInput']: - if time.time() - self.env['input']['lastInputTime'] <= self.env['runtime']['settingsManager'].getSettingAsFloat('keyboard','doubleTapTimeout'): + if len(self.lastDeepestInput) < len(self.env['input']['currInput']): + self.setLastDeepestInput( self.env['input']['currInput'].copy()) + elif self.lastDeepestInput == self.env['input']['currInput']: + if time.time() - self.lastInputTime <= self.env['runtime']['settingsManager'].getSettingAsFloat('keyboard','doubleTapTimeout'): self.env['input']['shortcutRepeat'] += 1 else: self.env['input']['shortcutRepeat'] = 1 self.setLedState = self.handleLedStates(mEvent) - self.env['input']['lastInputTime'] = time.time() + self.lastInputTime = time.time() elif mEvent['EventState'] == 2: - self.env['input']['lastInputTime'] = time.time() + self.lastInputTime = time.time() else: pass self.env['input']['oldNumLock'] = self.env['input']['newNumLock'] @@ -143,7 +143,14 @@ class inputManager(): def clearEventBuffer(self): self.env['runtime']['inputDriver'].clearEventBuffer() - + def setLastDeepestInput(self, currentDeepestInput): + self.lastDeepestInput = currentDeepestInput + def clearLastDeepInput(self): + self.lastDeepestInput = [] + def getLastInputTime(self): + return self.lastInputTime + def getLastDeepestInput(self): + return self.lastDeepestInput def writeEventBuffer(self): try: if self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'grabDevices'): @@ -157,10 +164,10 @@ class inputManager(): return self.env['input']['currInput'] == [] def isKeyPress(self): return (self.env['input']['prevInput'] == []) and (self.env['input']['currInput'] != []) - def getPrevDeepestInput(self): + def getPrevDeepestShortcut(self): shortcut = [] shortcut.append(self.env['input']['shortcutRepeat']) - shortcut.append(self.env['input']['prevDeepestInput']) + shortcut.append(self.getLastDeepestInput()) return str(shortcut) def getPrevShortcut(self): @@ -186,7 +193,7 @@ class inputManager(): return str(shortcut) def currKeyIsModifier(self): - if len(self.env['input']['prevDeepestInput']) != 1: + if len(self.getLastDeepestInput()) != 1: return False return (self.env['input']['currInput'][0] =='KEY_FENRIR') or (self.env['input']['currInput'][0] == 'KEY_SCRIPT') diff --git a/src/fenrir/screenDriver/vcsaDriver.py b/src/fenrir/screenDriver/vcsaDriver.py index 5480dc21..618a89aa 100644 --- a/src/fenrir/screenDriver/vcsaDriver.py +++ b/src/fenrir/screenDriver/vcsaDriver.py @@ -130,7 +130,6 @@ class driver(): watchdog = select.epoll() watchdog.register(vcsa[currScreen], select.POLLPRI | select.POLLERR) watchdog.register(tty, select.POLLPRI | select.POLLERR) - lastScreenContent = b'' while active.value == 1: changes = watchdog.poll(2) for change in changes: @@ -155,23 +154,21 @@ class driver(): vcsa[currScreen].seek(0) lastScreenContent = vcsa[currScreen].read() except: - lastScreenContent = b'' + pass else: self.env['runtime']['debug'].writeDebugOut('ScreenUpdate',debug.debugLevel.INFO) vcsa[currScreen].seek(0) dirtyContent = vcsa[currScreen].read() screenContent = b'' timeout = time.time() - if dirtyContent != lastScreenContent: - while screenContent != dirtyContent: - screenContent = dirtyContent - if time.time() - timeout >= 0.3: - break - vcsa[currScreen].seek(0) - dirtyContent = vcsa[currScreen].read() - time.sleep(0.01) - eventQueue.put({"Type":fenrirEventType.ScreenUpdate,"Data":None}) - lastScreenContent = screenContent + while screenContent != dirtyContent: + screenContent = dirtyContent + if time.time() - timeout >= 0.4: + break + time.sleep(0.03) + vcsa[currScreen].seek(0) + dirtyContent = vcsa[currScreen].read() + eventQueue.put({"Type":fenrirEventType.ScreenUpdate,"Data":None}) except Exception as e: self.env['runtime']['debug'].writeDebugOut('VCSA:updateWatchdog:' + str(e),debug.debugLevel.ERROR) From a14cf82a2f3d477bcd4b16deb588539e40561450 Mon Sep 17 00:00:00 2001 From: chrys Date: Fri, 25 Aug 2017 21:38:54 +0200 Subject: [PATCH 4/5] fix history, start cleaning up API --- .../commands/onScreenUpdate/60000-history.py | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/fenrir/commands/onScreenUpdate/60000-history.py diff --git a/src/fenrir/commands/onScreenUpdate/60000-history.py b/src/fenrir/commands/onScreenUpdate/60000-history.py new file mode 100644 index 00000000..efdbe244 --- /dev/null +++ b/src/fenrir/commands/onScreenUpdate/60000-history.py @@ -0,0 +1,54 @@ +#!/bin/python +# -*- coding: utf-8 -*- + +# Fenrir TTY screen reader +# By Chrys, Storm Dragon, and contributers. + +from core import debug + +class command(): + def __init__(self): + pass + def initialize(self, environment): + self.env = environment + def shutdown(self): + pass + def getDescription(self): + return '' + + def run(self): + if self.env['screen']['newAttribDelta'] != '': + return + if self.env['runtime']['screenManager'].isScreenChange(): + return + if self.env['runtime']['cursorManager'].isCursorVerticalMove(): + return + if not (self.env['runtime']['inputManager'].getLastDeepestInput() in [['KEY_UP'],['KEY_DOWN']]): + return + prevLine = self.env['screen']['oldContentText'].split('\n')[self.env['screen']['newCursor']['y']] + currLine = self.env['screen']['newContentText'].split('\n')[self.env['screen']['newCursor']['y']] + if not currLine.isspace(): + currPrompt = currLine.find('$') + rootPrompt = currLine.find('#') + if currPrompt <= 0: + if rootPrompt > 0: + currPrompt = rootPrompt + else: + announce = currLine + if currPrompt > 0: + remove_digits = str.maketrans('0123456789', ' ') + if prevLine[:currPrompt].translate(remove_digits) == currLine[:currPrompt].translate(remove_digits): + announce = currLine[currPrompt+1:] + else: + announce = currLine + + if currLine.isspace(): + self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True, flush=False) + else: + self.env['runtime']['outputManager'].presentText(announce, interrupt=True, flush=False) + self.env['commandsIgnore']['onScreenUpdate']['CHAR_DELETE_ECHO'] = True + self.env['commandsIgnore']['onScreenUpdate']['CHAR_ECHO'] = True + self.env['commandsIgnore']['onScreenUpdate']['INCOMING_IGNORE'] = True + def setCallback(self, callback): + pass + From 9db0073fdf42e9eef58d604a2fea0b4f583da457 Mon Sep 17 00:00:00 2001 From: chrys Date: Fri, 25 Aug 2017 21:49:48 +0200 Subject: [PATCH 5/5] mark bug as fixed --- TODO v1.5 | 1 - 1 file changed, 1 deletion(-) diff --git a/TODO v1.5 b/TODO v1.5 index b92a87b2..0be766b3 100644 --- a/TODO v1.5 +++ b/TODO v1.5 @@ -1,6 +1,5 @@ Blocker bugs for fenrir 1.5 - device detection is broken -- arrow up/down announcement is broken -----------DONE---------------- - Doku: Write a user wiki