Dear all, My name is Bhavya Shah, and I am an undergraduate studying Mathematical and Computational Science and am currently working my way through the incredible add-ons development guide. My hope is to, in the near future, be able to meaningfully contribute code either to NVDA core or add-ons. Since I may have multiple questions coming up at irregular intervals, I thought it would be better to initiate a unified thread to house them all rather than spammily starting new ones for each query. My first set of questions is under. With respect to "Example 2: Generate a tone when switching to Notepad" whose code is pasted below for convenient access: import appModuleHandler import tones class AppModule(appModuleHandler.AppModule): def event_gainFocus(self, obj, nextHandler): tones.beep(256, 200) nextHandler() * Could you please explain the parameters for a general event method? * Here, it looks like self refers to the current class - what does that mean practically? * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep? I would be deeply, deeply grateful for your guidance and mentorship. I look forward to learning loads and contributing thereafter. Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
|
|
Hi Bhavya, The example you gave ultimately came from NVDA's own development guide, which became the basis for the add-on dev guide. To answer the first set of questions: First, regarding event handler method parameters: generally, there are two event handler method signatures: # From the plugin class level: def event_eventName(self, obj, nextHandler) # At the NVDA object level: def event_eventName(self)
Parameters: * self: the instance of the class itself (plugin class or an NVDA object class). * obj: NVDA object that fired the event in question. * nextHandler: a callable that will handle the given event at the next level.
In NVDA, event handling goes through the following steps: 1. An object (UIA element, MSAA object, JAB object, etc.) fires an event, and accessibility API's notifies NVDA of this fact. 2. After the events are filtered (such as not responding to duplicate events), a chain of generators is called. This chain, called event executor, calls event handlers defined in global plugins, app modules, tree interceptors, and NVDA objects, in that order. 3. The event handler at the global plugin, app module, or tree interceptor level can "cut" the event execution chain by NOT calling nextHandler() function defined as the event handler parameter. To put it differently, calling nextHandler() (a generator) causes NVDA to move down the event execution chain. Note that event handling and chaining is described in NVDA's event handler source code module (eventHandler.py). As for add-on development practice, I'm about to announce something that might be of use for you. Cheers, Joseph
toggle quoted message
Show quoted text
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 5:49 PM To: nvda-addons <nvda-addons@nvda-addons.groups.io> Subject: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide Dear all, My name is Bhavya Shah, and I am an undergraduate studying Mathematical and Computational Science and am currently working my way through the incredible add-ons development guide. My hope is to, in the near future, be able to meaningfully contribute code either to NVDA core or add-ons. Since I may have multiple questions coming up at irregular intervals, I thought it would be better to initiate a unified thread to house them all rather than spammily starting new ones for each query. My first set of questions is under. With respect to "Example 2: Generate a tone when switching to Notepad" whose code is pasted below for convenient access: import appModuleHandler import tones class AppModule(appModuleHandler.AppModule): def event_gainFocus(self, obj, nextHandler): tones.beep(256, 200) nextHandler() * Could you please explain the parameters for a general event method? * Here, it looks like self refers to the current class - what does that mean practically? * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep? I would be deeply, deeply grateful for your guidance and mentorship. I look forward to learning loads and contributing thereafter. Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
|
|
Dear all,
With respect to "Example 1: am I on the right app where the focus is located?" whose code is pasted below for convenient access: import api def sameApp(obj=None): if obj is None: obj = api.getNavigatorObject() return api.getFocusObject().appModule == obj.appModule
* I take it that obj=None assigns the value None to the variable obj as part of the function definition. Is it common to assign the value of a parameter during the function definition itself? It seems slightly odd to me at first glance. * I don't follow why we check if obj is None right after it was assigned that value by us, but I am probably missing something. What is the purpose of that conditional? * There is an explanatory sentence in this section: "Each NVDA object includes appModule member which records on which app an object is located." Where can I learn more about the NVDA object? Is it a module, class, method, or something else? What methods and/or members does an NVDA object have access to?
Thanks.
toggle quoted message
Show quoted text
On 1/9/22, Bhavya shah <bhavya.shah125@...> wrote: Dear all,
My name is Bhavya Shah, and I am an undergraduate studying Mathematical and Computational Science and am currently working my way through the incredible add-ons development guide. My hope is to, in the near future, be able to meaningfully contribute code either to NVDA core or add-ons. Since I may have multiple questions coming up at irregular intervals, I thought it would be better to initiate a unified thread to house them all rather than spammily starting new ones for each query. My first set of questions is under. With respect to "Example 2: Generate a tone when switching to Notepad" whose code is pasted below for convenient access: import appModuleHandler import tones class AppModule(appModuleHandler.AppModule): def event_gainFocus(self, obj, nextHandler): tones.beep(256, 200) nextHandler() * Could you please explain the parameters for a general event method? * Here, it looks like self refers to the current class - what does that mean practically? * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep?
I would be deeply, deeply grateful for your guidance and mentorship. I look forward to learning loads and contributing thereafter.
Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
|
|
Dear Joseph,
Thank you so much for the detailed and informative response! Based on my understanding of your explanation, if I were to go back to my questions, I have understood the following: * Could you please explain the parameters for a general event method? Response: The two event method signatures you noted. * Here, it looks like self refers to the current class - what does that mean practically? Response: Self is just an instance of the class we began to define. It doesn't mean anything unusual, but is what we will keep using to define methods for that class of things. * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? Response: obj refers to the NVDA object that fired the event in question. But in the example's code, how did we identify when we landed on an object inside Notepad in the first place? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep? Response: Your (Joseph's) explanation of event handling sheds a lot of light on how nextHandler works especially in the bigger picture. Just to confirm then, is nextHandler provided by Python or part of one of the NVDA moduels we imported?
Thanks.
toggle quoted message
Show quoted text
On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote: Hi Bhavya, The example you gave ultimately came from NVDA's own development guide, which became the basis for the add-on dev guide. To answer the first set of questions: First, regarding event handler method parameters: generally, there are two event handler method signatures: # From the plugin class level: def event_eventName(self, obj, nextHandler) # At the NVDA object level: def event_eventName(self)
Parameters: * self: the instance of the class itself (plugin class or an NVDA object class). * obj: NVDA object that fired the event in question. * nextHandler: a callable that will handle the given event at the next level.
In NVDA, event handling goes through the following steps: 1. An object (UIA element, MSAA object, JAB object, etc.) fires an event, and accessibility API's notifies NVDA of this fact. 2. After the events are filtered (such as not responding to duplicate events), a chain of generators is called. This chain, called event executor, calls event handlers defined in global plugins, app modules, tree interceptors, and NVDA objects, in that order. 3. The event handler at the global plugin, app module, or tree interceptor level can "cut" the event execution chain by NOT calling nextHandler() function defined as the event handler parameter. To put it differently, calling nextHandler() (a generator) causes NVDA to move down the event execution chain. Note that event handling and chaining is described in NVDA's event handler source code module (eventHandler.py). As for add-on development practice, I'm about to announce something that might be of use for you. Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 5:49 PM To: nvda-addons <nvda-addons@nvda-addons.groups.io> Subject: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear all,
My name is Bhavya Shah, and I am an undergraduate studying Mathematical and Computational Science and am currently working my way through the incredible add-ons development guide. My hope is to, in the near future, be able to meaningfully contribute code either to NVDA core or add-ons. Since I may have multiple questions coming up at irregular intervals, I thought it would be better to initiate a unified thread to house them all rather than spammily starting new ones for each query. My first set of questions is under. With respect to "Example 2: Generate a tone when switching to Notepad" whose code is pasted below for convenient access: import appModuleHandler import tones class AppModule(appModuleHandler.AppModule): def event_gainFocus(self, obj, nextHandler): tones.beep(256, 200) nextHandler() * Could you please explain the parameters for a general event method? * Here, it looks like self refers to the current class - what does that mean practically? * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep?
I would be deeply, deeply grateful for your guidance and mentorship. I look forward to learning loads and contributing thereafter.
Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
|
|
Hi, In regards to how we know that NVDA object came from Notepad app: this is because of the fact that event handler is defined for an app module, which becomes active as long as the given app is in use (focused). So when writing app modules, you can assume that the NVDA object that fired the event is NVDA's representation of a control from the app in question, which in this case, can be anything from Notepad. Regarding where next handler come from: it is not defined in Python, but rather it is a convention used to identify the next event handler chain. Think of it as a tagged function pointer (hope I'm using the term correctly) - as far as Python is concerned, functions are internally seen as pointers to addresses, and you can name that "address" whatever you like. To go a bit into computer science way of thinking about this (WARNING: will get really geeky here), computers don't care about how things are named as long as they can access whatever they are told to read from specific locations. To explain: Computer memory is a collection of integers known as "memory addresses" (or "addresses" for short). Each address, in turn, consists of bits, with eight bits making a byte (at the hardware level, they are really boxes filled with transistors; you won't learn about how that is possible until you take computer engineering or electrical engineering courses). When a computer is powered on, memory is "empty" - they are not really set to zero's, but are random things but computers treat it as "empty". (or rather, not filled with recognizable things). When a program loads and wants to do something with variables, the central processing unit (CPU) performs a complicated operation that ultimately results in reading something from a memory location. This involves: 1. The processor reads the instruction to read the value of a variable. 2. The processor first locates the location of the variable within the program's working memory set (the amount of memory the program/process is occupying at that moment). 3. Since the variable "points" to the memory location of whatever it points to, a special component of the processor, called memory management unit (MMU) looks up the actual memory address the variable points to. 4. Once the memory location is fetched, the processor returns whatever value the "variable" references (points to). This is why computer scientists and programmers sometimes call variables "pointers", as variables are really tagged memory locations as far as the operating system and the computer hardware is concerned. Although different programming languages use different strategies internally, generally when folks talk about variable names, they are really talking about the memory location the variable points to. Therefore, when we talk about Python variables, it is better to say "the variable references this memory location that contains a specific thing" rather than "something is assigned to a variable". But that's at the advanced level - for convenience, when people teach introductory programming, instructors say "something is assigned to a variable". Building on this, it is perfectly possible to "rename" a variable; after all, a variable is a tag for a memory location, so all you are doing is changing the "outside tag" without changing the memory location the tag points to (or references). This is the reason why we can name the event chaining function anything, but for convenience, we call this "nextHandler" - ultimately, what Python will look at is the address of the function tagged "nextHandler". Hope this helps - I understand what I described above is quite a geeky explanation, but since you are studying computer science, I felt it is time to introduce you to the actual internals of computer science (math and computer science go hand in hand because computer science began as a branch of mathematics; although Alan Turing and John von Neumann popularized computer science in the 20th century, the foundations were laid centuries earlier). Cheers, Joseph
toggle quoted message
Show quoted text
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 6:44 PM To: nvda-addons@nvda-addons.groups.io Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide Dear Joseph, Thank you so much for the detailed and informative response! Based on my understanding of your explanation, if I were to go back to my questions, I have understood the following: * Could you please explain the parameters for a general event method? Response: The two event method signatures you noted. * Here, it looks like self refers to the current class - what does that mean practically? Response: Self is just an instance of the class we began to define. It doesn't mean anything unusual, but is what we will keep using to define methods for that class of things. * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? Response: obj refers to the NVDA object that fired the event in question. But in the example's code, how did we identify when we landed on an object inside Notepad in the first place? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep? Response: Your (Joseph's) explanation of event handling sheds a lot of light on how nextHandler works especially in the bigger picture. Just to confirm then, is nextHandler provided by Python or part of one of the NVDA moduels we imported? Thanks. On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote: Hi Bhavya, The example you gave ultimately came from NVDA's own development guide, which became the basis for the add-on dev guide. To answer the first set of questions: First, regarding event handler method parameters: generally, there are two event handler method signatures: # From the plugin class level: def event_eventName(self, obj, nextHandler) # At the NVDA object level: def event_eventName(self)
Parameters: * self: the instance of the class itself (plugin class or an NVDA object class). * obj: NVDA object that fired the event in question. * nextHandler: a callable that will handle the given event at the next level.
In NVDA, event handling goes through the following steps: 1. An object (UIA element, MSAA object, JAB object, etc.) fires an event, and accessibility API's notifies NVDA of this fact. 2. After the events are filtered (such as not responding to duplicate events), a chain of generators is called. This chain, called event executor, calls event handlers defined in global plugins, app modules, tree interceptors, and NVDA objects, in that order. 3. The event handler at the global plugin, app module, or tree interceptor level can "cut" the event execution chain by NOT calling nextHandler() function defined as the event handler parameter. To put it differently, calling nextHandler() (a generator) causes NVDA to move down the event execution chain. Note that event handling and chaining is described in NVDA's event handler source code module (eventHandler.py). As for add-on development practice, I'm about to announce something that might be of use for you. Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 5:49 PM To: nvda-addons <nvda-addons@nvda-addons.groups.io> Subject: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear all,
My name is Bhavya Shah, and I am an undergraduate studying Mathematical and Computational Science and am currently working my way through the incredible add-ons development guide. My hope is to, in the near future, be able to meaningfully contribute code either to NVDA core or add-ons. Since I may have multiple questions coming up at irregular intervals, I thought it would be better to initiate a unified thread to house them all rather than spammily starting new ones for each query. My first set of questions is under. With respect to "Example 2: Generate a tone when switching to Notepad" whose code is pasted below for convenient access: import appModuleHandler import tones class AppModule(appModuleHandler.AppModule): def event_gainFocus(self, obj, nextHandler): tones.beep(256, 200) nextHandler() * Could you please explain the parameters for a general event method? * Here, it looks like self refers to the current class - what does that mean practically? * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep?
I would be deeply, deeply grateful for your guidance and mentorship. I look forward to learning loads and contributing thereafter.
Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
|
|
Hi Bhavya, Ah, these are really good questions - reminds me of a day (many years ago) when I learned about algorithms... To answer the third question first: NVDA objects are housed inside NVDAObjects folder inside nVDA's source code folder (source/NvDAObjects). As far as runtime is concerned (when NVDA Runs), an NVDA object is an instance of NvDAObjects.NVDAObject abstract class. Because abstract classes only gives us a blueprint, we often deal with concrete NVDA objects such as API classes from IAccessible, UIA, and others. As for the other two questions, they go hand in hand sometimes, but to explain: Suppose you need to travel from home to campus. You know that you need to walk several blocks, and that takes this amount of minutes. Now suppose that you need to go somewhere on campus. Questions: * How long will that take? * What are your assumptions as you walk from home to somewhere on campus? The above scenario describes keyword arguments - functions can take in keyword parameters that effectively tells Python that it should use whatever thing that was passed into the parameter if nothing else comes in. For example, suppose that it takes five minutes to walk from home to campus. Then: * Without keywords (positional parameters): def walkFromHomeToCampus(durationInMinutes) * With keyword parameters: def walkFromHomeToCampus(durationInMinutes=5) In the first case, you MUST tell the walk function how long it takes to walk from home to campus. With keyword parameters, when duration is not specified, you can assume that it takes five minutes to walk from home to campus. A special situation arises when you must check something against None (NULL in some languages), which is a way of saying, "this variable points to nowhere or to a possibly invalid location". The function fragment: def something(obj=None): if obj is None: # Do something when obj points to nowhere (None)
Without this, you may get the following traceback that ends with: AttributeError: obj has no attribute "someAttribute" So for example, suppose you want to look at obj.appModule. Without checking for None, when trying to access obj.appModule, you may get an attribute error exception if obj happens to point to nowhere (technically, it points to a None object when var = None). Hope this helps. Cheers, Joseph
toggle quoted message
Show quoted text
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 6:24 PM To: nvda-addons <nvda-addons@nvda-addons.groups.io> Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide Dear all, With respect to "Example 1: am I on the right app where the focus is located?" whose code is pasted below for convenient access: import api def sameApp(obj=None): if obj is None: obj = api.getNavigatorObject() return api.getFocusObject().appModule == obj.appModule * I take it that obj=None assigns the value None to the variable obj as part of the function definition. Is it common to assign the value of a parameter during the function definition itself? It seems slightly odd to me at first glance. * I don't follow why we check if obj is None right after it was assigned that value by us, but I am probably missing something. What is the purpose of that conditional? * There is an explanatory sentence in this section: "Each NVDA object includes appModule member which records on which app an object is located." Where can I learn more about the NVDA object? Is it a module, class, method, or something else? What methods and/or members does an NVDA object have access to? Thanks. On 1/9/22, Bhavya shah <bhavya.shah125@...> wrote: Dear all,
My name is Bhavya Shah, and I am an undergraduate studying Mathematical and Computational Science and am currently working my way through the incredible add-ons development guide. My hope is to, in the near future, be able to meaningfully contribute code either to NVDA core or add-ons. Since I may have multiple questions coming up at irregular intervals, I thought it would be better to initiate a unified thread to house them all rather than spammily starting new ones for each query. My first set of questions is under. With respect to "Example 2: Generate a tone when switching to Notepad" whose code is pasted below for convenient access: import appModuleHandler import tones class AppModule(appModuleHandler.AppModule): def event_gainFocus(self, obj, nextHandler): tones.beep(256, 200) nextHandler() * Could you please explain the parameters for a general event method? * Here, it looks like self refers to the current class - what does that mean practically? * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep?
I would be deeply, deeply grateful for your guidance and mentorship. I look forward to learning loads and contributing thereafter.
Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
|
|
Dear Joseph,
Much appreciated again! The exposition about what variables really are and do was quite illuminating. I am taking a systems class this quarter, so will be dealing with pointers much more extensively there. I think I have one final question on the Notepad example then. * What did we do in the code to produce the beep only when we first entered Notepad as opposed to all of the time we spent doing things (and thus firing events) in Notepad? I suspect nextHandler is to thank, but I thought nextHandler was only to allow for the *current* event to continue to be handled and would not affect any subsequent events.
Thanks.
toggle quoted message
Show quoted text
On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote: Hi, In regards to how we know that NVDA object came from Notepad app: this is because of the fact that event handler is defined for an app module, which becomes active as long as the given app is in use (focused). So when writing app modules, you can assume that the NVDA object that fired the event is NVDA's representation of a control from the app in question, which in this case, can be anything from Notepad. Regarding where next handler come from: it is not defined in Python, but rather it is a convention used to identify the next event handler chain. Think of it as a tagged function pointer (hope I'm using the term correctly) - as far as Python is concerned, functions are internally seen as pointers to addresses, and you can name that "address" whatever you like. To go a bit into computer science way of thinking about this (WARNING: will get really geeky here), computers don't care about how things are named as long as they can access whatever they are told to read from specific locations. To explain: Computer memory is a collection of integers known as "memory addresses" (or "addresses" for short). Each address, in turn, consists of bits, with eight bits making a byte (at the hardware level, they are really boxes filled with transistors; you won't learn about how that is possible until you take computer engineering or electrical engineering courses). When a computer is powered on, memory is "empty" - they are not really set to zero's, but are random things but computers treat it as "empty". (or rather, not filled with recognizable things). When a program loads and wants to do something with variables, the central processing unit (CPU) performs a complicated operation that ultimately results in reading something from a memory location. This involves: 1. The processor reads the instruction to read the value of a variable. 2. The processor first locates the location of the variable within the program's working memory set (the amount of memory the program/process is occupying at that moment). 3. Since the variable "points" to the memory location of whatever it points to, a special component of the processor, called memory management unit (MMU) looks up the actual memory address the variable points to. 4. Once the memory location is fetched, the processor returns whatever value the "variable" references (points to). This is why computer scientists and programmers sometimes call variables "pointers", as variables are really tagged memory locations as far as the operating system and the computer hardware is concerned. Although different programming languages use different strategies internally, generally when folks talk about variable names, they are really talking about the memory location the variable points to. Therefore, when we talk about Python variables, it is better to say "the variable references this memory location that contains a specific thing" rather than "something is assigned to a variable". But that's at the advanced level - for convenience, when people teach introductory programming, instructors say "something is assigned to a variable". Building on this, it is perfectly possible to "rename" a variable; after all, a variable is a tag for a memory location, so all you are doing is changing the "outside tag" without changing the memory location the tag points to (or references). This is the reason why we can name the event chaining function anything, but for convenience, we call this "nextHandler" - ultimately, what Python will look at is the address of the function tagged "nextHandler". Hope this helps - I understand what I described above is quite a geeky explanation, but since you are studying computer science, I felt it is time to introduce you to the actual internals of computer science (math and computer science go hand in hand because computer science began as a branch of mathematics; although Alan Turing and John von Neumann popularized computer science in the 20th century, the foundations were laid centuries earlier). Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 6:44 PM To: nvda-addons@nvda-addons.groups.io Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear Joseph,
Thank you so much for the detailed and informative response! Based on my understanding of your explanation, if I were to go back to my questions, I have understood the following: * Could you please explain the parameters for a general event method? Response: The two event method signatures you noted. * Here, it looks like self refers to the current class - what does that mean practically? Response: Self is just an instance of the class we began to define. It doesn't mean anything unusual, but is what we will keep using to define methods for that class of things. * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? Response: obj refers to the NVDA object that fired the event in question. But in the example's code, how did we identify when we landed on an object inside Notepad in the first place? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep? Response: Your (Joseph's) explanation of event handling sheds a lot of light on how nextHandler works especially in the bigger picture. Just to confirm then, is nextHandler provided by Python or part of one of the NVDA moduels we imported?
Thanks.
On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote:
Hi Bhavya, The example you gave ultimately came from NVDA's own development guide, which became the basis for the add-on dev guide. To answer the first set of questions: First, regarding event handler method parameters: generally, there are two event handler method signatures: # From the plugin class level: def event_eventName(self, obj, nextHandler) # At the NVDA object level: def event_eventName(self)
Parameters: * self: the instance of the class itself (plugin class or an NVDA object class). * obj: NVDA object that fired the event in question. * nextHandler: a callable that will handle the given event at the next level.
In NVDA, event handling goes through the following steps: 1. An object (UIA element, MSAA object, JAB object, etc.) fires an event, and accessibility API's notifies NVDA of this fact. 2. After the events are filtered (such as not responding to duplicate events), a chain of generators is called. This chain, called event executor, calls event handlers defined in global plugins, app modules, tree interceptors, and NVDA objects, in that order. 3. The event handler at the global plugin, app module, or tree interceptor level can "cut" the event execution chain by NOT calling nextHandler() function defined as the event handler parameter. To put it differently, calling nextHandler() (a generator) causes NVDA to move down the event execution chain. Note that event handling and chaining is described in NVDA's event handler source code module (eventHandler.py). As for add-on development practice, I'm about to announce something that might be of use for you. Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 5:49 PM To: nvda-addons <nvda-addons@nvda-addons.groups.io> Subject: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear all,
My name is Bhavya Shah, and I am an undergraduate studying Mathematical and Computational Science and am currently working my way through the incredible add-ons development guide. My hope is to, in the near future, be able to meaningfully contribute code either to NVDA core or add-ons. Since I may have multiple questions coming up at irregular intervals, I thought it would be better to initiate a unified thread to house them all rather than spammily starting new ones for each query. My first set of questions is under. With respect to "Example 2: Generate a tone when switching to Notepad" whose code is pasted below for convenient access: import appModuleHandler import tones class AppModule(appModuleHandler.AppModule): def event_gainFocus(self, obj, nextHandler): tones.beep(256, 200) nextHandler() * Could you please explain the parameters for a general event method? * Here, it looks like self refers to the current class - what does that mean practically? * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep?
I would be deeply, deeply grateful for your guidance and mentorship. I look forward to learning loads and contributing thereafter.
Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
|
|
Dear Joseph,
Perfect - nearly everything makes complete sense (and thanks for the helpful analogy)! Just two remarks: * I went into C drive>Program Files (x86)>NVDA and was unable to find a folder called "Source" or "Source Code." Where might I find this folder so as to then access the NVDA Objects folder? * I don't fully understand what an API class from IAccessible looks like at present. I think I have a high-level guess, and should revisit this later when I am exploring the api module.
Thanks.
toggle quoted message
Show quoted text
On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote: Hi Bhavya, Ah, these are really good questions - reminds me of a day (many years ago) when I learned about algorithms... To answer the third question first: NVDA objects are housed inside NVDAObjects folder inside nVDA's source code folder (source/NvDAObjects). As far as runtime is concerned (when NVDA Runs), an NVDA object is an instance of NvDAObjects.NVDAObject abstract class. Because abstract classes only gives us a blueprint, we often deal with concrete NVDA objects such as API classes from IAccessible, UIA, and others. As for the other two questions, they go hand in hand sometimes, but to explain: Suppose you need to travel from home to campus. You know that you need to walk several blocks, and that takes this amount of minutes. Now suppose that you need to go somewhere on campus. Questions: * How long will that take? * What are your assumptions as you walk from home to somewhere on campus? The above scenario describes keyword arguments - functions can take in keyword parameters that effectively tells Python that it should use whatever thing that was passed into the parameter if nothing else comes in. For example, suppose that it takes five minutes to walk from home to campus. Then: * Without keywords (positional parameters): def walkFromHomeToCampus(durationInMinutes) * With keyword parameters: def walkFromHomeToCampus(durationInMinutes=5) In the first case, you MUST tell the walk function how long it takes to walk from home to campus. With keyword parameters, when duration is not specified, you can assume that it takes five minutes to walk from home to campus. A special situation arises when you must check something against None (NULL in some languages), which is a way of saying, "this variable points to nowhere or to a possibly invalid location". The function fragment: def something(obj=None): if obj is None: # Do something when obj points to nowhere (None)
Without this, you may get the following traceback that ends with: AttributeError: obj has no attribute "someAttribute" So for example, suppose you want to look at obj.appModule. Without checking for None, when trying to access obj.appModule, you may get an attribute error exception if obj happens to point to nowhere (technically, it points to a None object when var = None). Hope this helps. Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 6:24 PM To: nvda-addons <nvda-addons@nvda-addons.groups.io> Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear all,
With respect to "Example 1: am I on the right app where the focus is located?" whose code is pasted below for convenient access: import api def sameApp(obj=None): if obj is None: obj = api.getNavigatorObject() return api.getFocusObject().appModule == obj.appModule
* I take it that obj=None assigns the value None to the variable obj as part of the function definition. Is it common to assign the value of a parameter during the function definition itself? It seems slightly odd to me at first glance. * I don't follow why we check if obj is None right after it was assigned that value by us, but I am probably missing something. What is the purpose of that conditional? * There is an explanatory sentence in this section: "Each NVDA object includes appModule member which records on which app an object is located." Where can I learn more about the NVDA object? Is it a module, class, method, or something else? What methods and/or members does an NVDA object have access to?
Thanks.
On 1/9/22, Bhavya shah <bhavya.shah125@...> wrote:
Dear all,
My name is Bhavya Shah, and I am an undergraduate studying Mathematical and Computational Science and am currently working my way through the incredible add-ons development guide. My hope is to, in the near future, be able to meaningfully contribute code either to NVDA core or add-ons. Since I may have multiple questions coming up at irregular intervals, I thought it would be better to initiate a unified thread to house them all rather than spammily starting new ones for each query. My first set of questions is under. With respect to "Example 2: Generate a tone when switching to Notepad" whose code is pasted below for convenient access: import appModuleHandler import tones class AppModule(appModuleHandler.AppModule): def event_gainFocus(self, obj, nextHandler): tones.beep(256, 200) nextHandler() * Could you please explain the parameters for a general event method? * Here, it looks like self refers to the current class - what does that mean practically? * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep?
I would be deeply, deeply grateful for your guidance and mentorship. I look forward to learning loads and contributing thereafter.
Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
|
|
Hi, This depends on which event we wish to listen to (after all, GUI programs rely on what's called an "event loop" to respond to things happening on screen). Gain focus event is fired whenever system focus moves to a new object on screen. This is prominent in Notepad when we switch to it from other programs. Looking at which events are fired by which objects will require observing and debugging accessible events, and one such tool is AccEvent from Windows SDK (and it is one of the reasons for writing Event Tracker add-on so this process can be done easily). Cheers, Joseph
toggle quoted message
Show quoted text
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 10:06 PM To: nvda-addons@nvda-addons.groups.io Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide Dear Joseph, Much appreciated again! The exposition about what variables really are and do was quite illuminating. I am taking a systems class this quarter, so will be dealing with pointers much more extensively there. I think I have one final question on the Notepad example then. * What did we do in the code to produce the beep only when we first entered Notepad as opposed to all of the time we spent doing things (and thus firing events) in Notepad? I suspect nextHandler is to thank, but I thought nextHandler was only to allow for the *current* event to continue to be handled and would not affect any subsequent events. Thanks. On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote: Hi, In regards to how we know that NVDA object came from Notepad app: this is because of the fact that event handler is defined for an app module, which becomes active as long as the given app is in use (focused). So when writing app modules, you can assume that the NVDA object that fired the event is NVDA's representation of a control from the app in question, which in this case, can be anything from Notepad. Regarding where next handler come from: it is not defined in Python, but rather it is a convention used to identify the next event handler chain. Think of it as a tagged function pointer (hope I'm using the term correctly) - as far as Python is concerned, functions are internally seen as pointers to addresses, and you can name that "address" whatever you like. To go a bit into computer science way of thinking about this (WARNING: will get really geeky here), computers don't care about how things are named as long as they can access whatever they are told to read from specific locations. To explain: Computer memory is a collection of integers known as "memory addresses" (or "addresses" for short). Each address, in turn, consists of bits, with eight bits making a byte (at the hardware level, they are really boxes filled with transistors; you won't learn about how that is possible until you take computer engineering or electrical engineering courses). When a computer is powered on, memory is "empty" - they are not really set to zero's, but are random things but computers treat it as "empty". (or rather, not filled with recognizable things). When a program loads and wants to do something with variables, the central processing unit (CPU) performs a complicated operation that ultimately results in reading something from a memory location. This involves: 1. The processor reads the instruction to read the value of a variable. 2. The processor first locates the location of the variable within the program's working memory set (the amount of memory the program/process is occupying at that moment). 3. Since the variable "points" to the memory location of whatever it points to, a special component of the processor, called memory management unit (MMU) looks up the actual memory address the variable points to. 4. Once the memory location is fetched, the processor returns whatever value the "variable" references (points to). This is why computer scientists and programmers sometimes call variables "pointers", as variables are really tagged memory locations as far as the operating system and the computer hardware is concerned. Although different programming languages use different strategies internally, generally when folks talk about variable names, they are really talking about the memory location the variable points to. Therefore, when we talk about Python variables, it is better to say "the variable references this memory location that contains a specific thing" rather than "something is assigned to a variable". But that's at the advanced level - for convenience, when people teach introductory programming, instructors say "something is assigned to a variable". Building on this, it is perfectly possible to "rename" a variable; after all, a variable is a tag for a memory location, so all you are doing is changing the "outside tag" without changing the memory location the tag points to (or references). This is the reason why we can name the event chaining function anything, but for convenience, we call this "nextHandler" - ultimately, what Python will look at is the address of the function tagged "nextHandler". Hope this helps - I understand what I described above is quite a geeky explanation, but since you are studying computer science, I felt it is time to introduce you to the actual internals of computer science (math and computer science go hand in hand because computer science began as a branch of mathematics; although Alan Turing and John von Neumann popularized computer science in the 20th century, the foundations were laid centuries earlier). Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 6:44 PM To: nvda-addons@nvda-addons.groups.io Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear Joseph,
Thank you so much for the detailed and informative response! Based on my understanding of your explanation, if I were to go back to my questions, I have understood the following: * Could you please explain the parameters for a general event method? Response: The two event method signatures you noted. * Here, it looks like self refers to the current class - what does that mean practically? Response: Self is just an instance of the class we began to define. It doesn't mean anything unusual, but is what we will keep using to define methods for that class of things. * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? Response: obj refers to the NVDA object that fired the event in question. But in the example's code, how did we identify when we landed on an object inside Notepad in the first place? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep? Response: Your (Joseph's) explanation of event handling sheds a lot of light on how nextHandler works especially in the bigger picture. Just to confirm then, is nextHandler provided by Python or part of one of the NVDA moduels we imported?
Thanks.
On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote:
Hi Bhavya, The example you gave ultimately came from NVDA's own development guide, which became the basis for the add-on dev guide. To answer the first set of questions: First, regarding event handler method parameters: generally, there are two event handler method signatures: # From the plugin class level: def event_eventName(self, obj, nextHandler) # At the NVDA object level: def event_eventName(self)
Parameters: * self: the instance of the class itself (plugin class or an NVDA object class). * obj: NVDA object that fired the event in question. * nextHandler: a callable that will handle the given event at the next level.
In NVDA, event handling goes through the following steps: 1. An object (UIA element, MSAA object, JAB object, etc.) fires an event, and accessibility API's notifies NVDA of this fact. 2. After the events are filtered (such as not responding to duplicate events), a chain of generators is called. This chain, called event executor, calls event handlers defined in global plugins, app modules, tree interceptors, and NVDA objects, in that order. 3. The event handler at the global plugin, app module, or tree interceptor level can "cut" the event execution chain by NOT calling nextHandler() function defined as the event handler parameter. To put it differently, calling nextHandler() (a generator) causes NVDA to move down the event execution chain. Note that event handling and chaining is described in NVDA's event handler source code module (eventHandler.py). As for add-on development practice, I'm about to announce something that might be of use for you. Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 5:49 PM To: nvda-addons <nvda-addons@nvda-addons.groups.io> Subject: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear all,
My name is Bhavya Shah, and I am an undergraduate studying Mathematical and Computational Science and am currently working my way through the incredible add-ons development guide. My hope is to, in the near future, be able to meaningfully contribute code either to NVDA core or add-ons. Since I may have multiple questions coming up at irregular intervals, I thought it would be better to initiate a unified thread to house them all rather than spammily starting new ones for each query. My first set of questions is under. With respect to "Example 2: Generate a tone when switching to Notepad" whose code is pasted below for convenient access: import appModuleHandler import tones class AppModule(appModuleHandler.AppModule): def event_gainFocus(self, obj, nextHandler): tones.beep(256, 200) nextHandler() * Could you please explain the parameters for a general event method? * Here, it looks like self refers to the current class - what does that mean practically? * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep?
I would be deeply, deeply grateful for your guidance and mentorship. I look forward to learning loads and contributing thereafter.
Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
|
|
Hi, To view NvDA objects folder in source code, you must clone NVDA source code (believe it or not). To do, you must install Git (Git for Windows, part of Windows Subsystem for Linux (WSL), etc.), then Git clone the following URL: https://github.com/nvaccess/nvdaFor best results, try cloning recursively. If using command line, do: 1. cd sourceFolderLocationWhereYouWantToStoreNVDASource 2. git clone --recursive https://github.com/nvaccess/nvdaYou can then build NVDA itself from source code (a requirement if you wish to send NVDA pull requests in the future). Sometimes it is helpful to have the NVDA source code handy if you want to learn the magic behind NVDA add-ons (although NVDA source code is not exactly a good case of software documentation, at least it is readable when trying to understand basics; to grasp the full power of NVDA, you must be familiar with both Python and C++; my point about documentation is the biggest reason for writing add-on dev guide, and the number one wish remains the same for the last five years or so: better source code documentation). Cheers, Joseph
toggle quoted message
Show quoted text
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 10:14 PM To: nvda-addons@nvda-addons.groups.io Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide Dear Joseph, Perfect - nearly everything makes complete sense (and thanks for the helpful analogy)! Just two remarks: * I went into C drive>Program Files (x86)>NVDA and was unable to find a folder called "Source" or "Source Code." Where might I find this folder so as to then access the NVDA Objects folder? * I don't fully understand what an API class from IAccessible looks like at present. I think I have a high-level guess, and should revisit this later when I am exploring the api module. Thanks. On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote: Hi Bhavya, Ah, these are really good questions - reminds me of a day (many years ago) when I learned about algorithms... To answer the third question first: NVDA objects are housed inside NVDAObjects folder inside nVDA's source code folder (source/NvDAObjects). As far as runtime is concerned (when NVDA Runs), an NVDA object is an instance of NvDAObjects.NVDAObject abstract class. Because abstract classes only gives us a blueprint, we often deal with concrete NVDA objects such as API classes from IAccessible, UIA, and others. As for the other two questions, they go hand in hand sometimes, but to explain: Suppose you need to travel from home to campus. You know that you need to walk several blocks, and that takes this amount of minutes. Now suppose that you need to go somewhere on campus. Questions: * How long will that take? * What are your assumptions as you walk from home to somewhere on campus? The above scenario describes keyword arguments - functions can take in keyword parameters that effectively tells Python that it should use whatever thing that was passed into the parameter if nothing else comes in. For example, suppose that it takes five minutes to walk from home to campus. Then: * Without keywords (positional parameters): def walkFromHomeToCampus(durationInMinutes) * With keyword parameters: def walkFromHomeToCampus(durationInMinutes=5) In the first case, you MUST tell the walk function how long it takes to walk from home to campus. With keyword parameters, when duration is not specified, you can assume that it takes five minutes to walk from home to campus. A special situation arises when you must check something against None (NULL in some languages), which is a way of saying, "this variable points to nowhere or to a possibly invalid location". The function fragment: def something(obj=None): if obj is None: # Do something when obj points to nowhere (None)
Without this, you may get the following traceback that ends with: AttributeError: obj has no attribute "someAttribute" So for example, suppose you want to look at obj.appModule. Without checking for None, when trying to access obj.appModule, you may get an attribute error exception if obj happens to point to nowhere (technically, it points to a None object when var = None). Hope this helps. Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 6:24 PM To: nvda-addons <nvda-addons@nvda-addons.groups.io> Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear all,
With respect to "Example 1: am I on the right app where the focus is located?" whose code is pasted below for convenient access: import api def sameApp(obj=None): if obj is None: obj = api.getNavigatorObject() return api.getFocusObject().appModule == obj.appModule
* I take it that obj=None assigns the value None to the variable obj as part of the function definition. Is it common to assign the value of a parameter during the function definition itself? It seems slightly odd to me at first glance. * I don't follow why we check if obj is None right after it was assigned that value by us, but I am probably missing something. What is the purpose of that conditional? * There is an explanatory sentence in this section: "Each NVDA object includes appModule member which records on which app an object is located." Where can I learn more about the NVDA object? Is it a module, class, method, or something else? What methods and/or members does an NVDA object have access to?
Thanks.
On 1/9/22, Bhavya shah <bhavya.shah125@...> wrote:
Dear all,
My name is Bhavya Shah, and I am an undergraduate studying Mathematical and Computational Science and am currently working my way through the incredible add-ons development guide. My hope is to, in the near future, be able to meaningfully contribute code either to NVDA core or add-ons. Since I may have multiple questions coming up at irregular intervals, I thought it would be better to initiate a unified thread to house them all rather than spammily starting new ones for each query. My first set of questions is under. With respect to "Example 2: Generate a tone when switching to Notepad" whose code is pasted below for convenient access: import appModuleHandler import tones class AppModule(appModuleHandler.AppModule): def event_gainFocus(self, obj, nextHandler): tones.beep(256, 200) nextHandler() * Could you please explain the parameters for a general event method? * Here, it looks like self refers to the current class - what does that mean practically? * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep?
I would be deeply, deeply grateful for your guidance and mentorship. I look forward to learning loads and contributing thereafter.
Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
|
|
Dear Joseph,
I just installed your Event Tracker add-on and look forward to using it as we go. In this case, you noted the gain focus event. My earlier understanding was that event_gainFocus was just a random name for a function wherein "event_" told Python that this method was an event method and "gainFocus" was only to make it clear for humans. I tested this hypothesis by modifying event_gainFocus to event_testing and the app module stopped working which tells me that the "gainFocus" bit is also significant for Python. I used to think function names only acted as placeholders but clearly that is not the case. I learnt something new.
Thanks.
toggle quoted message
Show quoted text
On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote: Hi, This depends on which event we wish to listen to (after all, GUI programs rely on what's called an "event loop" to respond to things happening on screen). Gain focus event is fired whenever system focus moves to a new object on screen. This is prominent in Notepad when we switch to it from other programs. Looking at which events are fired by which objects will require observing and debugging accessible events, and one such tool is AccEvent from Windows SDK (and it is one of the reasons for writing Event Tracker add-on so this process can be done easily). Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 10:06 PM To: nvda-addons@nvda-addons.groups.io Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear Joseph,
Much appreciated again! The exposition about what variables really are and do was quite illuminating. I am taking a systems class this quarter, so will be dealing with pointers much more extensively there. I think I have one final question on the Notepad example then. * What did we do in the code to produce the beep only when we first entered Notepad as opposed to all of the time we spent doing things (and thus firing events) in Notepad? I suspect nextHandler is to thank, but I thought nextHandler was only to allow for the *current* event to continue to be handled and would not affect any subsequent events.
Thanks.
On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote:
Hi, In regards to how we know that NVDA object came from Notepad app: this is because of the fact that event handler is defined for an app module, which becomes active as long as the given app is in use (focused). So when writing app modules, you can assume that the NVDA object that fired the event is NVDA's representation of a control from the app in question, which in this case, can be anything from Notepad. Regarding where next handler come from: it is not defined in Python, but rather it is a convention used to identify the next event handler chain. Think of it as a tagged function pointer (hope I'm using the term correctly) - as far as Python is concerned, functions are internally seen as pointers to addresses, and you can name that "address" whatever you like. To go a bit into computer science way of thinking about this (WARNING: will get really geeky here), computers don't care about how things are named as long as they can access whatever they are told to read from specific locations. To explain: Computer memory is a collection of integers known as "memory addresses" (or "addresses" for short). Each address, in turn, consists of bits, with eight bits making a byte (at the hardware level, they are really boxes filled with transistors; you won't learn about how that is possible until you take computer engineering or electrical engineering courses). When a computer is powered on, memory is "empty" - they are not really set to zero's, but are random things but computers treat it as "empty". (or rather, not filled with recognizable things). When a program loads and wants to do something with variables, the central processing unit (CPU) performs a complicated operation that ultimately results in reading something from a memory location. This involves: 1. The processor reads the instruction to read the value of a variable. 2. The processor first locates the location of the variable within the program's working memory set (the amount of memory the program/process is occupying at that moment). 3. Since the variable "points" to the memory location of whatever it points to, a special component of the processor, called memory management unit (MMU) looks up the actual memory address the variable points to. 4. Once the memory location is fetched, the processor returns whatever value the "variable" references (points to). This is why computer scientists and programmers sometimes call variables "pointers", as variables are really tagged memory locations as far as the operating system and the computer hardware is concerned. Although different programming languages use different strategies internally, generally when folks talk about variable names, they are really talking about the memory location the variable points to. Therefore, when we talk about Python variables, it is better to say "the variable references this memory location that contains a specific thing" rather than "something is assigned to a variable". But that's at the advanced level - for convenience, when people teach introductory programming, instructors say "something is assigned to a variable". Building on this, it is perfectly possible to "rename" a variable; after all, a variable is a tag for a memory location, so all you are doing is changing the "outside tag" without changing the memory location the tag points to (or references). This is the reason why we can name the event chaining function anything, but for convenience, we call this "nextHandler" - ultimately, what Python will look at is the address of the function tagged "nextHandler". Hope this helps - I understand what I described above is quite a geeky explanation, but since you are studying computer science, I felt it is time to introduce you to the actual internals of computer science (math and computer science go hand in hand because computer science began as a branch of mathematics; although Alan Turing and John von Neumann popularized computer science in the 20th century, the foundations were laid centuries earlier). Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 6:44 PM To: nvda-addons@nvda-addons.groups.io Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear Joseph,
Thank you so much for the detailed and informative response! Based on my understanding of your explanation, if I were to go back to my questions, I have understood the following: * Could you please explain the parameters for a general event method? Response: The two event method signatures you noted. * Here, it looks like self refers to the current class - what does that mean practically? Response: Self is just an instance of the class we began to define. It doesn't mean anything unusual, but is what we will keep using to define methods for that class of things. * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? Response: obj refers to the NVDA object that fired the event in question. But in the example's code, how did we identify when we landed on an object inside Notepad in the first place? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep? Response: Your (Joseph's) explanation of event handling sheds a lot of light on how nextHandler works especially in the bigger picture. Just to confirm then, is nextHandler provided by Python or part of one of the NVDA moduels we imported?
Thanks.
On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote:
Hi Bhavya, The example you gave ultimately came from NVDA's own development guide, which became the basis for the add-on dev guide. To answer the first set of questions: First, regarding event handler method parameters: generally, there are two event handler method signatures: # From the plugin class level: def event_eventName(self, obj, nextHandler) # At the NVDA object level: def event_eventName(self)
Parameters: * self: the instance of the class itself (plugin class or an NVDA object class). * obj: NVDA object that fired the event in question. * nextHandler: a callable that will handle the given event at the next level.
In NVDA, event handling goes through the following steps: 1. An object (UIA element, MSAA object, JAB object, etc.) fires an event, and accessibility API's notifies NVDA of this fact. 2. After the events are filtered (such as not responding to duplicate events), a chain of generators is called. This chain, called event executor, calls event handlers defined in global plugins, app modules, tree interceptors, and NVDA objects, in that order. 3. The event handler at the global plugin, app module, or tree interceptor level can "cut" the event execution chain by NOT calling nextHandler() function defined as the event handler parameter. To put it differently, calling nextHandler() (a generator) causes NVDA to move down the event execution chain. Note that event handling and chaining is described in NVDA's event handler source code module (eventHandler.py). As for add-on development practice, I'm about to announce something that might be of use for you. Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 5:49 PM To: nvda-addons <nvda-addons@nvda-addons.groups.io> Subject: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear all,
My name is Bhavya Shah, and I am an undergraduate studying Mathematical and Computational Science and am currently working my way through the incredible add-ons development guide. My hope is to, in the near future, be able to meaningfully contribute code either to NVDA core or add-ons. Since I may have multiple questions coming up at irregular intervals, I thought it would be better to initiate a unified thread to house them all rather than spammily starting new ones for each query. My first set of questions is under. With respect to "Example 2: Generate a tone when switching to Notepad" whose code is pasted below for convenient access: import appModuleHandler import tones class AppModule(appModuleHandler.AppModule): def event_gainFocus(self, obj, nextHandler): tones.beep(256, 200) nextHandler() * Could you please explain the parameters for a general event method? * Here, it looks like self refers to the current class - what does that mean practically? * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep?
I would be deeply, deeply grateful for your guidance and mentorship. I look forward to learning loads and contributing thereafter.
Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
|
|
Hi Bhavya, I have no problem with these types of questions being asked on the list, and I'm greatful to anyone who is able to provide helpful answers. I particularly think it was a good idea to create a thread for them, and ask people to not highjack it (e.g. by changing the subject line to talk about a different topic). Having said that, a number of your questions so far have not been related specifically to NVDA, although you weren't to know that when you asked them. Default function/method arguments, instance variables when using classes, passing functions/methods around as arguments, and the difference between function/method arguments and variable assignments. These are all general software development topics and, in many cases, would be better understood from a course and/or book about a programming language you're interested in learning. In this case, it seems to be Python. I don't believe the NVDA codebase to represent a particularly good resource for beginners, because of some of the more advanced techniques that it uses. Positive reinforcement is important, i.e. having some successes to validate your learning, and I speak from experience when I say that developing against NVDA can, at first and still at times, feel like bashing your head into a wall. Hope you take this in the spirit it is intended. Please do continue to ask, but it would be helpful: 1. for others, to sometimes answer in more abstract /non-NVDA-related ways, perhaps with links to good resources on a software development topic; and 2. for you, to find a good resource from which to learn object-oriented Python. In short, learn software development and Python, and use them to apply to NVDA, not the other way around. For the record, I originally learned Python from this book: https://learncodethehardway.org/python/Regards, James Scholes
toggle quoted message
Show quoted text
On 10/01/2022 at 9:09 am, Bhavya shah wrote: Dear Joseph,
I just installed your Event Tracker add-on and look forward to using it as we go. In this case, you noted the gain focus event. My earlier understanding was that event_gainFocus was just a random name for a function wherein "event_" told Python that this method was an event method and "gainFocus" was only to make it clear for humans. I tested this hypothesis by modifying event_gainFocus to event_testing and the app module stopped working which tells me that the "gainFocus" bit is also significant for Python. I used to think function names only acted as placeholders but clearly that is not the case. I learnt something new.
Thanks.
On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote:
Hi, This depends on which event we wish to listen to (after all, GUI programs rely on what's called an "event loop" to respond to things happening on screen). Gain focus event is fired whenever system focus moves to a new object on screen. This is prominent in Notepad when we switch to it from other programs. Looking at which events are fired by which objects will require observing and debugging accessible events, and one such tool is AccEvent from Windows SDK (and it is one of the reasons for writing Event Tracker add-on so this process can be done easily). Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 10:06 PM To: nvda-addons@nvda-addons.groups.io Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear Joseph,
Much appreciated again! The exposition about what variables really are and do was quite illuminating. I am taking a systems class this quarter, so will be dealing with pointers much more extensively there. I think I have one final question on the Notepad example then. * What did we do in the code to produce the beep only when we first entered Notepad as opposed to all of the time we spent doing things (and thus firing events) in Notepad? I suspect nextHandler is to thank, but I thought nextHandler was only to allow for the *current* event to continue to be handled and would not affect any subsequent events.
Thanks.
On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote:
Hi, In regards to how we know that NVDA object came from Notepad app: this is because of the fact that event handler is defined for an app module, which becomes active as long as the given app is in use (focused). So when writing app modules, you can assume that the NVDA object that fired the event is NVDA's representation of a control from the app in question, which in this case, can be anything from Notepad. Regarding where next handler come from: it is not defined in Python, but rather it is a convention used to identify the next event handler chain. Think of it as a tagged function pointer (hope I'm using the term correctly) - as far as Python is concerned, functions are internally seen as pointers to addresses, and you can name that "address" whatever you like. To go a bit into computer science way of thinking about this (WARNING: will get really geeky here), computers don't care about how things are named as long as they can access whatever they are told to read from specific locations. To explain: Computer memory is a collection of integers known as "memory addresses" (or "addresses" for short). Each address, in turn, consists of bits, with eight bits making a byte (at the hardware level, they are really boxes filled with transistors; you won't learn about how that is possible until you take computer engineering or electrical engineering courses). When a computer is powered on, memory is "empty" - they are not really set to zero's, but are random things but computers treat it as "empty". (or rather, not filled with recognizable things). When a program loads and wants to do something with variables, the central processing unit (CPU) performs a complicated operation that ultimately results in reading something from a memory location. This involves: 1. The processor reads the instruction to read the value of a variable. 2. The processor first locates the location of the variable within the program's working memory set (the amount of memory the program/process is occupying at that moment). 3. Since the variable "points" to the memory location of whatever it points to, a special component of the processor, called memory management unit (MMU) looks up the actual memory address the variable points to. 4. Once the memory location is fetched, the processor returns whatever value the "variable" references (points to). This is why computer scientists and programmers sometimes call variables "pointers", as variables are really tagged memory locations as far as the operating system and the computer hardware is concerned. Although different programming languages use different strategies internally, generally when folks talk about variable names, they are really talking about the memory location the variable points to. Therefore, when we talk about Python variables, it is better to say "the variable references this memory location that contains a specific thing" rather than "something is assigned to a variable". But that's at the advanced level - for convenience, when people teach introductory programming, instructors say "something is assigned to a variable". Building on this, it is perfectly possible to "rename" a variable; after all, a variable is a tag for a memory location, so all you are doing is changing the "outside tag" without changing the memory location the tag points to (or references). This is the reason why we can name the event chaining function anything, but for convenience, we call this "nextHandler" - ultimately, what Python will look at is the address of the function tagged "nextHandler". Hope this helps - I understand what I described above is quite a geeky explanation, but since you are studying computer science, I felt it is time to introduce you to the actual internals of computer science (math and computer science go hand in hand because computer science began as a branch of mathematics; although Alan Turing and John von Neumann popularized computer science in the 20th century, the foundations were laid centuries earlier). Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 6:44 PM To: nvda-addons@nvda-addons.groups.io Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear Joseph,
Thank you so much for the detailed and informative response! Based on my understanding of your explanation, if I were to go back to my questions, I have understood the following: * Could you please explain the parameters for a general event method? Response: The two event method signatures you noted. * Here, it looks like self refers to the current class - what does that mean practically? Response: Self is just an instance of the class we began to define. It doesn't mean anything unusual, but is what we will keep using to define methods for that class of things. * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? Response: obj refers to the NVDA object that fired the event in question. But in the example's code, how did we identify when we landed on an object inside Notepad in the first place? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep? Response: Your (Joseph's) explanation of event handling sheds a lot of light on how nextHandler works especially in the bigger picture. Just to confirm then, is nextHandler provided by Python or part of one of the NVDA moduels we imported?
Thanks.
On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote:
Hi Bhavya, The example you gave ultimately came from NVDA's own development guide, which became the basis for the add-on dev guide. To answer the first set of questions: First, regarding event handler method parameters: generally, there are two event handler method signatures: # From the plugin class level: def event_eventName(self, obj, nextHandler) # At the NVDA object level: def event_eventName(self)
Parameters: * self: the instance of the class itself (plugin class or an NVDA object class). * obj: NVDA object that fired the event in question. * nextHandler: a callable that will handle the given event at the next level.
In NVDA, event handling goes through the following steps: 1. An object (UIA element, MSAA object, JAB object, etc.) fires an event, and accessibility API's notifies NVDA of this fact. 2. After the events are filtered (such as not responding to duplicate events), a chain of generators is called. This chain, called event executor, calls event handlers defined in global plugins, app modules, tree interceptors, and NVDA objects, in that order. 3. The event handler at the global plugin, app module, or tree interceptor level can "cut" the event execution chain by NOT calling nextHandler() function defined as the event handler parameter. To put it differently, calling nextHandler() (a generator) causes NVDA to move down the event execution chain. Note that event handling and chaining is described in NVDA's event handler source code module (eventHandler.py). As for add-on development practice, I'm about to announce something that might be of use for you. Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 5:49 PM To: nvda-addons <nvda-addons@nvda-addons.groups.io> Subject: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear all,
My name is Bhavya Shah, and I am an undergraduate studying Mathematical and Computational Science and am currently working my way through the incredible add-ons development guide. My hope is to, in the near future, be able to meaningfully contribute code either to NVDA core or add-ons. Since I may have multiple questions coming up at irregular intervals, I thought it would be better to initiate a unified thread to house them all rather than spammily starting new ones for each query. My first set of questions is under. With respect to "Example 2: Generate a tone when switching to Notepad" whose code is pasted below for convenient access: import appModuleHandler import tones class AppModule(appModuleHandler.AppModule): def event_gainFocus(self, obj, nextHandler): tones.beep(256, 200) nextHandler() * Could you please explain the parameters for a general event method? * Here, it looks like self refers to the current class - what does that mean practically? * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep?
I would be deeply, deeply grateful for your guidance and mentorship. I look forward to learning loads and contributing thereafter.
Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
|
|
Hi, Like anything in programming internals, function names are really tags to memory locations where the function code begins. As for gain focus event, that name comes from: 1. Abstract event names: NVDA's own NVDAObject abstract class comes with base definitions for events, including, believe it or not, event_gainFocus. 2. Accessibility API event map: each accessibility API (IAccessible, UIA, and others) include an events to NVDA events map where API specific events are mapped to NVDA events. For example, in UIA, tooltip open event is internally mapped to UIA_tooltipOpen event in NVDA. 3. Event names: after determining what event it is, NVDA's event handler (as part of event executor chain) will create an idealized method name such as event_gainFocus.
As James pointed out in another message and as I've been saying to new add-on authors for years, it is really helpful to work on something else before coming back to NVDA. This is so that you can get a general overview of concepts such as object-oriented programming, data structures and algorithms, and related things and use NVDA as an application of these concepts. To illustrate the knowledge you need to provide really effective NVDA pull requests, you must be able to describe in your own words the following: * Inheritance * Abstract classes * Testing and debugging * Version control system
Or, to summarize, you should have experience with object-oriented programming (OOP). I understand that it is really tempting to learn OOP using a tool we are most familiar with (a screen reader with available source code). I advise against this - or rather, I strongly encourage people to gain experience with something else BEFORE applying what they have learned through NVDA. This is another reason why I also advise against jumping to submitting NVDA pull requests write away if you are new to computer science or programming (as James also notes, NVDA source code is not really an easy source code to understand; even after ten years, I still don't understand browse mode internals fully); writing add-ons after doing something else is a gentler way to get into screen reader internals, in my opinion. Hope this helps. Cheers, Joseph
toggle quoted message
Show quoted text
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Monday, January 10, 2022 7:10 AM To: nvda-addons@nvda-addons.groups.io Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide Dear Joseph, I just installed your Event Tracker add-on and look forward to using it as we go. In this case, you noted the gain focus event. My earlier understanding was that event_gainFocus was just a random name for a function wherein "event_" told Python that this method was an event method and "gainFocus" was only to make it clear for humans. I tested this hypothesis by modifying event_gainFocus to event_testing and the app module stopped working which tells me that the "gainFocus" bit is also significant for Python. I used to think function names only acted as placeholders but clearly that is not the case. I learnt something new. Thanks. On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote: Hi, This depends on which event we wish to listen to (after all, GUI programs rely on what's called an "event loop" to respond to things happening on screen). Gain focus event is fired whenever system focus moves to a new object on screen. This is prominent in Notepad when we switch to it from other programs. Looking at which events are fired by which objects will require observing and debugging accessible events, and one such tool is AccEvent from Windows SDK (and it is one of the reasons for writing Event Tracker add-on so this process can be done easily). Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 10:06 PM To: nvda-addons@nvda-addons.groups.io Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear Joseph,
Much appreciated again! The exposition about what variables really are and do was quite illuminating. I am taking a systems class this quarter, so will be dealing with pointers much more extensively there. I think I have one final question on the Notepad example then. * What did we do in the code to produce the beep only when we first entered Notepad as opposed to all of the time we spent doing things (and thus firing events) in Notepad? I suspect nextHandler is to thank, but I thought nextHandler was only to allow for the *current* event to continue to be handled and would not affect any subsequent events.
Thanks.
On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote:
Hi, In regards to how we know that NVDA object came from Notepad app: this is because of the fact that event handler is defined for an app module, which becomes active as long as the given app is in use (focused). So when writing app modules, you can assume that the NVDA object that fired the event is NVDA's representation of a control from the app in question, which in this case, can be anything from Notepad. Regarding where next handler come from: it is not defined in Python, but rather it is a convention used to identify the next event handler chain. Think of it as a tagged function pointer (hope I'm using the term correctly) - as far as Python is concerned, functions are internally seen as pointers to addresses, and you can name that "address" whatever you like. To go a bit into computer science way of thinking about this (WARNING: will get really geeky here), computers don't care about how things are named as long as they can access whatever they are told to read from specific locations. To explain: Computer memory is a collection of integers known as "memory addresses" (or "addresses" for short). Each address, in turn, consists of bits, with eight bits making a byte (at the hardware level, they are really boxes filled with transistors; you won't learn about how that is possible until you take computer engineering or electrical engineering courses). When a computer is powered on, memory is "empty" - they are not really set to zero's, but are random things but computers treat it as "empty". (or rather, not filled with recognizable things). When a program loads and wants to do something with variables, the central processing unit (CPU) performs a complicated operation that ultimately results in reading something from a memory location. This involves: 1. The processor reads the instruction to read the value of a variable. 2. The processor first locates the location of the variable within the program's working memory set (the amount of memory the program/process is occupying at that moment). 3. Since the variable "points" to the memory location of whatever it points to, a special component of the processor, called memory management unit (MMU) looks up the actual memory address the variable points to. 4. Once the memory location is fetched, the processor returns whatever value the "variable" references (points to). This is why computer scientists and programmers sometimes call variables "pointers", as variables are really tagged memory locations as far as the operating system and the computer hardware is concerned. Although different programming languages use different strategies internally, generally when folks talk about variable names, they are really talking about the memory location the variable points to. Therefore, when we talk about Python variables, it is better to say "the variable references this memory location that contains a specific thing" rather than "something is assigned to a variable". But that's at the advanced level - for convenience, when people teach introductory programming, instructors say "something is assigned to a variable". Building on this, it is perfectly possible to "rename" a variable; after all, a variable is a tag for a memory location, so all you are doing is changing the "outside tag" without changing the memory location the tag points to (or references). This is the reason why we can name the event chaining function anything, but for convenience, we call this "nextHandler" - ultimately, what Python will look at is the address of the function tagged "nextHandler". Hope this helps - I understand what I described above is quite a geeky explanation, but since you are studying computer science, I felt it is time to introduce you to the actual internals of computer science (math and computer science go hand in hand because computer science began as a branch of mathematics; although Alan Turing and John von Neumann popularized computer science in the 20th century, the foundations were laid centuries earlier). Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 6:44 PM To: nvda-addons@nvda-addons.groups.io Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear Joseph,
Thank you so much for the detailed and informative response! Based on my understanding of your explanation, if I were to go back to my questions, I have understood the following: * Could you please explain the parameters for a general event method? Response: The two event method signatures you noted. * Here, it looks like self refers to the current class - what does that mean practically? Response: Self is just an instance of the class we began to define. It doesn't mean anything unusual, but is what we will keep using to define methods for that class of things. * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? Response: obj refers to the NVDA object that fired the event in question. But in the example's code, how did we identify when we landed on an object inside Notepad in the first place? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep? Response: Your (Joseph's) explanation of event handling sheds a lot of light on how nextHandler works especially in the bigger picture. Just to confirm then, is nextHandler provided by Python or part of one of the NVDA moduels we imported?
Thanks.
On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote:
Hi Bhavya, The example you gave ultimately came from NVDA's own development guide, which became the basis for the add-on dev guide. To answer the first set of questions: First, regarding event handler method parameters: generally, there are two event handler method signatures: # From the plugin class level: def event_eventName(self, obj, nextHandler) # At the NVDA object level: def event_eventName(self)
Parameters: * self: the instance of the class itself (plugin class or an NVDA object class). * obj: NVDA object that fired the event in question. * nextHandler: a callable that will handle the given event at the next level.
In NVDA, event handling goes through the following steps: 1. An object (UIA element, MSAA object, JAB object, etc.) fires an event, and accessibility API's notifies NVDA of this fact. 2. After the events are filtered (such as not responding to duplicate events), a chain of generators is called. This chain, called event executor, calls event handlers defined in global plugins, app modules, tree interceptors, and NVDA objects, in that order. 3. The event handler at the global plugin, app module, or tree interceptor level can "cut" the event execution chain by NOT calling nextHandler() function defined as the event handler parameter. To put it differently, calling nextHandler() (a generator) causes NVDA to move down the event execution chain. Note that event handling and chaining is described in NVDA's event handler source code module (eventHandler.py). As for add-on development practice, I'm about to announce something that might be of use for you. Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 5:49 PM To: nvda-addons <nvda-addons@nvda-addons.groups.io> Subject: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear all,
My name is Bhavya Shah, and I am an undergraduate studying Mathematical and Computational Science and am currently working my way through the incredible add-ons development guide. My hope is to, in the near future, be able to meaningfully contribute code either to NVDA core or add-ons. Since I may have multiple questions coming up at irregular intervals, I thought it would be better to initiate a unified thread to house them all rather than spammily starting new ones for each query. My first set of questions is under. With respect to "Example 2: Generate a tone when switching to Notepad" whose code is pasted below for convenient access: import appModuleHandler import tones class AppModule(appModuleHandler.AppModule): def event_gainFocus(self, obj, nextHandler): tones.beep(256, 200) nextHandler() * Could you please explain the parameters for a general event method? * Here, it looks like self refers to the current class - what does that mean practically? * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep?
I would be deeply, deeply grateful for your guidance and mentorship. I look forward to learning loads and contributing thereafter.
Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
|
|
Dear James and Joseph,
I think it was discourteous of me to have seemingly abandoned this thread for a period of time. I will respond in more detail next week, but right after your feedback, I did some intensive self-learning and refreshing on object-oriented design in Python. From basic syntax (like default parameter assignment in a function) to fundamental concepts (like inheritance), I reminded myself of what I had learnt in my last programming class from winter 2021 (I pivoted to theory for the following quarters) and built on that knowledge. Joseph's checklist has been incredibly useful and I will do some self-learning on version control before returning to this thread. I am currently swamped with college coursework, including my systems class wherein I deal with C, bits and pointers, WSL and Vim, and am prioritizing that for now. I do hugely appreciate your thoughtful advice and will engage with it more fully in a subsequent mail.
Thanks.
toggle quoted message
Show quoted text
On 1/10/22, Joseph Lee <joseph.lee22590@...> wrote: Hi, Like anything in programming internals, function names are really tags to memory locations where the function code begins. As for gain focus event, that name comes from: 1. Abstract event names: NVDA's own NVDAObject abstract class comes with base definitions for events, including, believe it or not, event_gainFocus. 2. Accessibility API event map: each accessibility API (IAccessible, UIA, and others) include an events to NVDA events map where API specific events are mapped to NVDA events. For example, in UIA, tooltip open event is internally mapped to UIA_tooltipOpen event in NVDA. 3. Event names: after determining what event it is, NVDA's event handler (as part of event executor chain) will create an idealized method name such as event_gainFocus.
As James pointed out in another message and as I've been saying to new add-on authors for years, it is really helpful to work on something else before coming back to NVDA. This is so that you can get a general overview of concepts such as object-oriented programming, data structures and algorithms, and related things and use NVDA as an application of these concepts. To illustrate the knowledge you need to provide really effective NVDA pull requests, you must be able to describe in your own words the following: * Inheritance * Abstract classes * Testing and debugging * Version control system
Or, to summarize, you should have experience with object-oriented programming (OOP). I understand that it is really tempting to learn OOP using a tool we are most familiar with (a screen reader with available source code). I advise against this - or rather, I strongly encourage people to gain experience with something else BEFORE applying what they have learned through NVDA. This is another reason why I also advise against jumping to submitting NVDA pull requests write away if you are new to computer science or programming (as James also notes, NVDA source code is not really an easy source code to understand; even after ten years, I still don't understand browse mode internals fully); writing add-ons after doing something else is a gentler way to get into screen reader internals, in my opinion. Hope this helps. Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Monday, January 10, 2022 7:10 AM To: nvda-addons@nvda-addons.groups.io Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear Joseph,
I just installed your Event Tracker add-on and look forward to using it as we go. In this case, you noted the gain focus event. My earlier understanding was that event_gainFocus was just a random name for a function wherein "event_" told Python that this method was an event method and "gainFocus" was only to make it clear for humans. I tested this hypothesis by modifying event_gainFocus to event_testing and the app module stopped working which tells me that the "gainFocus" bit is also significant for Python. I used to think function names only acted as placeholders but clearly that is not the case. I learnt something new.
Thanks.
On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote:
Hi, This depends on which event we wish to listen to (after all, GUI programs rely on what's called an "event loop" to respond to things happening on screen). Gain focus event is fired whenever system focus moves to a new object on screen. This is prominent in Notepad when we switch to it from other programs. Looking at which events are fired by which objects will require observing and debugging accessible events, and one such tool is AccEvent from Windows SDK (and it is one of the reasons for writing Event Tracker add-on so this process can be done easily). Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 10:06 PM To: nvda-addons@nvda-addons.groups.io Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear Joseph,
Much appreciated again! The exposition about what variables really are and do was quite illuminating. I am taking a systems class this quarter, so will be dealing with pointers much more extensively there. I think I have one final question on the Notepad example then. * What did we do in the code to produce the beep only when we first entered Notepad as opposed to all of the time we spent doing things (and thus firing events) in Notepad? I suspect nextHandler is to thank, but I thought nextHandler was only to allow for the *current* event to continue to be handled and would not affect any subsequent events.
Thanks.
On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote:
Hi, In regards to how we know that NVDA object came from Notepad app: this is because of the fact that event handler is defined for an app module, which becomes active as long as the given app is in use (focused). So when writing app modules, you can assume that the NVDA object that fired the event is NVDA's representation of a control from the app in question, which in this case, can be anything from Notepad. Regarding where next handler come from: it is not defined in Python, but rather it is a convention used to identify the next event handler chain. Think of it as a tagged function pointer (hope I'm using the term correctly) - as far as Python is concerned, functions are internally seen as pointers to addresses, and you can name that "address" whatever you like. To go a bit into computer science way of thinking about this (WARNING: will get really geeky here), computers don't care about how things are named as long as they can access whatever they are told to read from specific locations. To explain: Computer memory is a collection of integers known as "memory addresses" (or "addresses" for short). Each address, in turn, consists of bits, with eight bits making a byte (at the hardware level, they are really boxes filled with transistors; you won't learn about how that is possible until you take computer engineering or electrical engineering courses). When a computer is powered on, memory is "empty" - they are not really set to zero's, but are random things but computers treat it as "empty". (or rather, not filled with recognizable things). When a program loads and wants to do something with variables, the central processing unit (CPU) performs a complicated operation that ultimately results in reading something from a memory location. This involves: 1. The processor reads the instruction to read the value of a variable. 2. The processor first locates the location of the variable within the program's working memory set (the amount of memory the program/process is occupying at that moment). 3. Since the variable "points" to the memory location of whatever it points to, a special component of the processor, called memory management unit (MMU) looks up the actual memory address the variable points to. 4. Once the memory location is fetched, the processor returns whatever value the "variable" references (points to). This is why computer scientists and programmers sometimes call variables "pointers", as variables are really tagged memory locations as far as the operating system and the computer hardware is concerned. Although different programming languages use different strategies internally, generally when folks talk about variable names, they are really talking about the memory location the variable points to. Therefore, when we talk about Python variables, it is better to say "the variable references this memory location that contains a specific thing" rather than "something is assigned to a variable". But that's at the advanced level - for convenience, when people teach introductory programming, instructors say "something is assigned to a variable". Building on this, it is perfectly possible to "rename" a variable; after all, a variable is a tag for a memory location, so all you are doing is changing the "outside tag" without changing the memory location the tag points to (or references). This is the reason why we can name the event chaining function anything, but for convenience, we call this "nextHandler" - ultimately, what Python will look at is the address of the function tagged "nextHandler". Hope this helps - I understand what I described above is quite a geeky explanation, but since you are studying computer science, I felt it is time to introduce you to the actual internals of computer science (math and computer science go hand in hand because computer science began as a branch of mathematics; although Alan Turing and John von Neumann popularized computer science in the 20th century, the foundations were laid centuries earlier). Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 6:44 PM To: nvda-addons@nvda-addons.groups.io Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear Joseph,
Thank you so much for the detailed and informative response! Based on my understanding of your explanation, if I were to go back to my questions, I have understood the following: * Could you please explain the parameters for a general event method? Response: The two event method signatures you noted. * Here, it looks like self refers to the current class - what does that mean practically? Response: Self is just an instance of the class we began to define. It doesn't mean anything unusual, but is what we will keep using to define methods for that class of things. * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? Response: obj refers to the NVDA object that fired the event in question. But in the example's code, how did we identify when we landed on an object inside Notepad in the first place? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep? Response: Your (Joseph's) explanation of event handling sheds a lot of light on how nextHandler works especially in the bigger picture. Just to confirm then, is nextHandler provided by Python or part of one of the NVDA moduels we imported?
Thanks.
On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote:
Hi Bhavya, The example you gave ultimately came from NVDA's own development guide, which became the basis for the add-on dev guide. To answer the first set of questions: First, regarding event handler method parameters: generally, there are two event handler method signatures: # From the plugin class level: def event_eventName(self, obj, nextHandler) # At the NVDA object level: def event_eventName(self)
Parameters: * self: the instance of the class itself (plugin class or an NVDA object class). * obj: NVDA object that fired the event in question. * nextHandler: a callable that will handle the given event at the next level.
In NVDA, event handling goes through the following steps: 1. An object (UIA element, MSAA object, JAB object, etc.) fires an event, and accessibility API's notifies NVDA of this fact. 2. After the events are filtered (such as not responding to duplicate events), a chain of generators is called. This chain, called event executor, calls event handlers defined in global plugins, app modules, tree interceptors, and NVDA objects, in that order. 3. The event handler at the global plugin, app module, or tree interceptor level can "cut" the event execution chain by NOT calling nextHandler() function defined as the event handler parameter. To put it differently, calling nextHandler() (a generator) causes NVDA to move down the event execution chain. Note that event handling and chaining is described in NVDA's event handler source code module (eventHandler.py). As for add-on development practice, I'm about to announce something that might be of use for you. Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 5:49 PM To: nvda-addons <nvda-addons@nvda-addons.groups.io> Subject: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear all,
My name is Bhavya Shah, and I am an undergraduate studying Mathematical and Computational Science and am currently working my way through the incredible add-ons development guide. My hope is to, in the near future, be able to meaningfully contribute code either to NVDA core or add-ons. Since I may have multiple questions coming up at irregular intervals, I thought it would be better to initiate a unified thread to house them all rather than spammily starting new ones for each query. My first set of questions is under. With respect to "Example 2: Generate a tone when switching to Notepad" whose code is pasted below for convenient access: import appModuleHandler import tones class AppModule(appModuleHandler.AppModule): def event_gainFocus(self, obj, nextHandler): tones.beep(256, 200) nextHandler() * Could you please explain the parameters for a general event method? * Here, it looks like self refers to the current class - what does that mean practically? * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep?
I would be deeply, deeply grateful for your guidance and mentorship. I look forward to learning loads and contributing thereafter.
Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
|
|
Hi, It is okay to take a break from add-on development to focus on other life priorities (I'm doing the same thing as you at this time). The fact that you are prioritizing your duty as a student speaks a lot. Cheers, Joseph
toggle quoted message
Show quoted text
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Thursday, January 27, 2022 10:16 PM To: nvda-addons@nvda-addons.groups.io Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide Dear James and Joseph, I think it was discourteous of me to have seemingly abandoned this thread for a period of time. I will respond in more detail next week, but right after your feedback, I did some intensive self-learning and refreshing on object-oriented design in Python. From basic syntax (like default parameter assignment in a function) to fundamental concepts (like inheritance), I reminded myself of what I had learnt in my last programming class from winter 2021 (I pivoted to theory for the following quarters) and built on that knowledge. Joseph's checklist has been incredibly useful and I will do some self-learning on version control before returning to this thread. I am currently swamped with college coursework, including my systems class wherein I deal with C, bits and pointers, WSL and Vim, and am prioritizing that for now. I do hugely appreciate your thoughtful advice and will engage with it more fully in a subsequent mail. Thanks. On 1/10/22, Joseph Lee <joseph.lee22590@...> wrote: Hi, Like anything in programming internals, function names are really tags to memory locations where the function code begins. As for gain focus event, that name comes from: 1. Abstract event names: NVDA's own NVDAObject abstract class comes with base definitions for events, including, believe it or not, event_gainFocus. 2. Accessibility API event map: each accessibility API (IAccessible, UIA, and others) include an events to NVDA events map where API specific events are mapped to NVDA events. For example, in UIA, tooltip open event is internally mapped to UIA_tooltipOpen event in NVDA. 3. Event names: after determining what event it is, NVDA's event handler (as part of event executor chain) will create an idealized method name such as event_gainFocus.
As James pointed out in another message and as I've been saying to new add-on authors for years, it is really helpful to work on something else before coming back to NVDA. This is so that you can get a general overview of concepts such as object-oriented programming, data structures and algorithms, and related things and use NVDA as an application of these concepts. To illustrate the knowledge you need to provide really effective NVDA pull requests, you must be able to describe in your own words the following: * Inheritance * Abstract classes * Testing and debugging * Version control system
Or, to summarize, you should have experience with object-oriented programming (OOP). I understand that it is really tempting to learn OOP using a tool we are most familiar with (a screen reader with available source code). I advise against this - or rather, I strongly encourage people to gain experience with something else BEFORE applying what they have learned through NVDA. This is another reason why I also advise against jumping to submitting NVDA pull requests write away if you are new to computer science or programming (as James also notes, NVDA source code is not really an easy source code to understand; even after ten years, I still don't understand browse mode internals fully); writing add-ons after doing something else is a gentler way to get into screen reader internals, in my opinion. Hope this helps. Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Monday, January 10, 2022 7:10 AM To: nvda-addons@nvda-addons.groups.io Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear Joseph,
I just installed your Event Tracker add-on and look forward to using it as we go. In this case, you noted the gain focus event. My earlier understanding was that event_gainFocus was just a random name for a function wherein "event_" told Python that this method was an event method and "gainFocus" was only to make it clear for humans. I tested this hypothesis by modifying event_gainFocus to event_testing and the app module stopped working which tells me that the "gainFocus" bit is also significant for Python. I used to think function names only acted as placeholders but clearly that is not the case. I learnt something new.
Thanks.
On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote:
Hi, This depends on which event we wish to listen to (after all, GUI programs rely on what's called an "event loop" to respond to things happening on screen). Gain focus event is fired whenever system focus moves to a new object on screen. This is prominent in Notepad when we switch to it from other programs. Looking at which events are fired by which objects will require observing and debugging accessible events, and one such tool is AccEvent from Windows SDK (and it is one of the reasons for writing Event Tracker add-on so this process can be done easily). Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 10:06 PM To: nvda-addons@nvda-addons.groups.io Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear Joseph,
Much appreciated again! The exposition about what variables really are and do was quite illuminating. I am taking a systems class this quarter, so will be dealing with pointers much more extensively there. I think I have one final question on the Notepad example then. * What did we do in the code to produce the beep only when we first entered Notepad as opposed to all of the time we spent doing things (and thus firing events) in Notepad? I suspect nextHandler is to thank, but I thought nextHandler was only to allow for the *current* event to continue to be handled and would not affect any subsequent events.
Thanks.
On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote:
Hi, In regards to how we know that NVDA object came from Notepad app: this is because of the fact that event handler is defined for an app module, which becomes active as long as the given app is in use (focused). So when writing app modules, you can assume that the NVDA object that fired the event is NVDA's representation of a control from the app in question, which in this case, can be anything from Notepad. Regarding where next handler come from: it is not defined in Python, but rather it is a convention used to identify the next event handler chain. Think of it as a tagged function pointer (hope I'm using the term correctly) - as far as Python is concerned, functions are internally seen as pointers to addresses, and you can name that "address" whatever you like. To go a bit into computer science way of thinking about this (WARNING: will get really geeky here), computers don't care about how things are named as long as they can access whatever they are told to read from specific locations. To explain: Computer memory is a collection of integers known as "memory addresses" (or "addresses" for short). Each address, in turn, consists of bits, with eight bits making a byte (at the hardware level, they are really boxes filled with transistors; you won't learn about how that is possible until you take computer engineering or electrical engineering courses). When a computer is powered on, memory is "empty" - they are not really set to zero's, but are random things but computers treat it as "empty". (or rather, not filled with recognizable things). When a program loads and wants to do something with variables, the central processing unit (CPU) performs a complicated operation that ultimately results in reading something from a memory location. This involves: 1. The processor reads the instruction to read the value of a variable. 2. The processor first locates the location of the variable within the program's working memory set (the amount of memory the program/process is occupying at that moment). 3. Since the variable "points" to the memory location of whatever it points to, a special component of the processor, called memory management unit (MMU) looks up the actual memory address the variable points to. 4. Once the memory location is fetched, the processor returns whatever value the "variable" references (points to). This is why computer scientists and programmers sometimes call variables "pointers", as variables are really tagged memory locations as far as the operating system and the computer hardware is concerned. Although different programming languages use different strategies internally, generally when folks talk about variable names, they are really talking about the memory location the variable points to. Therefore, when we talk about Python variables, it is better to say "the variable references this memory location that contains a specific thing" rather than "something is assigned to a variable". But that's at the advanced level - for convenience, when people teach introductory programming, instructors say "something is assigned to a variable". Building on this, it is perfectly possible to "rename" a variable; after all, a variable is a tag for a memory location, so all you are doing is changing the "outside tag" without changing the memory location the tag points to (or references). This is the reason why we can name the event chaining function anything, but for convenience, we call this "nextHandler" - ultimately, what Python will look at is the address of the function tagged "nextHandler". Hope this helps - I understand what I described above is quite a geeky explanation, but since you are studying computer science, I felt it is time to introduce you to the actual internals of computer science (math and computer science go hand in hand because computer science began as a branch of mathematics; although Alan Turing and John von Neumann popularized computer science in the 20th century, the foundations were laid centuries earlier). Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 6:44 PM To: nvda-addons@nvda-addons.groups.io Subject: Re: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear Joseph,
Thank you so much for the detailed and informative response! Based on my understanding of your explanation, if I were to go back to my questions, I have understood the following: * Could you please explain the parameters for a general event method? Response: The two event method signatures you noted. * Here, it looks like self refers to the current class - what does that mean practically? Response: Self is just an instance of the class we began to define. It doesn't mean anything unusual, but is what we will keep using to define methods for that class of things. * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? Response: obj refers to the NVDA object that fired the event in question. But in the example's code, how did we identify when we landed on an object inside Notepad in the first place? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep? Response: Your (Joseph's) explanation of event handling sheds a lot of light on how nextHandler works especially in the bigger picture. Just to confirm then, is nextHandler provided by Python or part of one of the NVDA moduels we imported?
Thanks.
On 1/9/22, Joseph Lee <joseph.lee22590@...> wrote:
Hi Bhavya, The example you gave ultimately came from NVDA's own development guide, which became the basis for the add-on dev guide. To answer the first set of questions: First, regarding event handler method parameters: generally, there are two event handler method signatures: # From the plugin class level: def event_eventName(self, obj, nextHandler) # At the NVDA object level: def event_eventName(self)
Parameters: * self: the instance of the class itself (plugin class or an NVDA object class). * obj: NVDA object that fired the event in question. * nextHandler: a callable that will handle the given event at the next level.
In NVDA, event handling goes through the following steps: 1. An object (UIA element, MSAA object, JAB object, etc.) fires an event, and accessibility API's notifies NVDA of this fact. 2. After the events are filtered (such as not responding to duplicate events), a chain of generators is called. This chain, called event executor, calls event handlers defined in global plugins, app modules, tree interceptors, and NVDA objects, in that order. 3. The event handler at the global plugin, app module, or tree interceptor level can "cut" the event execution chain by NOT calling nextHandler() function defined as the event handler parameter. To put it differently, calling nextHandler() (a generator) causes NVDA to move down the event execution chain. Note that event handling and chaining is described in NVDA's event handler source code module (eventHandler.py). As for add-on development practice, I'm about to announce something that might be of use for you. Cheers, Joseph
-----Original Message----- From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Bhavya shah Sent: Sunday, January 9, 2022 5:49 PM To: nvda-addons <nvda-addons@nvda-addons.groups.io> Subject: [nvda-addons] Questions About Add-On Dev: Working My Way Through The NVDA Add-ons Development Guide
Dear all,
My name is Bhavya Shah, and I am an undergraduate studying Mathematical and Computational Science and am currently working my way through the incredible add-ons development guide. My hope is to, in the near future, be able to meaningfully contribute code either to NVDA core or add-ons. Since I may have multiple questions coming up at irregular intervals, I thought it would be better to initiate a unified thread to house them all rather than spammily starting new ones for each query. My first set of questions is under. With respect to "Example 2: Generate a tone when switching to Notepad" whose code is pasted below for convenient access: import appModuleHandler import tones class AppModule(appModuleHandler.AppModule): def event_gainFocus(self, obj, nextHandler): tones.beep(256, 200) nextHandler() * Could you please explain the parameters for a general event method? * Here, it looks like self refers to the current class - what does that mean practically? * What does obj refer to (the variable does not seem to have been defined previously and I am not sure if this is a keyword)? * Where are we getting the nextHandler method from? Is it built into Python, or is it coming from either tones or appModuleHandler? In case the latter, then why don't we need to do {module of origin}.nextHandler like we had to do tones.beep?
I would be deeply, deeply grateful for your guidance and mentorship. I look forward to learning loads and contributing thereafter.
Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
-- Best Regards, Bhavya Shah Stanford University | Class of 2024 LinkedIn: https://www.linkedin.com/in/bhavyashah125/
|
|