OSDN Git Service

Hungarian (hu):
[nvdajp/nvdajp.git] / developerGuide.t2t
1 NVDA NVDA_VERSION Developer Guide\r
2 \r
3 \r
4 %!includeconf: user_docs/userGuide.t2tconf\r
5 \r
6 % Remove double spacing from the beginning of each line as txt2tags seems to indent preformatted text by two spaces\r
7 %!PostProc(html): '^  ' ''\r
8 \r
9 = Table of Contents =[toc]\r
10 %%toc\r
11 \r
12 + Introduction +\r
13 This guide provides information concerning NVDA development, including translation and the development of components for NVDA.\r
14 \r
15 ++ A Note About Python ++\r
16 NVDA and its components are primarily written in the Python programming language.\r
17 It is not the goal of this guide to teach you Python, though examples are provided through out this guide which will help to familiarise you with the Python syntax.\r
18 Documentation and other resources related to the Python language can be found at www.python.org/\r
19 \r
20 + Translation +\r
21 In order to support multiple languages/locales, NVDA must be translated and data specific to the locale must be provided.\r
22 This section only includes information on custom NVDA file formats required for translation.\r
23 Other items need to be translated, such as the NVDA user interface and documentation, but these use standard file formats.\r
24 For complete documentation about translating NVDA, please see http://www.nvda-project.org/wiki/TranslatingNVDA\r
25 \r
26 ++ Character Descriptions ++\r
27 Sometimes, it can be very difficult or even impossible to distinguish one character from another.\r
28 For example, two characters might be pronounced the same way, even though they are actually different characters.\r
29 To help users when this occurs, character descriptions can be provided which describe the character in a unique way.\r
30 \r
31 Character descriptions can be provided for a locale in a file named characterDescriptions.dic in the directory for the locale.\r
32 This is a UTF-8 encoded text file.\r
33 Blank lines and lines beginning with a "#" character are ignored.\r
34 All other lines should contain a character, followed by a tab, then one or more descriptions separated by tabs.\r
35 \r
36 For example:\r
37 ```\r
38 # This is a comment.\r
39 a       alpha\r
40 b       bravo\r
41 ```\r
42 \r
43 See the file locale\en\characterDescriptions.dic for a full example.\r
44 \r
45 ++ Symbol Pronunciation ++\r
46 It is often useful to hear punctuation and other symbols pronounced as words when reading text, particularly when moving by character.\r
47 Unfortunately, the pronunciation of symbols is inconsistent between speech synthesisers and many synthesisers do not speak many symbols and/or do not allow control over what symbols are spoken.\r
48 Therefore, NVDA allows information about symbol pronunciation to be provided.\r
49 \r
50 This is done for a locale by providing a file named symbols.dic in the directory for the locale.\r
51 This is a UTF-8 encoded text file.\r
52 Blank lines and lines beginning with a "#" character are ignored.\r
53 All locales implicitly inherit the symbol information for English, though any of this information can be overridden.\r
54 \r
55 The file contains two sections.\r
56 \r
57 +++ Defining Complex Symbols +++\r
58 The first section is optional and defines regular expression patterns for complex symbols.\r
59 Complex symbols are symbols which aren't simply a character or sequence of characters, but instead require a more complicated match.\r
60 An example is the full stop (.) sentence ending in English.\r
61 The "." is used for multiple purposes, so a more complicated check is required to determine whether this refers to the end of a sentence.\r
62 \r
63 The complex symbols section begins with the line:\r
64 ```\r
65 complexSymbols:\r
66 ```\r
67 \r
68 Subsequent lines contain a textual identifier used to identify the symbol, a tab and the regular expression pattern for that symbol.\r
69 For example:\r
70 ```\r
71 . sentence ending       (?<=[^\s.])\.(?=[\"')\s]|$)\r
72 ```\r
73 \r
74 Again, the English symbols are inherited by all other locales, so you need not include any complex symbols already defined for English.\r
75 \r
76 +++ Defining Symbol Information +++\r
77 The second section provides information about when and how to pronounce all symbols.\r
78 It begins with the line:\r
79 ```\r
80 symbols:\r
81 ```\r
82 \r
83 Subsequent lines should contain several fields separated by tabs.\r
84 The only mandatory fields are the identifier and replacement.\r
85 The default will be used for omitted fields.\r
86 The fields are as follows:\r
87 - identifier: The identifier of the symbol.\r
88 In most cases, this is just the character or characters of the symbol.\r
89 However, it can also be the identifier of a complex symbol.\r
90 Certain characters cannot be typed into the file, so the following special sequences can be used:\r
91  - \0: null\r
92  - \t: tab\r
93  - \n: line feed\r
94  - \r: carriage return\r
95  - \f: form feed\r
96  - \#: # character (needed because # at the start of a line denotes a comment)\r
97 - replacement: The text which should be spoken for the symbol.\r
98 - level: The symbol level at which the symbol should be spoken.\r
99 The symbol level is configured by the user and specifies the amount of symbols that should be spoken.\r
100 This field should contain one of the levels "none", "some", "most", "all" or "char", or "-" to use the default.\r
101 "char" means that the symbol should only be pronounced when moving by character.\r
102 The default is to inherit the value or "all" if there is nothing to inherit.\r
103 - preserve: Whether the symbol itself should be preserved to facilitate correct pronunciation by the synthesiser.\r
104 For example, symbols which cause pauses or inflection (such as the comma in English) should be preserved.\r
105 This field should be one of the following:\r
106  - never: Never preserve the symbol.\r
107  - always: Always preserve the symbol.\r
108  - norep: Only preserve the symbol if it is not being replaced; i.e. the user has set symbol level lower than the level of this symbol.\r
109  - -: Use the default.\r
110  -\r
111 The default is to inherit the value or "never" if there is nothing to inherit.\r
112 -\r
113 Finally, a display name for the symbol can be provided in a comment after a tab at the end of the line.\r
114 This will be shown to users when editing the symbol information and is especially useful for translators to define translated names for English complex symbols.\r
115 \r
116 Here are some examples:\r
117 ```\r
118 (       left paren      most\r
119 ```\r
120 This means that the "(" character should be spoken as "left paren" only when the symbol level is set to most or higher; i.e. most or all.\r
121 ```\r
122 ,       comma   all     always\r
123 ```\r
124 This means that the "," character should be spoken as "comma" when the symbol level is set to all and that the character itself should always be preserved so that the synthesiser will pause appropriately.\r
125 ```\r
126 . sentence ending       point   # . fin de phrase\r
127 ```\r
128 This line appears in the French symbols.dic file.\r
129 It means that the ". sentence ending" complex symbol should be spoken as "point".\r
130 Level and preserve are not specified, so they will be taken from English.\r
131 A display name is provided so that French users will know what the symbol represents.\r
132 \r
133 Please see the file locale\en\symbols.dic for the English definitions which are inherited for all locales.\r
134 This is also a good full example.\r
135 \r
136 + Plugins +\r
137 \r
138 ++ Overview ++\r
139 Plugins allow you to customize the way NVDA behaves overall or within a particular application.\r
140 They are able to:\r
141 - Respond to particular events such as focus and object property changes; e.g. when a control changes its name.\r
142 - Implement commands which are bound to particular key presses or other input.\r
143 - Customise the behaviour of and implement additional functionality for particular controls.\r
144 - Customise or add new support for text content and complex documents.\r
145 -\r
146 \r
147 This section provides an introduction to developing plugins.\r
148 Developers should consult the code documentation for a complete reference.\r
149 \r
150 ++ Types of Plugins ++\r
151 There are two types of plugins. These are:\r
152 - App Modules: code specific to a particular application.\r
153 The App Module receives all events for a particular application, even if that application is not currently active.\r
154 When the application is active, any commands that the App Module has bound to key presses or other input can be executed by the user.\r
155 - Global Plugins: code global to NVDA; i.e. it is used in all applications.\r
156 Global Plugins Receive all events for all controls in the Operating System.\r
157 Any commands bound by a Global Plugin can be executed by the user wherever they are in the operating system, regardless of application.\r
158 -\r
159 \r
160 If you wish to improve NVDA's access to a particular application, it is most likely you will want to write an App Module.\r
161 In contrast, if you wish to add some overall functionality to NVDA (e.g. a script that announces current Wireless network strength while in any application), then a Global Plugin is what you want.\r
162 \r
163 Both App Modules and Global Plugins share a common look and feel.\r
164 They are both Python source files (with a .py extension), they both define a special class containing all events, scripts and bindings, and they both may define custom classes to access controls, text content and complex documents.\r
165 However, they do differ in some ways.\r
166 \r
167 The following few sections will talk separately about App Modules and Global Plugins.\r
168 After this point, discussion is again more general.\r
169 \r
170 ++ Basics of an App Module ++\r
171 App Module files have a .py extension, and are named the same as the main executable of the application for which you wish them to be used.\r
172 For example, an App Module for notepad would be called notepad.py, as notepad's main executable is called notepad.exe.\r
173 \r
174 App Module files must be placed in the appModules subdirectory of the user's NVDA user configuration directory.\r
175 For more information on where to find the user configuration directory, please see the NVDA user guide.\r
176 \r
177 App Modules must define a class called AppModule, which inherits from appModuleHandler.AppModule.\r
178 This class can then define event and script methods, gesture bindings and other code.\r
179 This will all be covered in depth later.\r
180 \r
181 NVDA loads an App Module for an application as soon as it notices the application is running.\r
182 The App Module is unloaded once the application is closed or when NVDA is exiting.\r
183 \r
184 ++ Example 1: An App Module that Beeps on Focus Change Events ++[Example1]\r
185 The following example App Module makes NVDA beep each time the focus changes within the notepad application.\r
186 This example shows you the basic layout of an App Module.\r
187 \r
188 Copy and paste the code between (but not including) the start and end markers into a new text file called notepad.py, which should be saved in the AppModules subdirectory.\r
189 Be very careful to keep all tabs and spaces intact.\r
190 \r
191 Once saved in the correct location, either restart NVDA or choose Reload Plugins found under Tools in the NVDA menu.\r
192 \r
193 Finally, open Notepad and move the focus around the application; e.g. move along the menu bar, open some dialog boxes, etc.\r
194 You should hear beeps each time the focus changes.\r
195 Note though that if you move outside of Notepad - for instance, to Windows Explorer - you do not hear beeps.\r
196 \r
197 ```\r
198 --- start ---\r
199 # Notepad App Module for NVDA\r
200 # Developer guide example 1\r
201 \r
202 import appModuleHandler\r
203 \r
204 class AppModule(appModuleHandler.AppModule):\r
205 \r
206         def event_gainFocus(self, obj, nextHandler):\r
207                 import tones\r
208                 tones.beep(550, 50)\r
209                 nextHandler()\r
210 \r
211 --- end ---\r
212 ```\r
213 \r
214 This App Module file starts with two comment lines, which describe what the file is for.\r
215 \r
216 It then imports the appModuleHandler module, so that the App Module then has access to the base AppModule class.\r
217 \r
218 Next, it defines a class called AppModule, which is inherited from appModuleHandler.AppModule.\r
219 \r
220 Inside this class, it defines 1 or more events, scripts or gesture bindings.\r
221 In this example, it defines one event method for gainFocus events (event_gainFocus), which plays a short beep each time it is executed.\r
222 The implementation of this event is not important for the purposes of this example.\r
223 The most important part is the class itself.\r
224 Events will be covered in greater detail later.\r
225 \r
226 As with other examples in this guide, remember to delete the created app module when you are finished testing and then restart NVDA or reload plugins, so that original functionality is restored.\r
227 \r
228 ++ Basics of a Global Plugin ++\r
229 Global Plugin files have a .py extension, and should have a short unique name which identifies what they do.\r
230 \r
231 Global Plugin files must be placed in the globalPlugins subdirectory of the user's NVDA user configuration directory.\r
232 For more information on where to find the user configuration directory, please see the NVDA user guide.\r
233 \r
234 Global Plugins must define a class called GlobalPlugin, which inherits from globalPluginHandler.GlobalPlugin.\r
235 This class can then define event and script methods, gesture bindings and other code.\r
236 This will all be covered in depth later.\r
237 \r
238 NVDA loads all global plugins as soon as it starts, and unloads them on exit.\r
239 \r
240 ++ Example 2: a Global Plugin Providing a Script to Announce the NVDA Version ++\r
241 The following example Global Plugin Allows you to press NVDA+shift+v while anywhere in the Operating System to find out NVDA's version.\r
242 This example is only to show you the basic layout of a Global Plugin.\r
243 \r
244 Copy and paste the code between (but not including) the start and end markers into a new text file with a name of example2.py, which should be saved in the globalPlugins subdirectory.\r
245 Be very careful to keep all tabs and spaces intact.\r
246 \r
247 Once saved in the right place, either restart NVDA or choose Reload Plugins found under Tools in the NVDA menu.\r
248 \r
249 From anywhere, you can now press NVDA+shift+v to have NVDA's version spoken and brailled.\r
250 \r
251 ```\r
252 --- start ---\r
253 # Version announcement plugin for NVDA\r
254 # Developer guide example 2\r
255 \r
256 import globalPluginHandler\r
257 import ui\r
258 import versionInfo\r
259 \r
260 class GlobalPlugin(globalPluginHandler.GlobalPlugin):\r
261 \r
262         def script_announceNVDAVersion(self, gesture):\r
263                 ui.message(versionInfo.version)\r
264 \r
265         __gestures={\r
266                 "kb:NVDA+shift+v": "announceNVDAVersion",\r
267         }\r
268 \r
269 --- end ---\r
270 ```\r
271 \r
272 This Global Plugin file starts with two comment lines, which describe what the file is for.\r
273 \r
274 It then imports the globalPluginHandler module, so that the Global Plugin has access to the base GlobalPlugin class.\r
275 \r
276 It also imports a few other modules, namely ui and versionInfo, which this specific plugin needs in order for it to perform the necessary actions to announce the version.\r
277 \r
278 Next, it defines a class called GlobalPlugin, which is inherited from globalPluginHandler.GlobalPlugin.\r
279 \r
280 Inside this class, it defines 1 or more events, scripts or gesture bindings.\r
281 In this example, it defines a script method that performs the version announcement, and provides a binding from NVDA+shift+v to this script.\r
282 However, the details of the script and its binding are not important for the purposes of this example.\r
283 The most important part is the class itself.\r
284 \r
285 As with other examples in this guide, remember to delete the created Global Plugin when finished testing and then restart NVDA or reload plugins, so that original functionality is restored.\r
286 \r
287 ++ NVDA Objects ++\r
288 NVDA represents controls and other GUI elements as NVDA Objects.\r
289 These NVDA Objects contain standardised properties, such as name, role, value, states and description, which allow other parts of NVDA to query or present information about a control in a generalised way.\r
290 For example, the OK button in a dialog would be represented as an NVDA Object with a name of "OK" and a role of button.\r
291 Similarly, a checkbox with a label of "I agree" would have a name of "I agree", a role of checkbox, and if currently checked, a state of checked.\r
292 \r
293 As there are many different GUI Toolkits and platform and accessibility APIs, NVDA Objects abstract these differences into a standard form that NVDA can use, regardless of the toolkit or API a particular control is made with.\r
294 For example, the Ok button just discussed could be a widget in a Java application, an MSAA object, an IAccessible2 object or a UI Automation element.\r
295 \r
296 NVDA Objects have many properties.\r
297 Some of the most useful are:\r
298 - name: the label of the control.\r
299 - role: one of the ROLE_* constants from NVDA's controlTypes module.\r
300 Button, dialog, editableText, window and checkbox are examples of roles.\r
301 - states: a set of 0 or more of the STATE_* constants from NVDA's controlTypes module.\r
302 Focusable, focused, selected, selectable, expanded, collapsed and checked are some examples of states.\r
303 - value: the value of the control; e.g. the percentage of a scroll bar or the current setting of a combo box.\r
304 - description: a sentence or two describing what the control does (usually the same as its tooltip).\r
305 - location: the object's left, top, width and height positions in screen coordinates.\r
306 - parent: this object's parent object.\r
307 For example, a list item object's parent would be the list containing it.\r
308 - next: the object directly after this one on the same level in logical order.\r
309 For example, a menu item NVDA Object's next object is most likely another menu item within the same menu.\r
310 - previous: like next but in reverse.\r
311 - firstChild: the first direct child object of this object.\r
312 For example, a list's first child would be the first list item.\r
313 - lastChild: the last direct child of this object.\r
314 - children: a list of all the direct children of this object; e.g. all the menu items in a menu.\r
315 -\r
316 \r
317 There are also a few simplified navigation properties such as simpleParent, simpleNext, simpleFirstChild and simpleLastChild.\r
318 These are like their respective navigation properties described above, but NVDA filters out unuseful objects.\r
319 These properties are used when NVDA's simple review mode is turned on, which is the default.\r
320 These simple properties may be easier to use, but the real navigation properties more closely reflect the underlying Operating System structure.\r
321 \r
322 When developing plugins, most of the time, it is not important what toolkit or API backs an NVDA Object, as the plugin will usually only access standard properties such as name, role and value.\r
323 However, as plugins become more advanced, it is certainly possible to delve deeper into NVDA Objects to find out toolkit or API specific information if required.\r
324 \r
325 Plugins make use of NVDA Objects in three particular ways:\r
326 - Most events that plugins receive take an argument which is the NVDA Object on which the event occurred.\r
327 For example, event_gainFocus takes the NVDA Object that represents the control gaining focus.\r
328 - Scripts, events or other code may fetch objects of interest such as the NVDA Object with focus, NVDA's current navigator object, or perhaps the Desktop NVDA Object.\r
329 The code may then retreave information from that object or perhaps even retreave another object related to it (e.g. its parent, first child, etc.).\r
330 - the Plugin may define its own custom NVDA Object classes which will be used to wrap a specific control to give it extra functionality, mutate its properties, etc.\r
331 -\r
332 \r
333 Just like App Modules and Global Plugins, NVDA Objects can also define events, scripts and gesture bindings.\r
334 \r
335 ++ Scripts and Gesture Bindings ++\r
336 App Modules, Global Plugins and NVDA Objects can define special methods which can be bound to a particular piece of input such as a key press.\r
337 NVDA refers to these methods as scripts.\r
338 \r
339 A script is a standard Python instance method with a name starting with "script_"; e.g. "script_sayDateTime".\r
340 \r
341 A script method takes two arguments:\r
342 - self: a reference to the App Module, Global Plugin or NVDA Object instance the script was called on.\r
343 - gesture: an Input Gesture object, which represents the input that caused the script to run.\r
344 -\r
345 \r
346 As well as the actual script method, some form of gesture binding must be defined, so that NVDA knows what input should execute the script.\r
347 \r
348 To bind a gesture to a script, a special "__gestures" Python dictionary can be defined as a class variable on the App Module, Global Plugin or NVDA Object.\r
349 These dictionaries should contain gesture identifier strings pointing to the name of the requested script, without the "script_" prefix.\r
350 \r
351 There are more advanced ways of binding gestures in a more dynamic fashion, though the __gestures dictionary is the simplest.\r
352 \r
353 A gesture identifier string is a simple string representation of a piece of input.\r
354 It consists of a two leter character code denoting the source of the input, an optional device in brackets, a colon (:) and one or more names separated by a plus (+) denoting the actual keys or input values.\r
355 \r
356 Some examples of gesture string identifiers are:\r
357 - "kb:NVDA+shift+v"\r
358 - "br(freedomScientific):leftWizWheelUp"\r
359 - "kb(laptop):NVDA+t"\r
360 -\r
361 \r
362 Currently, the only input sources in NVDA are:\r
363 - kb: keyboard input\r
364 - br: braille input\r
365 -\r
366 \r
367 When NVDA receives input, it looks for a matching gesture binding in a particular order.\r
368 Once a gesture binding is found, the script is executed and no further bindings are used, nore is that particular gesture passed on automatically to the Operating System.\r
369 \r
370 The order for gesture binding lookup is:\r
371 - Loaded Global Plugins\r
372 - App Module of the active application\r
373 - Tree Interceptor of the NVDA Object with focus if any; e.g. a virtualBuffer\r
374 - NVDA Object with focus\r
375 - Global Commands (built in commands like quitting NVDA, object navigation commands, etc.)\r
376 -\r
377 \r
378 ++ Example 3: A Global Plugin to Find out Window Class and Control ID ++\r
379 The following Global Plugin allows you to press NVDA+leftArrow to have the window class of the current focus announced, and NVDA+rightArrow to have the window control ID of the current focus announced.\r
380 This example shows you how to define one or more scripts and gesture bindings on a class such as an App Module, Global Plugin or NVDA Object.\r
381 \r
382 Copy and paste the code between (but not including) the start and end markers into a new text file with a name of example3.py, which should be saved in the globalPlugins subdirectory.\r
383 Be very careful to keep all tabs and spaces intact.\r
384 \r
385 Once saved in the right place, either restart NVDA or choose Reload Plugins found under Tools in the NVDA menu.\r
386 \r
387 ```\r
388 --- start ---\r
389 #Window utility scripts for NVDA\r
390 #Developer guide example 3\r
391 \r
392 import globalPluginHandler\r
393 import ui\r
394 import api\r
395 \r
396 class GlobalPlugin(globalPluginHandler.GlobalPlugin):\r
397 \r
398         def script_announceWindowClassName(self, gesture):\r
399                 focusObj = api.getFocusObject()\r
400                 name = focusObj.name\r
401                 windowClassName = focusObj.windowClassName\r
402                 ui.message("class for %s window: %s" % (name, windowClassName))\r
403 \r
404         def script_announceWindowControlID(self, gesture):\r
405                 focusObj = api.getFocusObject()\r
406                 name = focusObj.name\r
407                 windowControlID = focusObj.windowControlID\r
408                 ui.message("Control ID for %s window: %d" % (name, windowControlID))\r
409 \r
410         __gestures = {\r
411                 "kb:NVDA+leftArrow": "announceWindowClassName",\r
412                 "kb:NVDA+rightArrow": "announceWindowControlID",\r
413         }\r
414 \r
415 --- end ---\r
416 ```\r
417 \r
418 ++ Events ++\r
419 When NVDA detects particular toolkit, API or Operating System events, it abstracts these and fires its own internal events on plugins and NVDA Objects.\r
420 \r
421 Although most events are related to a specific NVDA Object (e.g. name change, gain focus, state change, etc.), these events can be handled at various levels.\r
422 When an event is handled, it is stopped from going further down the chain.\r
423 However, code inside the event can choose to propagate it further if needed.\r
424 \r
425 The order of levels through which the event passes until an event method is found is:\r
426 - Loaded Global Plugins\r
427 - The App Module associated with the NVDA Object on which the event was fired\r
428 - The Tree Interceptor (if any) associated with the NVDAObject on which the event was fired\r
429 - the NVDAObject itself.\r
430 -\r
431 \r
432 Events are Python instance methods, with a name starting with "event_" followed by the actual name of the event (e.g. gainFocus).\r
433 \r
434 These event methods take slightly different arguments depending at what level they are defined.\r
435 \r
436 If an event for an NVDA Object is defined on an NVDA Object itself, the method only takes one mandatory argument which is the 'self' argument; i.e. the NVDA Object instance).\r
437 Some events may take extra arguments, though this is quite rare.\r
438 \r
439 If an event for an NVDA Object is defined on a Global Plugin, App Module or Tree Interceptor, the event takes the following arguments:\r
440 - self: the instance of the Global Plugin, App Module or Tree Interceptor\r
441 - obj: the NVDA Object on which the event was fired\r
442 - nextHandler: a function that when called will propagate the event further down the chain.\r
443 -\r
444 \r
445 Some common NVDA Object events are:\r
446 - foreground: this NVDA Object has become the new foreground object; i.e. active top-level object\r
447 - gainFocus\r
448 - loseFocus\r
449 - nameChange\r
450 - valueChange\r
451 - stateChange\r
452 - caret: when the caret (insertion point) within this NVDA Object moves\r
453 - locationChange: physical screen location changes\r
454 -\r
455 \r
456 There are many other events, though those listed above are usually the most useful.\r
457 \r
458 For an example of an event handled by an App Module, please refer to [example 1 #Example1] (focus beeps in notepad).\r
459 \r
460 ++ the App Module SleepMode variable ++\r
461 App Modules have one very useful property called "sleepMode", which if set to true almost completely disables NVDA within that application.\r
462 Sleep Mode is very useful for self voicing applications that have their own screen reading functionality, or perhaps even some games that need full use of the keyboard.\r
463 \r
464 Although sleep mode can be toggled on and off by the user with the key command NVDA+shift+s, a developer can choose to have sleep mode enabled by default for an application.\r
465 This is done by providing an App Module for that application which simply sets sleepMode to True in the AppModule class.\r
466 \r
467 ++ Example 4: A Sleep Mode App Module ++\r
468 \r
469 The following code can be copied and pasted in to a text file, then saved in the appModules directory with the name of the application you wish to enable sleep mode for.\r
470 As always, the file must have a .py extension.\r
471 \r
472 ```\r
473 --- start ---\r
474 import appModuleHandler\r
475 \r
476 class AppModule(appModuleHandler.AppModule):\r
477 \r
478         sleepMode = True\r
479 \r
480 --- end ---\r
481 ```\r
482 \r
483 ++ Providing Custom NVDA Object Classes ++\r
484 Providing custom NVDA Object classes is probably the most powerful and useful way to improve the experience of an application in an NVDA plugin.\r
485 This method allows you to place all the needed logic for a particular control altogether in one NVDA Object class for that control, rather than scattering code for many controls across a plugin's events.\r
486 \r
487 There are two steps to providing a custom NVDA Object class:\r
488 - Define the NVDA Object class and its events, scripts, gesture bindings and overridden properties.\r
489 - Tell NVDA to use this NVDA Object class in specific situations by handling it in the plugin's chooseNVDAObjectOverlayClasses method.\r
490 -\r
491 \r
492 When defining a custom NVDAObject class, you have many NVDAObject base classes to choose from.\r
493 These base classes contain the base support for the particular accessibility or OS API underlying the control, such as win32, MSAA or Java access Bridge.\r
494 You should usually inherit your custom NVDAObject class from the highest base class you need in order to choose your class in the first place.\r
495 For example, if you choose to use your custom NVDAObject class when the window class name is "Edit" and the window control ID is 15, you should probably inherit from NVDAObjects.window.Window, as clearly you are aware that this is a Window object.\r
496 Similarly, if you match on MSAA's accRole property, you would probably need to inherit from NVDAObjects.IAccessible.IAccessible.\r
497 You should also consider what properties you are going to override on the custom NVDA Object.\r
498 For instance, if you are going to override an IAccessible specific property, such as shouldAllowIAccessibleFocusEvent, then you need to inherit from NVDAObjects.IAccessible.IAccessible.\r
499 \r
500 the chooseNVDAObjectOverlayClasses method can be implemented on app modules or global plugin classes.\r
501 It takes 3 arguments:\r
502 + self: the app module or global plugin instance.\r
503 + obj: the NVDAObject for which classes are being chosen.\r
504 + clsList: a Python list of NVDAObject classes that will be used for obj.\r
505 +\r
506 \r
507 Inside this method, you should decide which custom NVDA Object class(es) (if any) this NVDA Object should use by checking its properties, etc.\r
508 If a custom class should be used, it must be inserted into the class list, usually at the beginning.\r
509 You can also remove classes chosen by NVDA from the class list, although this is rarely required.\r
510 \r
511 ++ Example 5: Command to Retrieve the Length of Text in an Edit Field Using a Custom NVDA Object ++\r
512 This app module for notepad provides a command to report the number of characters in edit fields.\r
513 You can activate it using NVDA+l.\r
514 Notice that the command is specific to edit fields; i.e. it only works while you are focused in an edit field, rather than anywhere in the application.\r
515 \r
516 The following code can be copied and pasted in to a text file, then saved in the appModules directory with the name of notepad.py.\r
517 \r
518 ```\r
519 --- start ---\r
520 import appModuleHandler\r
521 from NVDAObjects.IAccessible import IAccessible\r
522 import controlTypes\r
523 import ui\r
524 \r
525 class AppModule(appModuleHandler.AppModule):\r
526 \r
527         def chooseNVDAObjectOverlayClasses(self, obj, clsList):\r
528                 if obj.windowClassName == "Edit" and obj.role == controlTypes.ROLE_EDITABLETEXT:\r
529                         clsList.insert(0, EnhancedEditField)\r
530 \r
531 class EnhancedEditField(IAccessible):\r
532 \r
533         def script_reportLength(self, gesture):\r
534                 ui.message("%d" % len(self.value))\r
535 \r
536         __gestures = {\r
537                 "kb:NVDA+l": "reportLength",\r
538         }\r
539 \r
540 --- end ---\r
541 ```\r
542 \r
543 ++ Making Small Changes to an NVDA Object in App Modules ++\r
544 Sometimes, you may wish to make only small changes to an NVDA Object in an application, such as overriding its name or role.\r
545 In these cases, you don't need the full power of a custom NVDA Object class.\r
546 To do this, you can use the NVDAObject_init event available only on App Modules.\r
547 \r
548 The event_NVDAObject_init method takes two arguments:\r
549 + self: the AppModule instance.\r
550 + obj: the NVDAObject being initialized.\r
551 +\r
552 \r
553 Inside this method, you can check whether this object is relevant and then override properties accordingly.\r
554 \r
555 ++ Example 6: Labelling the Notepad Edit Field Using event_NVDAObject_init ++\r
556 This app module for notepad makes NVDA report Notepad's main edit field as having a name of "content".\r
557 That is, when it receives focus, NVDA will say "Content edit".\r
558 \r
559 The following code can be copied and pasted in to a text file, then saved in the appModules directory with the name of notepad.py.\r
560 \r
561 ```\r
562 --- start ---\r
563 import appModuleHandler\r
564 from NVDAObjects.window import Window\r
565 \r
566 class AppModule(appModuleHandler.AppModule):\r
567 \r
568         def event_NVDAObject_init(self, obj):\r
569                 if isinstance(obj, Window) and obj.windowClassName == "Edit" and obj.windowControlID == 15:\r
570                         obj.name = "Content"\r
571 --- end ---\r
572 ```\r
573 \r
574 + Packaging  Code as  NVDA Add-ons +\r
575 To make it easy for users to share and install plugins and drivers, they can be packaged in to a single NVDA add-on package which the user can then install into a copy of NVDA via the Add-ons Manager found under Tools in the NVDA menu.\r
576 Add-on packages are only supported in NVDA 2012.2 and later.\r
577 An add-on package is simply a standard zip archive with the file extension of nvda-addon which contains a manifest file,  optional  install/uninstall code and  one or more  directories containing plugins and/or drivers.\r
578 \r
579 ++ Non-ASCII File Names in Zip Archives ++\r
580 If your add-on includes files which contain non-ASCII (non-English) characters, you should create the zip archive such that it uses UTF-8 file names.\r
581 This means that these files can be extracted properly on all systems, regardless of the system's configured language.\r
582 Unfortunately, many zip archivers do not support this, including Windows Explorer.\r
583 Generally, it has to be explicitly enabled even in archivers that do support it.\r
584 [http://www.7-zip.org/ 7-Zip] supports this, though it must be enabled by specifying the "cu=on" method parameter.\r
585 \r
586 ++ Manifest Files ++\r
587 Each add-on package must contain a manifest file named manifest.ini.\r
588 This must be a UTF-8 encoded text file.\r
589 This manifest file contains key = value pares declaring info such as the add-on's name, version and description.\r
590 \r
591 +++ Available Fields +++\r
592 Although it is highly suggested that manifests contain all fields, the fields marked as mandatory must be included.\r
593 Otherwise, the add-on will not install.  \r
594 - name: A short unique name for the add-on. This is used to differentiate add-ons internally and is not shown to the user. (Mandatory)\r
595 - summary: The name of the add-on as shown to the user. (Mandatory)\r
596 - version: The version of this add-on; e.g. 2.0. (Mandatory)\r
597 - author: The author of this add-on, preferably in the form Full Name <email address>; e.g. Michael Curran <mick@kulgan.net>. (Mandatory)\r
598 - description: A sentence or two describing what the add-on does.\r
599 - url: A URL where this add-on, further info and upgrades can be found.\r
600 -\r
601 \r
602 +++ An Example Manifest File +++\r
603 ```\r
604 --- start ---\r
605 name = MyTestAddon\r
606 summary = Cool Test Add-on\r
607 version = 1.0\r
608 description = An example add-on showing how to create add-ons!\r
609 author = Michael Curran <mick@kulgan.net>\r
610 url = http://www.nvda-project.org/wiki/Development\r
611 --- end ---\r
612 ``` \r
613 \r
614 ++ Plugins and Drivers ++\r
615 The following plugins and drivers can be included in an add-on:\r
616 - App modules: Place them in an appModules directory in the archive.\r
617 - Braille display drivers: Place them in a brailleDisplayDrivers directory in the archive.\r
618 - Global plugins: Place them in a globalPlugins directory in the archive.\r
619 - Synthesizer drivers: Place them in a synthDrivers directory in the archive.\r
620 -\r
621 \r
622 ++ Optional install / Uninstall code ++\r
623 If you need to execute code as your add-on is being installed or uninstalled from NVDA (e.g. to validate license information or to copy files to a custom location), you can provide a Python   file called installTasks.py in the archive which contains special functions that NVDA will call while installing or uninstalling your add-on.\r
624 This file should avoid loading any modules that are not absolutely necessary,  especially   Python C extensions or dlls from your own add-on, as this could cause later removal of the add-on to fail.\r
625 However, if this does happen, the add-on directory will be renamed and then   deleted after the next restart of NVDA. \r
626 Finally, it should not depend on the existence or state of other add-ons, as they may not be installed, have already been removed or not yet be initialized.\r
627 \r
628 +++ the onInstall function +++\r
629 NVDA will look for and execute an onInstall function in installTasks.py after it has finished extracting the add-on into NVDA.\r
630 Note that although the add-on will have been extracted at this time, its directory will have a .pendingInstall suffix until NVDA is restarted, the directory is renamed and the add-on is really loaded for the first time.\r
631 If this function raises an exception, the installation of the add-on will fail and its directory will be cleaned up.\r
632 \r
633 +++ The onUninstall Function +++\r
634 NVDA will look for and execute an onUninstall function in installTasks.py when NVDA is restarted after the user has chosen to remove the add-on.\r
635 After this function completes, the add-on's directory will automatically be removed.\r
636 As this happens on NVDA startup before other components are initialized, this function cannot request input from the user.\r
637 \r
638 ++ Localizing Add-ons ++\r
639 It is possible to provide locale-specific information and messages for your add-on.\r
640 Locale information can be stored in a locale directory in the archive.\r
641 This directory should contain directories for each language it supports, using the same language code format as the rest of NVDA; e.g. en for English, fr_CA for French Canadian.\r
642 \r
643 +++ Locale-specific Manifest Files +++\r
644 Each of these language directories can contain a locale-specific manifest file called manifest.ini, which can contain a small subset of the manifest fields for translation.\r
645 These fields are summary and description.\r
646 All other fields will be ignored.\r
647 \r
648 +++ Locale-specific Messages +++\r
649 Each language directory can also contain gettext information, which is the system used to translate the rest of NVDA's user interface and reported messages.\r
650 As with the rest of NVDA, an nvda.mo compiled gettext database file should be placed in the LC_MESSAGES directory within this directory.\r
651 to allow plugins in your add-on to access gettext message information via calls to _(), you must initialize  translations at the top of each Python module by calling addonHandler.initTranslation().\r
652 For more information about gettext and NVDA translation in general, please read\r
653 http://www.nvda-project.org/wiki/TranslatingNVDA\r
654 \r
655 + NVDA Python Console +[PythonConsole]\r
656 The NVDA Python console emulates the interactive Python interpreter from within NVDA.\r
657 It is a development tool which is useful for debugging, general inspection of NVDA internals or inspection of the accessibility hierarchy of an application.\r
658 \r
659 ++ Usage ++\r
660 The console can be activated in two ways:\r
661 - By pressing NVDA+control+z.\r
662 If activated in this fashion, a snapshot of the current state of NVDA at the time the key was pressed will be taken and saved in certain variables available in the console.\r
663 See [Snapshot Variables #PythonConsoleSnapshotVariables] for more details.\r
664 - By selecting Tools -> Python console from the NVDA system tray menu.\r
665 -\r
666 \r
667 The console is similar to the standard interactive Python interpreter.\r
668 Input is accepted one line at a time.\r
669 The current line is processed when enter is pressed.\r
670 You can navigate through the history of previously entered lines using the up and down arrow keys.\r
671 \r
672 Output (responses from the interpreter) will be spoken when enter is pressed.\r
673 The f6 key toggles between the input and output controls.\r
674 \r
675 Closing the console window simply hides it.\r
676 This allows the user to return to the session as it was left when it was closed, including history and variables.\r
677 \r
678 ++ Namespace ++[PythonConsoleNamespace]\r
679 \r
680 +++ Automatic Imports +++\r
681 For convenience, the following modules and variables are automatically imported in the console:\r
682 sys, os, wx, log (from logHandler), api, queueHandler, speech, braille\r
683 \r
684 +++ Snapshot Variables +++[PythonConsoleSnapshotVariables]\r
685 Whenever NVDA+control+z is pressed, certain variables available in the console will be assigned according to the current state of NVDA.\r
686 These variables are:\r
687 - focus: The current focus object\r
688 - focusAnc: The ancestors of the current focus object\r
689 - fdl: Focus difference level; i.e. the level at which the ancestors for the current and previous focus differ\r
690 - fg: The current foreground object\r
691 - nav: The current navigator object\r
692 - mouse: The current mouse object\r
693 - brlRegions: The braille regions from the active braille buffer\r
694 -\r
695 \r
696 + Remote Python Console +\r
697 A remote Python console is available for situations where remote debugging of NVDA is useful.\r
698 It is similar to the [local Python console #PythonConsole] discussed above, but is accessed via TCP.\r
699 \r
700 Please be aware that this is a huge security risk.\r
701 You should only enable it if you are connected to trusted networks.\r
702 \r
703 ++ Usage ++\r
704 To enable the remote Python console, use the local Python console to import remotePythonConsole and call remotePythonConsole.initialize().\r
705 You can then connect to it via TCP port 6832.\r
706 \r
707 History of previously entered lines is not supported.\r
708 \r
709 The namespace is the same as [the namespace in the local Python console #PythonConsoleNamespace].\r
710 \r
711 There are some special functions:\r
712 - snap(): Takes a snapshot of the current state of NVDA and saves it in the [snapshot variables #PythonConsoleSnapshotVariables].\r
713 - rmSnap(): Removes all snapshot variables.\r
714 -\r