Making software usable requires thoughtful design. Often, achieving a usable design means adding accessibility features, in addition to just a good UI.
Design is not just what it looks like and feels like. Design is how it works.
In DataRefTool, I've worked hard to maximize usability and accessibility. The effort required has been surprising. I've thought for months (and years) that one feature or another was 90% done, only to discover there was still much work required to get the right feel or functionality.
This page will share some of what I've learned in building an X-Plane plugin; I hope it can serve as a checklist for others trying to produce a high-quality experience in X-Plane.
General
UI
Text
Keyboard
While VR isn't the dominant way of using X-Plane, it definitely has vocal users. I've worked with Bill (Sparker256) to support VR as best as I can.
Most of what to do with VR, I found to be pretty straightforward, largely because of pretty good APIs for managing windows in X-Plane 11+.
Move windows in and out of VR automatically. By listening for XPLM_MSG_ENTERED_VR
and XPLM_MSG_EXITING_VR
messages, you can know when to automatically convert visible windows so they appear in the VR environment (using XPLMSetWindowPositioningMode()
).
While you're making these modifications, it's a good idea to go ahead an add support for pop-out windows; they are similar in some ways.
Ensure that functionality still works the limited keyboard in VR. DRT users relied on keyboard shortcuts for cut/copy/paste. While there is a keyboard in VR, it doesn't generally work for keyboard shortcuts. I added buttons to the search window for all functionality that relied on keyboard shortcuts.
Special windows may require special accomodations. PlaneCommand presents a couple of hovering widgets over the screen when in desktop mode; these don't always make sense in VR, and often get in the way. Consider if any of your UI needs to be re-evaluated for VR users.
Test using X-Plane's --fake_vr
mode if you don't have a headset. Launching X-Plane with the --fake_vr
flag on the command line enables a kind of VR emulation mode that's useful for finding bugs. I greatly prefer testing this way to using a real headset, as I invariably spend an hour or two updating drivers to get my Quest 2 to work with Windows / SteamVR / X-Plane. Instead, I'd rather just test with the fake VR mode on my Mac because it takes so much less time.
File bug reports. I've found a few bugs in X-Plane, especially with the pointer support. Helping Laminar get bugs fixed earlier reduces the number of bug report emails I get.
Approximately 5-10% of flight simulation users have some form of color vision deficiency ("color blindness"). As DRT uses color to indicate when a dataref or command is changing or active, its important that all users can perceive the differences indicated by color.
There are actually lots of different types of color blindness. Deuteranopia is the most common, and causes people to have a hard time differentiating red from green; there are other forms of color blindness. There's a lot written on the internet about the different variations.
While I'd love to have one color scheme that works for everybody, I couldn't figure out a universal color scheme that would be fully ergonomic for people with full color vision, and also support the 5-10% of users that have some form of colorblindness. Adding new settings or modes is never my preferred solution, but in this case, I couldn't figure out another way to do it.
To develop a solution, I used the built-in macOS feature for simulating color blindness (System settings > Acccessibilty > Display > Color filters; Windows has similar functionality). Once I had a proposed solution, it took a couple of rounds of user feedback to adjust it into something that actually worked well enough for my color blind users.
When the Reduce colors setting is turned on, a color scheme based on the Wong color palette (Figure 2).
Default | Reduce colors | |
---|---|---|
White | White | Dataref: not changed recently |
Light cyan | Sky blue | Dataref: recent small changes |
Light magenta | Blue | Dataref: recent large changes |
Green | Yellow | Command: not used recently |
Yellow | Orange/vermillion | Command: used recently |
Red-orange | Vermillion | Dataref: deprecated |
Red-orange | Reddish purple | Dataref or command: ignored |
English may be the international language of aviation, but that doesn't mean every user of X-Plane knows English. I decided to start adding support for other languages to DRT, and I found that it was both easier and more difficult that I had expected.
The SDK's XPLMGetLanguage() function returns the current language that X-Plane is set to. DRT 2.5 introduces a spanish translation that is shown when spanish is selected as the language; in all other situations, english is shown.
There are many different good localization libraries and tools; I used Mozilla's Project Fluent as the format for translations, primarily because it handles plurals and quantities in addition to simply substituting in strings. The translations are in FTL files, which are then loaded into DRT using Rust's fluent-static library. I found this to be a fairly ergonomic way to actually use the text strings in DRT's code; this part was easier than I expected.
To do localization and translation, first you have to separate all the UI-visible strings in your application. DRT 2.5 has approximately 140 labels and messages that need to be translated; this is way more than I expected. While it was more work than I was anticipating, luckly this part only has to be done once. Once this was done, I ended up with an FTL file with about 150 lines of each possible piece of text in DRT.
As an example, for this window:
I ended up with a file like this:
## ------
## Command window
command-window-title = Command { $name }
command-tab-command = Command
command-tab-history = History ({ $event_count })
command-tab-sources = { $source_count ->
[one] Source (1)
*[other] Sources ({ $source_count })
}
command-active-field-label = Active: { $value }
command-active-field-value-never = Never
command-active-field-value-yes = Yes
command-active-field-value-no = No
command-last-active-field-label = Last active:
command_tab_command_activate_press = Activate while held
command_tab_command_activate_once = Activate once
Once I had an english copy of all the strings, I did a kind of first draft of spanish translation, with the help of ChatGPT for some of the more technical language. (I'll be relying on feedback from users to get translations right!) There's one FLT (fluent) file for each language, and they look basically the same as the English file:
## ------
## Command window
command-window-title = Comando { $name }
command-tab-command = Comando
command-tab-history = Historial ({ $event_count })
command-tab-sources = { $source_count ->
[one] Fuente (1)
*[other] Fuentes ({ $source_count })
}
command-active-field-label = Activo: { $value }
command-active-field-value-never = nunca
command-active-field-value-yes = sí
command-active-field-value-no = no
command-last-active-field-label = Última vez activo:
command_tab_command_activate_press = Mantener para activar
command_tab_command_activate_once = Activar una vez
For additional languages, I expect I'll use a service like CrowdIn for additional translations, using a combination of crowdsourcing and AI for additional languages. First, we'll see how it goes with Spanish!
Example of characters Encodings & Multi-byte characters Interaction with X-Plane API Rendering