#api.py
#A part of NonVisual Desktop Access (NVDA)
#Copyright (C) 2006-2007 NVDA Contributors
#This file is covered by the GNU General Public License.
#See the file COPYING for more details.
"""General functions for NVDA"""
import textHandler
import globalVars
from logHandler import log
import speech
import sayAllHandler
import virtualBufferHandler
import NVDAObjects
import NVDAObjects.IAccessible
import winUser
import controlTypes
import win32clipboard
import win32con
#User functions
def findObjectWithFocus():
"""Walks the object hyerarchy starting at the desktop Window (root object) and follows the activeChild property of each object until it can not go any further - this will be the object with focus.
@returns: object with focus
@rtype: L{NVDAObjects.NVDAObject}
"""
obj=getDesktopObject()
prevObj=None
while obj and obj!=prevObj:
prevObj=obj
obj=obj.activeChild
return prevObj
def getFocusObject():
"""
Gets the current object with focus.
@returns: the object with focus
@rtype: L{NVDAObjects.NVDAObject}
"""
return globalVars.focusObject
def getForegroundObject():
"""Gets the current foreground object.
@returns: the current foreground object
@rtype: L{NVDAObjects.NVDAObject}
"""
numAncestors=len(globalVars.focusAncestors)
if numAncestors<=1:
return globalVars.focusObject
elif globalVars.focusAncestors[1].role==controlTypes.ROLE_WINDOW:
if numAncestors==2:
return globalVars.focusObject
return globalVars.focusAncestors[2]
else:
return globalVars.focusAncestors[1]
def setForegroundObject(obj):
"""Stores the given object as the current foreground object. (Note: it does not physically change the operating system foreground window, but only allows NVDA to keep track of what it is).
@param obj: the object that will be stored as the current foreground object
@type obj: NVDAObjects.NVDAObject
"""
if not isinstance(obj,NVDAObjects.NVDAObject):
return False
globalVars.foregroundObject=obj
if log.isEnabledFor(log.DEBUG):
log.debug("%s %s %s %s"%(obj.name or "",controlTypes.speechRoleLabels[obj.role],obj.value or "",obj.description or ""))
return True
def setFocusObject(obj):
"""Stores an object as the current focus object. (Note: this does not physically change the window with focus in the operating system, but allows NVDA to keep track of the correct object).
Before overriding the last object, this function calls event_loseFocus on the object to notify it that it is loosing focus.
@param obj: the object that will be stored as the focus object
@type obj: NVDAObjects.NVDAObject
"""
if not isinstance(obj,NVDAObjects.NVDAObject):
return False
if globalVars.focusObject and hasattr(globalVars.focusObject,"event_loseFocus"):
try:
globalVars.focusObject.event_loseFocus()
except:
log.error("event_loseFocus in focusObject", exc_info=True)
oldFocusLine=globalVars.focusAncestors
#add the old focus to the old focus ancestors, but only if its not None (is none at NVDA initialization)
if globalVars.focusObject:
oldFocusLine.append(globalVars.focusObject)
oldAppModuleSet=set(o.appModule for o in oldFocusLine if o and o.appModule)
ancestors=[]
tempObj=obj
matchedOld=False
focusDifferenceLevel=0
oldFocusLineLength=len(oldFocusLine)
# Starting from the focus, move up the ancestor chain.
while tempObj:
# Scan backwards through the old ancestors looking for a match.
for index in xrange(oldFocusLineLength-1,-1,-1):
if tempObj==oldFocusLine[index]:
# Match! The old and new focus ancestors converge at this point.
# Copy the old ancestors up to and including this object.
origAncestors=oldFocusLine[0:index+1]
#make sure to cache the last old ancestor as a parent on the first new ancestor so as not to leave a broken parent cache
if ancestors and origAncestors:
ancestors[0].parent=origAncestors[-1]
origAncestors.extend(ancestors)
ancestors=origAncestors
focusDifferenceLevel=index+1
# We don't need to process any more in either this loop or the outer loop; we have all of the ancestors.
matchedOld=True
break
if matchedOld:
break
# We're moving backwards along the ancestor chain, so add this to the start of the list.
ancestors.insert(0,tempObj)
parent=tempObj.parent
tempObj.parent=parent # Cache the parent.
tempObj=parent
#Remove the final new ancestor as this will be the new focus object
del ancestors[-1]
newAppModuleSet=set(o.appModule for o in ancestors+[obj] if o and o.appModule)
for removedMod in oldAppModuleSet-newAppModuleSet:
if hasattr(removedMod,'event_appLoseFocus'):
removedMod.event_appLoseFocus()
for addedMod in newAppModuleSet-oldAppModuleSet:
if hasattr(addedMod,'event_appGainFocus'):
addedMod.event_appGainFocus()
if not obj.virtualBuffer or not obj.virtualBuffer.isAlive():
virtualBufferObject=None
for o in ancestors[focusDifferenceLevel:]+[obj]:
virtualBufferObject=virtualBufferHandler.update(o)
if virtualBufferObject:
break
obj.virtualBuffer=virtualBufferObject
if virtualBufferObject and hasattr(virtualBufferObject,"event_virtualBuffer_firstGainFocus"):
virtualBufferObject.event_virtualBuffer_firstGainFocus()
oldVirtualBuffer=globalVars.focusObject.virtualBuffer if globalVars.focusObject else None
# Set global focus variables before calling event_virtualBuffer_gainFocus.
globalVars.focusDifferenceLevel=focusDifferenceLevel
globalVars.focusObject=obj
globalVars.focusAncestors=ancestors
if obj.virtualBuffer is not oldVirtualBuffer:
if hasattr(oldVirtualBuffer,"event_virtualBuffer_loseFocus"):
oldVirtualBuffer.event_virtualBuffer_loseFocus()
if hasattr(obj.virtualBuffer,"event_virtualBuffer_gainFocus"):
obj.virtualBuffer.event_virtualBuffer_gainFocus()
if log.isEnabledFor(log.DEBUG):
log.debug("%s %s %s %s"%(obj.name or "",controlTypes.speechRoleLabels[obj.role],obj.value or "",obj.description or ""))
return True
def getFocusDifferenceLevel():
return globalVars.focusDifferenceLevel
def getFocusAncestors():
return globalVars.focusAncestors
def getMouseObject():
"""Returns the object that is directly under the mouse"""
return globalVars.mouseObject
def setMouseObject(obj):
"""Tells NVDA to remember the given object as the object that is directly under the mouse"""
if log.isEnabledFor(log.DEBUG):
log.debug("%s %s %s %s"%(obj.name or "",controlTypes.speechRoleLabels[obj.role],obj.value or "",obj.description or ""))
globalVars.mouseObject=obj
def getDesktopObject():
"""Get the desktop object"""
return globalVars.desktopObject
def setDesktopObject(obj):
"""Tells NVDA to remember the given object as the desktop object"""
if log.isEnabledFor(log.DEBUG):
log.debug("%s %s %s %s"%(obj.name or "",controlTypes.speechRoleLabels[obj.role],obj.value or "",obj.description or ""))
globalVars.desktopObject=obj
def getReviewPosition():
"""Retreaves the current TextInfo instance representing the user's review position. If it is not set, it uses the user's set navigator object and creates a TextInfo from that.
"""
if globalVars.reviewPosition:
return globalVars.reviewPosition
else:
try:
globalVars.reviewPosition=globalVars.navigatorObject.virtualBuffer.makeTextInfo(globalVars.navigatorObject)
return globalVars.reviewPosition
except:
pass
try:
globalVars.reviewPosition=globalVars.navigatorObject.makeTextInfo(textHandler.POSITION_CARET)
return globalVars.reviewPosition
except:
globalVars.reviewPosition=globalVars.navigatorObject.makeTextInfo(textHandler.POSITION_FIRST)
return globalVars.reviewPosition
def setReviewPosition(reviewPosition):
"""Sets a TextInfo instance as the review position. It sets the current navigator object to None so that the next time the navigator object is asked for it fetches it from the review position.
"""
globalVars.reviewPosition=reviewPosition
globalVars.navigatorObject=None
import braille
braille.handler.handleReviewMove()
def getNavigatorObject():
"""Gets the current navigator object. Navigator objects can be used to navigate around the operating system (with the number pad) with out moving the focus. If the navigator object is not set, it fetches it from the review position.
@returns: the current navigator object
@rtype: L{NVDAObjects.NVDAObject}
"""
if globalVars.navigatorObject:
return globalVars.navigatorObject
else:
globalVars.navigatorObject=globalVars.reviewPosition.NVDAObjectAtStart
return globalVars.navigatorObject
def setNavigatorObject(obj):
"""Sets an object to be the current navigator object. Navigator objects can be used to navigate around the operating system (with the number pad) with out moving the focus. It also sets the current review position to None so that next time the review position is asked for, it is created from the navigator object.
@param obj: the object that will be set as the current navigator object
@type obj: NVDAObjects.NVDAObject
"""
if not isinstance(obj,NVDAObjects.NVDAObject):
return False
if log.isEnabledFor(log.DEBUG):
log.debug("%s %s %s %s"%(obj.name or "",controlTypes.speechRoleLabels[obj.role],obj.value or "",obj.description or ""))
globalVars.navigatorObject=obj
globalVars.reviewPosition=None
import braille
braille.handler.handleReviewMove()
def isTypingProtected():
"""Checks to see if key echo should be suppressed because the focus is currently on an object that has its protected state set.
@returns: True if it should be suppressed, False otherwise.
@rtype: boolean
"""
focusObject=getFocusObject()
if focusObject and (controlTypes.STATE_PROTECTED in focusObject.states or focusObject.role==controlTypes.ROLE_PASSWORDEDIT):
return True
else:
return False
def createStateList(states):
"""Breaks down the given integer in to a list of numbers that are 2 to the power of their position."""
return [x for x in [1<0 and not text.isspace():
win32clipboard.OpenClipboard()
try:
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardData(win32con.CF_UNICODETEXT, text)
finally:
win32clipboard.CloseClipboard()
win32clipboard.OpenClipboard() # there seems to be a bug so to retrieve unicode text we have to reopen the clipboard
try:
got = win32clipboard.GetClipboardData(win32con.CF_UNICODETEXT)
finally:
win32clipboard.CloseClipboard()
if got == text:
return True
return False
def getClipData():
"""Receives text from the windows clipboard.
@returns: Clipboard text
@rtype: string
"""
text = ""
win32clipboard.OpenClipboard()
try:
text = win32clipboard.GetClipboardData(win32con.CF_UNICODETEXT)
finally:
win32clipboard.CloseClipboard()
return text
def getStatusBar():
"""Obtain the status bar for the current foreground object.
@return: The status bar object or C{None} if no status bar was found.
@rtype: L{NVDAObjects.NVDAObject}
"""
# The status bar is usually at the bottom of the screen.
# Therefore, get the object at the bottom left of the foreground object using screen coordinates.
foreground = getForegroundObject()
location=foreground.location
if not location:
return None
left, top, width, height = location
bottom = top + height - 1
obj = NVDAObjects.IAccessible.getNVDAObjectFromPoint(left, bottom)
# We may have landed in a child of the status bar, so search the ancestry for a status bar.
while obj and not obj.role == controlTypes.ROLE_STATUSBAR:
obj = obj.parent
return obj
def getStatusBarText(obj):
"""Get the text from a status bar.
This includes the name of the status bar and the names and values of all of its children.
@param obj: The status bar.
@type obj: L{NVDAObjects.NVDAObject}
@return: The status bar text.
@rtype: str
"""
text = obj.name
if text is None:
text = ""
return text + " ".join(chunk for child in obj.children for chunk in (child.name, child.value) if chunk and isinstance(chunk, basestring) and not chunk.isspace())
def filterFileName(name):
"""Replaces invalid characters in a given string to make a windows compatible file name.
@param name: The file name to filter.
@type name: str
@returns: The filtered file name.
@rtype: str
"""
invalidChars=':?*\|<>/"'
for c in invalidChars:
name=name.replace(c,'_')
return name