# -*- coding: UTF-8 -*- #appModules/skype.py #A part of NonVisual Desktop Access (NVDA) #Copyright (C) 2007-2015 Peter Vágner, NV Access Limited #This file is covered by the GNU General Public License. #See the file COPYING for more details. import re from comtypes import COMError import wx import appModuleHandler import controlTypes import winUser import NVDAObjects.IAccessible import oleacc import ui import windowUtils import displayModel import queueHandler import config import NVDAObjects.behaviors import api from logHandler import log # Translators: The name of the NVDA command category for Skype specific commands. SCRCAT_SKYPE = _("Skype") TYPING_INDICATOR_MATCH = { ("TTypingIndicatorPanel", controlTypes.ROLE_STATICTEXT), ("TWidgetControl", controlTypes.ROLE_LISTITEM), # Skype <= 7.2 } class Conversation(NVDAObjects.IAccessible.IAccessible): scriptCategory = SCRCAT_SKYPE def initOverlayClass(self): for n in xrange(0, 10): self.bindGesture("kb:NVDA+control+%d" % n, "reviewRecentMessage") def _isEqual(self, other): # Sometimes, we get this object as an unproxied IAccessible, # which means the location is different, so IAccessible._isEqual return False. # This can cause us to get a gainFocus and a focusEntered on two different instances. # We don't care about the location here. return self.windowHandle == other.windowHandle def _gainedFocus(self): # The user has entered this Skype conversation. if self.appModule.conversation: # Another conversation was previously focused. Clean it up. self.appModule.conversation.lostFocus() self.appModule.conversation = self try: self.outputList = NVDAObjects.IAccessible.getNVDAObjectFromEvent( windowUtils.findDescendantWindow(self.windowHandle, className="TChatContentControl"), winUser.OBJID_CLIENT, 0).lastChild except LookupError: log.debugWarning("Couldn't find output list") self.outputList = None else: self.outputList.startMonitoring() for wClass, role in TYPING_INDICATOR_MATCH: try: self.typingIndicator = NVDAObjects.IAccessible.getNVDAObjectFromEvent( windowUtils.findDescendantWindow(self.windowHandle, className=wClass), winUser.OBJID_CLIENT, 1) except LookupError: continue self.typingIndicator.startMonitoring() break else: log.debugWarning("Couldn't find typing indicator") self.typingIndicator = None def event_focusEntered(self): self._gainedFocus() super(Conversation, self).event_focusEntered() def event_gainFocus(self): # A conversation might have its own top level window, # but foreground changes often trigger gainFocus instead of focusEntered. self._gainedFocus() super(Conversation, self).event_gainFocus() def lostFocus(self): self.appModule.conversation = None if self.outputList: self.outputList.stopMonitoring() self.outputList = None if self.typingIndicator: self.typingIndicator.stopMonitoring() self.typingIndicator = None def script_reviewRecentMessage(self, gesture): try: index = int(gesture.mainKeyName[-1]) except (AttributeError, ValueError): return if index == 0: index = 10 self.outputList.reviewRecentMessage(index) # Describes the NVDA command to review messages in Skype. script_reviewRecentMessage.__doc__ = _("Reports and moves the review cursor to a recent message") script_reviewRecentMessage.canPropagate = True class ChatOutputList(NVDAObjects.IAccessible.IAccessible): def startMonitoring(self): self.oldMessageCount = None self.update(initial=True) displayModel.requestTextChangeNotifications(self, True) def stopMonitoring(self): displayModel.requestTextChangeNotifications(self, False) RE_MESSAGE = re.compile(r"^From (?P.*), (?P.*), sent on (?P