Do NVDA addons have ability to execute on NVDA startup/shutdown? - nvda

I am trying to write an addon that does a thing when NVDA starts up. I want it do something else when NVDA shuts down. I have written a basic addon that uses input gestures to do my things... but are there event handlers or some other mechanism that I can use to tie into so I can do my things on NVDA startup/shutdown?

The answer is yes.
https://github.com/nvdaaddons/DevGuide/wiki/NVDA-Add-on-Development-Guide#other-components
For GlobalPlugins, a constructor like so can be used for startup:
def __init__(self):
super(GlobalPlugin, self).__init__()
# DO STUFF
And a terminate() for shutdown:
def terminate(self):
# DO STUFF

Related

X11: Detect general Mouse and Keyboard events

Is there a way to detect if the mouse has been moved ANYWHERE on the X Server or a keyboard event occured? I need to react on the user doing anything with the X11 input devices.
I only managed to detect events on my own window using GTK.
I am thankful for every information (it does not have to be full code, an entry point would be good enough!)
Yes, you can do this using the Xinput2 extension. A complete, but rather small, tool which does this for cursor events can be found here (unclutter-xfixes). As a disclaimer, I am the author of that tool.
Another good resource in tutorial form can be found here.
Using XInput2 has multiple benefits:
No need to constantly poll the position (resource efficient)
Does not interfere with / break applications like selecting mouse events on all windows would.
What you don't get easily using Xinput2 is the exact position (but you can query it when you need it), but my understanding is that you don't need it anyway.
Once you loaded the extension, which I won't show here, you can select all events like this:
XIEventMask masks[1];
unsigned char mask[(XI_LASTEVENT + 7)/8];
memset(mask, 0, sizeof(mask));
XISetMask(mask, XI_RawMotion);
XISetMask(mask, XI_RawButtonPress);
XISetMask(mask, XI_RawKeyPress);
masks[0].deviceid = XIAllMasterDevices;
masks[0].mask_len = sizeof(mask);
masks[0].mask = mask;
XISelectEvents(display, DefaultRootWindow(display), masks, 1);
XFlush(display);
In your event queue, you can now look for the corresponding events.
For modern X11 implementations, xinput --test-xi2 --root will display great detail about all X11 input events available on your root window. I use this in a shell script that needs to wait on any input event:
echo "DEBUG $(date) waiting on X event"
xinput --test-xi2 --root | head -n 15 >/dev/null
echo "DEBUG $(date) got X event"

Create Console like Progress Window

I am replacing many batch files, that do almost the exact same thing, with one WPF executable. I have the program written, but I am having troubles with my "console" like display.
Within the program I call an executable to perform a task. This executable sends it's output messages to the console. I am able to redirect those to my "console" like display with the following.
Process p = new Process();
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.FileName = MyExecutable;
p.StartInfo.Arguments = MyArguments;
p.Start();
while (!p.StandardOutput.EndOfStream)
{
string _output = p.StandardOutput.ReadLine();
// This is my display string ObservableCollection
_displayString.Add(new DisplayData { _string = _output, _color = System.Windows.Media.Brushes.Black, _fontSize = 12 });
// This is to redirect to a Console & what I want to get rid of
Console.WriteLine(_output);
}
p.WaitForExit();
When the executable is done running I use a MessageBox to ask the user if they want to run the executable again. The problem is that when the MessageBox is up the user is unable to scroll on my "console" like window to make an informative decision. To temporarily work around this I launch a console at start up, see this, and write the output stream from the process running the executable to the console so the user can scroll through the information and make a decision.
I am using a listbox to display a collection of textblocks, see this. I am not attached to anything for making the display, or MessageBox'es.
How can I make a "console" like display that will take a user input (MessageBox, direct input, etc...), but also allow them to scroll through the data before they make their decision?
EDIT:
As to the comments I have been receiving I am not clear on what I am trying to accomplish. I have a batch file that runs a executable multiple times with different arguments per run. There is a lot of setup before and between the executable calls. I have created an executable to replace many flavors of a similar batch file with drop down menus for the user to change settings at run time. When the user likes their settings they click a "Start" button, and away it goes doing setups and prompting questions as it goes and then finally runs executable for the first time.
My issue is when the called executable, inside mine, is done running the user needs to decide if they want to run it again for different reasons. I need to prompt the user "Run again - 'Yes' or 'No'?", and that is where I am running into problems. A MessageBox doesn't allow me to scroll on my Progress Window. I have tried a Modeless dialog box, but with Show() the program continues on, and ShowDialog() is the same issue as the MessageBox.
Any suggestions on how to do this would be appreciated.
You are in Windows, but trying to use DOS paradigm. Windows is event-based system! You need to write "event handlers" but not put all your code in one function.
However, there is a trick, which allows to show Modal (read "blocking your code") dialog in Modeless (read "not blocking your window"). Not sure how to implement this in WPF, but idea is to re-enable your window (which acts as parent for your dialog). You need to do this in your dialog event handler (WM_INITDIALOG equivalent?).
Also (in WinAPI) you may run dialog with NULL as parent window.

How to send message/activate a SysTray application?

We are trying to setup a SysTray application which can be activated from elsewhere. To be more specific the activation will come from a third party app which we cannot modify but allows us to activate our own app via its path (plus a parameter/argument).
When it gets activated we want to put up a BalloonText, there are to be no forms involved.
Therefore we have two problems to solve:
Make our SysTray application single instance (since it's no good generating multiple instances).
Allow this other app to activate our application with arguments
Lots of help out there to help learners create simple SysTray applications (and indeed we've done it ourselves as part of a solution to an unconnected project).
However we've never tried to make it single instance before.
Lots of help out there to help learners create single instance Winforms applications (again we've done this as part of other projects) but always simple applications with conventional forms (not SysTray). We use the VisualBasic WindowsFormsApplicationBase method.
Can't seem to combine these two approaches into a single solution.
Update:
Hans answer below nails it (and especially his comment):
This is already taken care of with a NotifyIcon, drop it on the form.
And the "Make single instance application" checkbox. And the
StartupNextInstance event. You'll need to stop assuming there's
anything special about this
As far as your first question about checking for other instances this seems to work. I used the CodeProject example as a baseline. In your Sub Main routine you can check for other instances by using the GetProcessesByName Method of the Process class. Something like this:
Public Sub Main()
'Turn visual styles back on
Application.EnableVisualStyles()
'Run the application using AppContext
Dim p() As Process
p = Process.GetProcessesByName("TrayApp") 'Your application name here
If UBound(p) >= 0 Then
End
End If
Application.Run(New AppContext)
End Sub
For the second question if your SysTray application is already running you might want to give this article on .Net Interprocess Communication a try. Otherwise parse the CommandLine arguments in yourSub Main as it is created.
From above article:
The XDMessaging library provides an easy-to-use, zero-configuration solution to same-box cross-AppDomain communications. It provides a simple API for sending and receiving targeted string messages across application boundaries. The library allows the use of user-defined pseudo 'channels' through which messages may be sent and received. Any application can send a message to any channel, but it must register as a listener with the channel in order to receive. In this way, developers can quickly and programmatically devise how best their applications can communicate with each other and work in harmony.
Everything becomes trivial when you actually do use a form. It is simple to put your app together with the designer, simple to get your app to terminate, simple to avoid a ghost icon in the tray, simple to create a context menu, simple to add popups if you ever need them.
The only un-simple thing is getting the form to not display. Paste this code in the form's class:
Protected Overrides Sub SetVisibleCore(ByVal value As Boolean)
If Not Me.IsHandleCreated Then
Me.CreateHandle()
value = False
End If
MyBase.SetVisibleCore(value)
End Sub
The "Exit" command in the context menu is now simply:
Private Sub ExitToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExitToolStripMenuItem.Click
Me.Close()
End Sub

winforms textbox Ctrl-Backspace to Delete Whole Word & Spaces

I found an article here:
Winforms Textbox - Using Ctrl-Backspace to Delete Whole Word
to delete the whole word in a textbox while holding ctrl+backspace, but I noticed that if you don't implement the app.config modifications like so:
<configuration>
<appSettings>
<add key="SendKeys" value="SendInput" />
</appSettings>
</configuration>
that only the current word will be removed and the process of backspacing will be interrupted. For instance, if I typed in "Tim tom" and then used the ctrl + backspace trick, "tom" would be deleted, interrupting any backspace operation and leaving "Tom ".
If you do use the app.config modification, however, "tom" would successfully be removed and backspace operations would continue, but without continuing to remove whole words, as if you were just holding the backspace button.
Does anyone know what causes this or how to fix it?
Your application is choosing a different behavior of sending keypress equivalents to the application.
The historical exposition why the two protocols exist is explained here:
The SendKeys class has been updated for the .NET Framework 3.0 to
enable its use in applications that run on Windows Vista. The enhanced
security of Windows Vista (known as User Account Control or UAC)
prevents the previous implementation from working as expected. The
SendKeys class is susceptible to timing issues, which some developers
have had to work around. The updated implementation is still
susceptible to timing issues, but is slightly faster and may require
changes to the workarounds. The SendKeys class tries to use the
previous implementation first, and if that fails, uses the new
implementation. As a result, the SendKeys class may behave differently
on different operating systems. Additionally, when the SendKeys class
uses the new implementation, the SendWait method will not wait for
messages to be processed when they are sent to another process.
The timing issues mentioned here concern especially continued control of application by characters, not just one character at a time. They include
difficulty in synchronizing typing rate
making sure that the right window receives the input when the app is opening dialogs
making sure that the right app receives the input even when the user meddles with close buttons
However, the real reason between the SendKeys behavior change was not programmer friendliness (which did not improve significantly), but security.
It is definitely a good idea to set the SendKeys parameter to specify the desired behavior. You don't want your application to mysteriously start behaving differently just because UAC was turned on or off.

MediaElement is repeating clips automatically, and sometimes fails to play them

I have an app which plays a few short sound clips. To play them I simply set the source to the new clip path, which is a WMA I encoded with Expression Encoder using WP7 settings. It's not even worth sharing the code -- there's an event handler. In it, I set the ME.Source property to a new Uri. It's set to AutoPlay, so that's it! Here:
private void PlaySound(ItemViewModel sound) {
Model.CurrentSound = sound;
CurrentSound.Source = new Uri(sound.Path, UriKind.Relative);
}
private void Sounds_SelectionChanged(object sender, SelectionChangedEventArgs e) {
var list = ((ListBox) sender);
var item = (ItemViewModel) list.SelectedItem;
SelectItem(item);
}
Also I should point out that the sounds are all resources (build type = Resource). I need them to be because the app needs to discover them dynamically. The paths are all like this, "sounds/foo/bar/sound.wma". Sometimes there is a space in the path, it is url encoded with %20 (this is how the resource manager returns the path, I didn't do that).
The problem is many people, but not all, are saying that the sound auto-repeats. The sounds are very short, only a few seconds, so it's very annoying. I don't understand how this is happening, the MediaElement doesn't even have an auto repeat feature.
Perhaps related, but some have also complained that every now and then the sound does not play. They have to click it again. All I can think of is that there is something wrong with how the sounds are encoded, but they are WMA, and as I said, I encoded them using the 'playback in WP7' settings in expression encoder. How could it be that it works usually but not other times if that were the case, anyway?
I'm at a loss and my app is getting some bad reviews because of this behavior. Help!
"there's and event handler" but you don't say of what? It could be that event firing over and over or not at all in some cases. Potentially your code has a logical errors where you have failed to detach an existing handler and then added another. As usage progresses you end up with a single event being handled by multiple handlers.
Edit
The Selection changed event is notorious for firing more frequently than we'd like. I suggest you add some debounce code that makes record of the last item selected and how long ago. If the next selected item is the same as the last one and it was say less than a second ago then swallow the event without doing anything else.
It sounds like you might be trying to play Sound Effects - in which case you might be better off using the XNA SoundEffect mechanism
e.g. http://www.japf.fr/2010/08/sound-effect-in-wp7-sl-application/
SoundEffect only works for WAV files (PCM) - but I've used it in several apps and scripts including embedded content files and downloaded files (e.g. translation and ironruby scripts).
The XNA class works well within SL and allows multiple sound effects to be played at the same time.
The problem with repeating turned out to be needing to do this:
MediaPlayer.IsRepeating = false;
I think what happened was the user would be in another app that sets this to true, and upon opening my app that value was still true! That has to be a bug, it's totally unexpected. If you look at other sound-playing apps like soundboard apps, there are users complaining in the reviews about the very same thing.. "I wish it wouldn't repeat the sounds..."

Resources