Package appModules :: Module miranda32
[hide private]
[frames] | no frames]

Source Code for Module appModules.miranda32

  1  #appModules/miranda32.py 
  2  #A part of NonVisual Desktop Access (NVDA) 
  3  #Copyright (C) 2006-2007 NVDA Contributors <http://www.nvda-project.org/> 
  4  #This file is covered by the GNU General Public License. 
  5  #See the file COPYING for more details. 
  6   
  7  import ui 
  8  import config 
  9  from ctypes import * 
 10  from ctypes.wintypes import * 
 11  import winKernel 
 12  from NVDAObjects.IAccessible import IAccessible, ContentGenericClient 
 13  from NVDAObjects.behaviors import Dialog 
 14  import appModuleHandler 
 15  import speech 
 16  import braille 
 17  import controlTypes 
 18  from scriptHandler import isScriptWaiting 
 19  import api 
 20  import mouseHandler 
 21  import oleacc 
 22  from keyboardHandler import KeyboardInputGesture 
 23  import watchdog 
 24   
 25  #contact list window messages 
 26  CLM_FIRST=0x1000    #this is the same as LVM_FIRST 
 27  CLM_LAST=0x1100 
 28   
 29  #messages, compare with equivalent TVM_s in the MSDN 
 30  CLM_ENSUREVISIBLE=CLM_FIRST+6    #wParam=hItem, lParam=partialOk 
 31  CLE_TOGGLE=-1 
 32  CLE_COLLAPSE=0 
 33  CLE_EXPAND=1 
 34  CLE_INVALID=0xFFFF 
 35  CLM_EXPAND=CLM_FIRST+7    #wParam=hItem, lParam=CLE_ 
 36  CLM_FINDCONTACT=CLM_FIRST+8    #wParam=hContact, returns an hItem 
 37  CLM_FINDGROUP=CLM_FIRST+9    #wParam=hGroup, returns an hItem 
 38  CLM_GETBKCOLOR=CLM_FIRST+10   #returns a COLORREF 
 39  CLM_GETCHECKMARK=CLM_FIRST+11   #wParam=hItem, returns 1 or 0 
 40  CLM_GETCOUNT=CLM_FIRST+12   #returns the total number of items 
 41  CLM_GETEXPAND=CLM_FIRST+14   #wParam=hItem, returns a CLE_, CLE_INVALID if not a group 
 42  CLM_GETEXTRACOLUMNS=CLM_FIRST+15   #returns number of extra columns 
 43  CLM_GETEXTRAIMAGE=CLM_FIRST+16   #wParam=hItem, lParam=MAKELPARAM(iColumn (0 based),0), returns iImage or 0xFF 
 44  CLM_GETEXTRAIMAGELIST=CLM_FIRST+17   #returns HIMAGELIST 
 45  CLM_GETFONT=CLM_FIRST+18   #wParam=fontId, see clm_setfont. returns hFont. 
 46  CLM_GETINDENT=CLM_FIRST+19   #wParam=new group indent 
 47  CLM_GETISEARCHSTRING=CLM_FIRST+20   #lParam=(char*)pszStr, max 120 bytes, returns number of chars in string 
 48  MAXITEMTEXTLEN=120 
 49  CLM_GETITEMTEXT=CLM_FIRST+21   #wParam=hItem, lParam=(char*)pszStr, max 120 bytes 
 50  CLM_GETSELECTION=CLM_FIRST+23   #returns hItem 
 51  CLM_SELECTITEM=CLM_FIRST+26   #wParam=hItem 
 52  CLM_GETHIDEOFFLINEROOT=CLM_FIRST+40   #returns TRUE/FALSE 
 53  CLM_GETEXSTYLE=CLM_FIRST+44   #returns CLS_EX_ flags 
 54  CLM_GETLEFTMARGIN=CLM_FIRST+46   #returns count of pixels 
 55  CLCIT_INVALID=-1 
 56  CLCIT_GROUP=0 
 57  CLCIT_CONTACT=1 
 58  CLCIT_DIVIDER=2 
 59  CLCIT_INFO=3 
 60  CLM_GETITEMTYPE=CLM_FIRST+49    #wParam=hItem, returns a CLCIT_ 
 61  CLGN_ROOT=0 
 62  CLGN_CHILD=1 
 63  CLGN_PARENT=2 
 64  CLGN_NEXT=3 
 65  CLGN_PREVIOUS=4 
 66  CLGN_NEXTCONTACT=5 
 67  CLGN_PREVIOUSCONTACT=6 
 68  CLGN_NEXTGROUP=7 
 69  CLGN_PREVIOUSGROUP=8 
 70  CLM_GETNEXTITEM=CLM_FIRST+50   #wParam=flag, lParam=hItem, returns an hItem 
 71  CLM_GETTEXTCOLOR=CLM_FIRST+51   #wParam=FONTID_, returns COLORREF 
 72  MAXSTATUSMSGLEN=256 
 73  CLM_GETSTATUSMSG=CLM_FIRST+105 
 74   
 75  #other constants 
 76  ANSILOGS=(1001,1006) 
 77  MESSAGEVIEWERS=(1001,1005,5005) 
 78   
79 -class AppModule(appModuleHandler.AppModule):
80 lastTextLengths={} 81 lastMessages=[] 82 # Must not be > 9. 83 MessageHistoryLength=3 84
85 - def chooseNVDAObjectOverlayClasses(self, obj, clsList):
86 if obj.role == controlTypes.ROLE_WINDOW: 87 return 88 windowClass = obj.windowClassName 89 if windowClass == "CListControl": 90 try: 91 clsList.remove(ContentGenericClient) 92 except ValueError: 93 pass 94 clsList.insert(0, mirandaIMContactList) 95 elif windowClass in ("MButtonClass", "TSButtonClass", "CLCButtonClass"): 96 clsList.insert(0, mirandaIMButton) 97 elif windowClass == "Hyperlink": 98 clsList.insert(0, mirandaIMHyperlink) 99 elif isinstance(obj, IAccessible) and obj.IAccessibleRole == oleacc.ROLE_SYSTEM_PROPERTYPAGE: 100 clsList.insert(0, MPropertyPage) 101 elif isinstance(obj, IAccessible) and obj.IAccessibleRole == oleacc.ROLE_SYSTEM_SCROLLBAR and obj.windowControlID in MESSAGEVIEWERS: 102 clsList.insert(0, MirandaMessageViewerScrollbar) 103 elif windowClass == "ListBox" and obj.windowControlID == 0: 104 clsList.insert(0, DuplicateFocusListBox)
105
106 - def event_NVDAObject_init(self,obj):
107 if obj.windowClassName=="ColourPicker": 108 obj.role=controlTypes.ROLE_COLORCHOOSER 109 elif (obj.windowControlID in ANSILOGS) and (obj.windowClassName=="RichEdit20A"): 110 obj._isWindowUnicode=False
111
112 - def script_readMessage(self,gesture):
113 num=int(gesture.mainKeyName[-1]) 114 if len(self.lastMessages)>num-1: 115 ui.message(self.lastMessages[num-1]) 116 else: 117 ui.message(_("No message yet"))
118 script_readMessage.__doc__=_("Displays one of the recent messages") 119
120 - def __init__(self, *args, **kwargs):
121 super(AppModule, self).__init__(*args, **kwargs) 122 for n in xrange(1, self.MessageHistoryLength + 1): 123 self.bindGesture("kb:NVDA+control+%s" % n, "readMessage")
124
125 -class mirandaIMContactList(IAccessible):
126
127 - def _get_name(self):
128 hItem=watchdog.cancellableSendMessage(self.windowHandle,CLM_GETSELECTION,0,0) 129 internalBuf=winKernel.virtualAllocEx(self.processHandle,None,MAXITEMTEXTLEN,winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) 130 try: 131 watchdog.cancellableSendMessage(self.windowHandle,CLM_GETITEMTEXT,hItem,internalBuf) 132 buf=create_unicode_buffer(MAXITEMTEXTLEN) 133 winKernel.readProcessMemory(self.processHandle,internalBuf,buf,MAXITEMTEXTLEN,None) 134 text=buf.value 135 statusMsgPtr=watchdog.cancellableSendMessage(self.windowHandle,CLM_GETSTATUSMSG,hItem,0) 136 if statusMsgPtr>0: 137 buf2=create_unicode_buffer(MAXSTATUSMSGLEN) 138 winKernel.readProcessMemory(self.processHandle,statusMsgPtr,buf2,MAXSTATUSMSGLEN,None) 139 text="%s %s"%(text,buf2.value) 140 finally: 141 winKernel.virtualFreeEx(self.processHandle,internalBuf,0,winKernel.MEM_RELEASE) 142 return text
143
144 - def _get_role(self):
145 hItem=watchdog.cancellableSendMessage(self.windowHandle,CLM_GETSELECTION,0,0) 146 iType=watchdog.cancellableSendMessage(self.windowHandle,CLM_GETITEMTYPE,hItem,0) 147 if iType==CLCIT_DIVIDER or iType==CLCIT_INVALID: #some clists treat invalid as divider 148 return controlTypes.ROLE_SEPARATOR 149 else: 150 return controlTypes.ROLE_TREEVIEWITEM
151
152 - def _get_states(self):
153 newStates=super(mirandaIMContactList,self)._get_states() 154 hItem=watchdog.cancellableSendMessage(self.windowHandle,CLM_GETSELECTION,0,0) 155 state=watchdog.cancellableSendMessage(self.windowHandle,CLM_GETEXPAND,hItem,0) 156 if state==CLE_EXPAND: 157 newStates.add(controlTypes.STATE_EXPANDED) 158 elif state==CLE_COLLAPSE: 159 newStates.add(controlTypes.STATE_COLLAPSED) 160 return newStates
161
162 - def script_changeItem(self,gesture):
163 gesture.send() 164 if not isScriptWaiting(): 165 api.processPendingEvents() 166 speech.speakObject(self,reason=speech.REASON_FOCUS) 167 braille.handler.handleGainFocus(self)
168 169 __changeItemGestures = ( 170 "kb:downArrow", 171 "kb:upArrow", 172 "kb:leftArrow", 173 "kb:rightArrow", 174 "kb:home", 175 "kb:end", 176 "kb:pageUp", 177 "kb:pageDown", 178 ) 179
180 - def initOverlayClass(self):
181 for gesture in self.__changeItemGestures: 182 self.bindGesture(gesture, "changeItem")
183
184 -class mirandaIMButton(IAccessible):
185
186 - def _get_name(self):
187 api.moveMouseToNVDAObject(self) 188 return super(mirandaIMButton,self)._get_name()
189
190 - def _get_role(self):
192
193 - def getActionName(self):
194 if controlTypes.STATE_FOCUSED not in self.states: 195 return 196 return "Click"
197
198 - def doAction(self):
199 if controlTypes.STATE_FOCUSED not in self.states: 200 return 201 KeyboardInputGesture.fromName("space").send()
202
203 - def script_doDefaultAction(self,gesture):
204 self.doAction()
205
206 - def initOverlayClass(self):
207 self.bindGesture("kb:enter", "doDefaultAction")
208 213
214 -class MPropertyPage(Dialog,IAccessible):
215
216 - def _get_name(self):
217 name=super(MPropertyPage,self)._get_name() 218 if not name: 219 try: 220 tc=self.parent.next.firstChild 221 except AttributeError: 222 tc=None 223 if tc and tc.role==controlTypes.ROLE_TABCONTROL: 224 children=tc.children 225 for index in range(len(children)): 226 if (children[index].role==controlTypes.ROLE_TAB) and (controlTypes.STATE_SELECTED in children[index].states): 227 name=children[index].name 228 break 229 return name
230 231
232 -class MirandaMessageViewerScrollbar(IAccessible):
233 - def event_valueChange(self):
234 curTextLength=len(self.windowText) 235 if self.windowHandle not in self.appModule.lastTextLengths: 236 self.appModule.lastTextLengths[self.windowHandle]=curTextLength 237 elif self.appModule.lastTextLengths[self.windowHandle]<curTextLength: 238 message=self.windowText[self.appModule.lastTextLengths[self.windowHandle]:] 239 self.appModule.lastMessages.insert(0,message) 240 self.appModule.lastMessages=self.appModule.lastMessages[:self.appModule.MessageHistoryLength] 241 if config.conf["presentation"]["reportDynamicContentChanges"]: 242 ui.message(message) 243 self.appModule.lastTextLengths[self.windowHandle]=curTextLength 244 super(MirandaMessageViewerScrollbar,self).event_valueChange()
245
246 -class DuplicateFocusListBox(IAccessible):
247 """A list box which annoyingly fires focus events every second, even when a menu is open. 248 """ 249
251 # Stop annoying duplicate focus events, which are fired even if a menu is open. 252 focus = api.getFocusObject() 253 focusRole = focus.role 254 focusStates = focus.states 255 if (self == focus or 256 (focusRole == controlTypes.ROLE_MENUITEM and controlTypes.STATE_FOCUSED in focusStates) or 257 (focusRole == controlTypes.ROLE_POPUPMENU and controlTypes.STATE_INVISIBLE not in focusStates) 258 ): 259 return False 260 return super(DuplicateFocusListBox, self).shouldAllowIAccessibleFocusEvent
261