Project ExtMFD automatic focus switch

kamaz

Unicorn hunter
Addon Developer
Joined
Mar 31, 2012
Messages
2,300
Reaction score
4
Points
0
Problem description. A common solution for displaying MFDs in an external window (i.e. outside the main Orbiter window) is to use ExtMFD. However, ExtMFD has a major problem: if you click on an MFD opened in an external window, the keyboard focus will switch to that window. Consequently, any key presses will be send to the MFD window (instead of the Orbiter main window) and be ignored.

In the desktop setting, the problem can be mitigated by using the "Focus follows mouse" option. However, that still requires the user to actually move the mouse pointer back to the Orbiter window, in order to regain the keyboard forcus (and the ability to control spacecraft).

While this is at worst irritating in dekstop setting, it is a major showstopper for simpit builders. A simplest (although not the cheapest) way of introducing dedicated MFD displays in a simpit is to hook a secondary touch screen display to the computer running orbiter. But that solutions runs into the problem described above: once a user touches the MFD touchscreen, they lose keyboard controls of the spacecraft. This has been documented in the past threads, e.g.:

The use of ExtMFD on a cockpit may prove to be harder than one may expect. Since it has no direct key access for the buttons, the mouse cliks must be used, and if you do that, you lose main window focus, which means no keyboard keys will work for functions found on the main window.

I would like to use MFDs in other PCs (especially my touch netbook). Currently, the only way to export MFDs over network has to be integrated in a ship, which is not very useful. I also tried solutions like VNC or MaxiVista with ExtMFD but there's alway the input problem : I can't touch / modify my external MFD and handle my ship in the same way as the coputer sees only one input.

A number of workarounds this problem have been proposed, usually revolving about sending the MFD image over network to a different computer (RemoteMFD, WebMFD, Network-MFD).

It appears however, that nobody thought about fixing the problem directly at its core, i.e. at ExtMFD.

The solution. The Win32 API provides the SetForegroundWindow() function, which programmatically switches keyboard focus to the window whose handle (HWND) is passed as an argument. We can thus trivially implement code switching the keyboard focus back to the main orbiter window:

Code:
void switchWindow(void)
{
	HWND mainWindow = FindWindow(NULL, "Orbiter 2010");
	if ( mainWindow == NULL )
		mainWindow = FindWindow(NULL, "Orbiter 2010 [D3D9Client]");
	if ( mainWindow == NULL ) {
		sprintf(oapiDebugString(), "%s:%d:Orbiter main window not found!", __FILE__, __LINE__);
		return ;
	}
	SetForegroundWindow(mainWindow);
}

Then, we add calls to switchWindow() to mouse event handlers in MFDWindow.cpp, so that the focus is automatically switched back on mouse relase... and that's it. After you click the MFD button, the focus will momentarily switch back to the Orbiter window. The focus will also switch back after moving or resizing the window.

In other words, you can do whatever you want with the ExtMFD window and your keyboard input will still go into Orbiter, as it should. (Okay, unless you are pressing keys when holding down the mouse in the ExtMFD window. That will not work.)

The code. I have uploaded modified code to: http://www.mediafire.com/?catbsx41ajudsda The archive contains two files.

The recompiled ExtMFD dll is called ExtMFDYieldFocus.dll. Put it in Modules\Plugin directory. Then, enable the plugin in Orbiter Launchpad, and disable stock ExtMFD and switch off "focus follows mouse".

The second file is modified version of MFDWindow.cpp. To recompile the plugin yourself, put it into orbitersdk\samples\ExtMFD replacing the orginal file and rebuild the dll normally. This file is also attached to this post, so it does not get lost :)

Bugs. The modified ExtMFD appears to work okay for me in orbiter 2010P1.

The biggest problem I can see is that I obtain HWND to Orbiter's main windown using FindWindow() function, which finds an open window by its title (normally it's "Orbiter 2010"). So, if your orbiter main window for some reason has a different title, FindWindow() will not be able to find it and the function will fail to switch the focus (it will not crash however :)).

This is specifically the case with the D3D9Client renderer, and, as, you can see above, the switchWindow() function can recognize the window title used by that one. So we would have to hardcode all possible main window names (i.e. for all renderers and Orbiter versions), unless there is a generic way to get the main window HWND which I am not aware of.

That's all. Please enjoy and test the code. Bug reports and comments are welcome and appreciated.
 

Attachments

  • MFDWindow.cpp.txt
    8.2 KB · Views: 11

Ripley

Tutorial translator
Donator
Joined
Sep 12, 2010
Messages
2,992
Reaction score
239
Points
78
Location
Rome
Website
www.tuttovola.org
Maybe you already know Autohotkey?

I use it to open and place at fixed coordinates some EtxMFDs whenever I launch Orbiter. It's a powerful scripting language, it has lots of functions and I think it can nearly perform any task...kind of!

It has windows focus handling functions too, exactly what you're looking for, though it could not be the path you intend to follow.

Here's "my" script:
https://www.orbiter-forum.com/showthread.php?p=329884&postcount=6
 
Last edited:

yagni01

Addon Developer
Addon Developer
Donator
Joined
Feb 8, 2008
Messages
464
Reaction score
0
Points
16
Location
Atlanta, GA
Problem description. A common solution for displaying MFDs in an external window (i.e. outside the main Orbiter window) is to use ExtMFD. However, ExtMFD has a major problem: if you click on an MFD opened in an external window, the keyboard focus will switch to that window. Consequently, any key presses will be send to the MFD window (instead of the Orbiter main window) and be ignored.
. . .
[This is a] major showstopper for simpit builders.

A number of workarounds this problem have been proposed, usually revolving about sending the MFD image over network to a different computer (RemoteMFD, WebMFD, Network-MFD).

Also the sound turns off.

The "workarounds" you mention are actually solutions for a different problem: creating interactive displays on different computers (btw, RemoteMFD does not send the image over the network). I also use Autohotkey (AHK) for controlling external windows, and for a physical flight deck, buttons are probably more logical than a mouse to interact with the MFDs. As Ripley mentions, AHK can do exactly that: switch focus to a desired MFD, click the mouse at a specified location, and return the focus to Orbiter.

The primary problem I ran into with using multiple monitors on the computer running Orbiter is many MFDs can give you a significant hit on frame rate (my MIP could hold as many as 8). A secondary computer sufficient to run some MFDs would not be terribly expensive, but on the other hand, a large network load can have the same effect.

I would like to see if an out-of-process Orbiter facade/container for MFDs could run on a separate box with only data communication at ~10fps with minimal frame rate impact on Orbiter itself; thus eliminating the loss-of-focus issue entirely and potentially allowing many more MFDs to be displayed. A true External MFD.
 
Top