FSUIPC Lua Library PDF
FSUIPC Lua Library PDF
FSUIPC Lua Library PDF
for FSUIPC7 (all versions) – WideClient 7.156 needed for some facilities as noted.
This document lists the facilities added to the standard Lua library complement via ten libraries “ipc”, “logic”,
"com", “event”, "sound", "gfd", "mouse", "ext", "wnd" and "display" (the last one for WideClient only).
The ipc library adds all of the facilities needed to interact with FS and FSUIPC, whilst the logic library just adds bit-
oriented logical operations which are otherwise missing from Lua but needed when dealing with arrays of bits for
switches and options in FS. The event library provides ways of having dormant Lua plug-ins containing functions
activated by events in FS. Events which can be so detected include joystick buttons, keyboard combinations being
pressed/released, FS controls being used, and FSUIPC offsets changing values.
ipc.createLvar(“name”, This creates a new FS local panel variable called “name” and sets
initialValue) its initial value. These are L: <name> values. You can provide the
[Not WideClient] L: part explicitly or leave it out.
N.B. To use this function, the FSUIPC WASM module must be
installed, and the WASM interface active in FSUIPC7.
ipc.display(“string”) Displays the given string value in FS, in a sizeable and undockable
ipc.display(“string”, delay) window entitled “Lua display” (“SimConnect Message Window”
on MSFS). The maximum string which will be displayed is 1023
ipc.display(“string”, colour, characters, including new lines (\n) codes.
delay)
If the delay parameter is provided (it is a number) it specifies how
long the display should stay for, in seconds. To remove a display
[WideClient okay, but display is prematurely, send a null string (“”).
in FS, not on client PC]
With 3 parameters given, the second specifies whether the message
should be in red (default, colour=0) or white (colour=1 or any non-
zero value). [This facility was added in FSUIPC 4.904, 3.999z3
and WideClient 6.996]
Note that with WideClient there is only one such window for all
Lua plug-ins. On MSFS the Simconnect window is shared by all
2
SimConnect clients. In all cases the last one wins!
This of course also applies to direct FSUIPC use, unless the
ipc.setowndisplay function (see below) is used to name, position
and size an individual window for this plug-in [This is NOT
currently supported on P3D4]
See also ipc.lineDisplay and ipc.setowndisplay
Note that there are currently many issues
with the simconnect message display
functionality. It is recommended to use the
wnd library for the time being.
n = ipc.elapsedtime() This returns the number of milliseconds since FSUIPC was started.
It is the same as the value shown in the Log files.
ipc.execCalcCode(“code”) This executes the argument code using the WAPI
[Not WideClient] execute_calculator_code method.
N.B. To use this function, the FSUIPC WASM module must be
installed, and the WASM interface active in FSUIPC7.
ipc.execPreset(“presetName”, This executes the calculator code associated to the argument
param) presetName using the WAPI execute_calculator_code method.
[Not WideClient] Note that the preset name must be given as it appears in the
events.txt or myevents.txt file, not as appears un the drop-down
menus where undercores are replaced by spaces.
N.B. To use this function, the FSUIPC WASM module must be
installed, and the WASM interface active in FSUIPC7.
ipc.exit() This terminates the current Lua plug-in thread. For plug-ins using
the event library this is the only programmatic way of doing so, as
the registration of the event processing functions effectively keeps
the thread idling, waiting for those events, until the thread is forc-
ibly killed by the Kill control or by re-loading the same plug-in.
x = ipc.get(“name”) Retrieves a Lua value (any simple type -- i.e. numbers, strings,
booleans) previously stored as a Global by “ipc.set”. This
mechanism provides a way for a Lua plug-in to pass values on to
successive iterations of itself, or provide and retrieve values from
other Lua plug-ins.
With effect from FSUIPC version 4.958, in combination with
WideClient version 6.999z2, the ‘Globalness’ of these values
extends between Clients and Server in a WideFS network, so can
be used to communicate values and strings over the network
without resorting to user offsets. This only works if Server and
Clients are in the same workgroup and can be turned off at the
FSUIPC end by setting the parameter “WideLuaGlobals=No” in its
INI file [General] section.
Use of this should be sparing – the Windows Mailslot system is
used and may not cope with excessive use very well. Also note that
there is no backlog – the globals are only broadcast when being set
(by ipc.set), so anything set before a client is actually running
won’t be seen by it. Also the Network protocol used is not checked
– messages are not guaranteed to arrive. Retries, maybe by a
system of Acknowledgement values, are up to the plug-in and
would be advisable in any “mission-critical” application of this
facility.
3
Note that there are limits on the sizes for network Globalness: the
variable names must not be greater than 32 characters, and string
values should be no longer than 384 characters. Values outside
these limits do not participate.
State, x, y, cx, cy = This gets information about the current communal "Lua display"
ipc.getdisplay() Window (or “SimConnect Message Window” on P3D4), as used
by ipc.display by default. The values returned are:
[Returns only zeroes in State = 0 for no display, 1 for docked, -1 for undocked
WideClient]
x, y are the screen coordinates of the top left corner.
cx, cy are the width and height, respectively.
n = ipc.getHvarId(“name”) This gets the ID of the FS html variable identified by the name
given. These variables are H: <name>. You must provide the H:
part explicitly.
[Not WideClient]
The value returned is numeric in the range 0 to 65535, or nil if the
variable is not available.
N.B. To use this function, the FSUIPC WASM module must be
installed, and the WASM interface active in FSUIPC7.
n = ipc.getHvarName(id) This gets the name of the FS html variable identified by the id
value, a numeric in the range 0 to 65535. These variables are H:
<name>.
[Not WideClient]
The value returned is a string, or nil if the variable is not available.
To get all available HVars you can iterate from 0 upwards until nil
is returned.
N.B. To use this function, the FSUIPC WASM module must be
installed, and the WASM interface active in FSUIPC7.
n = ipc.getLvarId(“name”) This gets the ID of the FS local panel variable identified by the
name given. These variables are L: <name>. You can provide the
L: part explicitly or leave it out.
[Not WideClient]
The value returned is numeric in the range 0 to 65535, or nil if the
variable is not available.
N.B. To use this function, the FSUIPC WASM module must be
installed, and the WASM interface active in FSUIPC7.
n = ipc.getLvarName(id) This gets the name of the current FS local panel variable identified
by the id value, a numeric in the range 0 to 65535. These variables
are L: <name> , but the result provided is only the ,name> part,
[Not WideClient] without the L:
The value returned is a string, or nil if the variable is not available.
To get all available LVars you can iterate from 0 upwards until nil
is returned.
N.B. To use this function, the FSUIPC WASM module must be
installed, and the WASM interface active in FSUIPC7.
ipc.keypress(keycode) Sends the specified key press to FS (provided it has keyboard
ipc.keypress(keycode, shifts) focus). If the ‘shifts parameter is omitted a normal unshifted
keycode is sent and a press-and-release. The Advanced User’s
guide gives a list of keycodes and shifts.
ipc.keypressplus(keycode) Same as the ipc.keypress function, above, except that the
ipc.keypressplus(keycode, shifts) keypresses are still sent whilst FS is inside a menu dialogue, and
the following additional options are provided, according to the
ipc.keypressplus(keycode, shifts,
4
options) value of the "options" parameter:
0 or omitted = press-and-release, as for ipc.keypress
[Not WideClient] 1 = press key, not press-and-release
2 = release key, not press-and-release
To which optionally one or both of these can be added:
4 = change focus to FS before keystroke
8 = return focus to originally active window after keystroke (this
needs a previous or concurrent '4' option to get the active window
remembered).
ipc.lineDisplay(“string”) A variation on the ipc.display function, this also displays the given
ipc.lineDisplay(“string”, line) string value in FS, in a sizeable and undockable window entitled
“Lua display”, but in this case the maximum string is 255
characters, and any new line codes will be stripped out.
[WideClient okay, but display is
in FS, not on client PC]
This function provides line selection and scrolling effects,
controlled by the "line" parameter as follows:
line = 0 (Or omitted): Clears the display and puts this text
(if any) in the first line. Provide a null string ("") to
simply initialise the text buffers.
line > 0 Specifies the line number for this text, from 1 to 32
(max). Line 1 is the top line. Lines above this,
between it and the last line written, are cleared.
line < 0 Adds this text as another line in the list, following
the last one sent. The line parameter gives the
negative of the maximum line number to be used
(counting from 1, max 32), and if this line would
be placed there, the display is scrolled up one line
before it is added.
Note that with WideClient there is only one such window for all
Lua plug-ins. The last one wins! This also applies to direct
FSUIPC use, unless the ipc.setowndisplay function (see below) is
used to name, position and size an individual window for this
plug-in [Not on P3D4]
See also ipc.display and ipc.setowndisplay
Note that there are currently many issues
with the simconnect message display
functionality. It is recommended to use the
wnd display library for the time being.
ipc.log(“string”) Logs the string provided. The log entry goes to the FSUIPC log
gile unless either the Lua plug-in is being run in debug mode (Lua
Debug control), or Lua logging is enabled in the FSUIPC options.
In these two cases the log message goes to the Lua plug-in’s log
file instead.
ipc.macro("macroname") Executes the named Macro, named in the same format as you see
ipc.macro("macroname", parameter) in the FSUIPC assignment drop-downs. For example:
ipc.macro("PMDGquad: cutoff1")
executes the macro named "cutoff1" in the Macro file
"PMDGquad.mcro".
The optional parameter should be an integer between -32768 and
32767 (or 0 and 65535 for unsigned values).
5
Note that the facility can be used to execute other Lua plug-ins too,
for example:
ipc.macro("Lua display vals")
or, indeed, any of the Lua controls.
Note that when used in WideClient, the macro or Lua execution
occurs on the FS PC, not on the local client PC.
n = ipc.readDBL(offset) Reads the double floating point (64-bit) value at the given IPC
offset.
The offset can be specified in Lua format hexadecimal, e.g.
0x0AEC, or in decimal, or as a string e.g. “0AEC”.
n = ipc.readFLT(offset) Reads the single floating point (32-bit) value at the given IPC
offset.
The offset can be specified in Lua format hexadecimal, e.g.
0x0AEC, or in decimal, or as a string e.g. “0AEC”.
n = ipc.readDD(offset) Reads the 64-bit signed integer value at the given IPC offset.
The offset can be specified in Lua format hexadecimal, e.g.
0x0AEC, or in decimal, or as a string e.g. “0AEC”.
n = ipc.readLvar(“name”) This reads the current value of the FS local panel variable called
n = ipc.readLvarSTR(“name”) “name”. These are L: <name> values. You can provide the L: part
explicitly or leave it out.
[Not WideClient]
The value returned from readLvar is numeric, or nil if the
variable is not available, and from readLvarSTR will be a
string or nil.
6
x1, x2, x3 ... = 0x0AEC, or in decimal, or as a string e.g. “0AEC”.
ipc.readStruct(offset1,
valuelist1, offset2, The lists consist of one of more entries defining numbers and types
valuelist2, ...) of values, as ‘nTYPE’. Types supported are:
UB unsigned 8-bit byte
UW unsigned 16-bit word
UD unsigned 32-bit dword
SB signed 8-bit byte
SW signed 16-bit word
SD signed 32-bit dword
DD signed 64-bit value
DBL 64-bit double floating point
FLT 32-bit single floating point
STR string of ASCII characters (in this case the preceding number,
n, gives the length not a repeat count)
7
without resorting to user offsets. This only works if Server and
Clients are in the same workgroup.
Use of this should be sparing – the Windows Mailslot system is
used and may not cope with excessive use very well. Also note that
there is no backlog – the globals are only broadcast when being set
(by ipc.set), so anything set before a client is actually running
won’t be seen by it. Also the Network protocol used is not checked
– messages are not guaranteed to arrive. Retries, maybe by a
system of Acknowledgement values, are up to the plug-in and
would be advisable in any “mission-critical” application of this
facility.
Note that there are limits on the sizes for network Globalness: the
variable names must not be greater than 32 characters, and string
values should be no longer than 384 characters. Values outside
these limits do not participate.
n = ipc.setbitsUB(offset, mask) Sets those bits in the Byte (UB), Word (UW) or DoubleWord (UD)
n = ipc.setbitsUW(offset, mask) offset which correspond to those present in the Mask value.
n = ipc.setbitsUD(offset, mask) This is equivalent to the following where XX is UB, UW or UD:
n = ipc.readXX(offset)
n = logic.Or(n, mask)
ipc.writeXX(offset, n)
ipc.setbtncol(btn, r, g, b) This WideClient-only function is used with the ButtonScreen
facility. It changes the button colour for the depicted button
corresponding to the number given as 'btn' (0-287). Button number
[WideClient ONLY] 0 corresponds to "joystick 64, button 0" with 287 being "joystick
72 button 31".
This is not applicable to buttons denoted as "Toggle" buttons (T or
TN) in the ButtonScreen definition. See ipc.setbtnstate for those.
The colour to be set is specified by the values given for r (red), g
(green) and b (blue), each of which can range from 0 (none) to 255
(full).
ipc.setbtnstate(btn, state) These WideClient-only functions are used with the ButtonScreen
and facility. They change the button state (pressed or released) for the
button corresponding to the number given as 'btn' (0-287). Button
ipc.setbtnstateonly(btn, state) number 0 corresponds to "joystick 64, button 0" with 287 being
"joystick 72 button 31".
This is only applicable to buttons denoted as "Toggle" buttons (T
[WideClient ONLY] or TN) in the ButtonScreen definition.
A state value of 0 changes the state to "released" and also, in the
case of setbtnstate, sends a "button up" indication to FSUIPC if
the button was previously recorded as being pressed. Any non-zero
value sets the state to 'pressed' and also, in the case of setbtnstate,
sends a "button pressed" indication if it was recorded as released.
This facility is designed to be used to allow Toggle buttons to
correctly depict the current state of the option they control, even if
that state is changed by other actions, such another button screen,
keyboard, mouse or flight reloading.
Note that you should really only use this for true Toggle actions --
i.e. ones for which the programmed actions in FSUIPC are
different from Press and Release and have those actions occur
twice in succession does no harm. Where this isn't the case try
setbtnstateonly so that a single press does not result in a conflict
condition.
8
ipc.setdisplay(x, y, cx, cy) This changes attributes of the current communal "Lua display"
Window, if there is one displayed. This is the window used by
ipc.display function by default. The values set are::
[Dummy only in WideClient]
x, y give the screen coordinates of the top left corner.
cx, cy give the width and height, respectively.
These are in screen coordinates (within the Flight Sim host
window), but unless the Windows is undocked (by the user), in
ipc.setdisplay(units, x, y, cx, windowed mode the placement is limited by the size and position
cy)
of the FS window itself. With FSUIPC, the top left position will be
adjusted if possible to fix the desired width and height into the
docking area.
It is best to read the current values first, using ipc.getdisplay,
modify them and write them back. This will also ensure the
Window exists.
Note that there is ever at most only one such "Lua display"
window. This command operates on that even if it was instigated
by another Lua plug-in. On MSFS the display is actually the
“SimConnect Message Window” and that is shared with any other
SimConnect client program too.
Except on P3D4, the ipc.setowndisplay function (see below) can
instead be used to name, position and size an individual window
for this specific plug-in.
With the latest FSUIPC, an initial parameter “units” can be set to
SET_PCTS to provide the coordinates and sizes in terms of
percentages of the dimensions of the host MSFS screen. In this
case each parameter must be in the range 0-100. The adjustment of
position and size to fit the docking area also applies, as for when
screen coordinates are used.
The default is for MSFS screen coordinates, which is also selected
by SET_SCRN.
Note that an attempt to set percentage coordinates for an undocked
Window will be refused. There is actually a result of true or false
from this function which will indicate such a failure (as well as
percentage values out of range).
See also ipc.lineDisplay and ipc.display
Note that there are currently many issues
with the simconnect message display
functionality. It is recommended to use the
wnd display library for the time being.
ipc.setflag(flagnum) Sets the specified local Flag, 0-255. These flags are the same ones
that can be changed by the FSUIPC assigned controls "LuaSet",
"LuaClear" and "Lua Toggle".
[Not WideClient]
Test flags using the ipc.testflag function.
ipc.SetMenu(title, prompt, To create a SimConnect text menu.
table_of_item)
The prompt can be omitted for blank in that space, The title and
[Not WideClient]
prompt can also both be omitted for blank in both spaces, the
table_of_items is a lua string table containing up to 10 menu
entries.
See event.MenuSelect for notification on the selection made.
9
ipc.setowndisplay("title", x, y, Except on P3D4 this sets all further calls to ipc.display or
cx, cy) ipc.linedisplay to operate on a private Window, owned by this Lua
plug-in, with the title given. Note that the title is NOT optional.
[Not WideClient] The x, y values give the top left corner position within the FS
window in terms of a percentage of the window width and height
respectively, so that 50, 50 is dead centre. Similarly the cx, cy
In FSUIPC7 this is the same as values give the size in the same way, so that 25,25,50,50 would
ipc.setdisplay(SET_PCTS, x, y, give a centred window with half the size (in both directions) of the
cx, cy)
FS window (or screen in full screen mode).
The function can be used again to move, resize and/or re-title the
window -- the previous one is automatically closed but its contents
are retained.
Note that except on P3D4 the ipc.getdisplay and ipc.setdisplay
functions do not operate on this Window -- those functions are
purely for the communal Window "Lua Display". Additionally,
whilst it can be moved, resized and undocked by the user, any such
changes are not currently readable and no record is made of them
in any configuration file.
NOTE:.in MSFS the "title" parameter is ignored and the
function acts identically to
ipc.setdisplay(SET_PCTS, x, y, cx, cy)
10
n = ipc.togglebitsUW(offset, mask) (UD) offset which correspond to those present in the Mask value.
n = ipc.togglebitsUD(offset, mask)
This is equivalent to the following where XX is UB, UW or UD:
n = ipc.readXX(offset)
n = logic.Xor(n, mask)
ipc.writeXX(offset, n)
ipc.toggleflag(flagnum) Toggles (i.e. inverts) the specified local Flag, 0-255. These flags
are the same ones that can be changed by the FSUIPC assigned
controls "LuaSet", "LuaClear" and "Lua Toggle".
[Not WideClient]
Test flags using the ipc.testflag function.
ipc.writeDBL(offset, value) Writes the value provided as a double floating point (64-bit) value
at the given IPC offset.
The offset can be specified in Lua format hexadecimal, e.g.
0x0AEC, or in decimal, or as a string e.g. “0AEC”.
ipc.writeFLT(offset, value) Writes the value provided as a single floating point (32-bit) value
at the given IPC offset.
The offset can be specified in Lua format hexadecimal, e.g.
0x0AEC, or in decimal, or as a string e.g. “0AEC”.
ipc.writeDD(offset, value) Writes the value provided as a 64-bit signed integer value at the
given IPC offset.
The offset can be specified in Lua format hexadecimal, e.g.
0x0AEC, or in decimal, or as a string e.g. “0AEC”.
ipc.writeLvar(“name”, n) This writes to the FS local panel variable called “name”. These are
ipc.writeLvarSTR(“name”, “value”) L: <name> values. You can provide the L: part explicitly or leave it
out.
[Not WideClient]
If the variable is not currently available, nothing happens.
N.B. To use this function, the FSUIPC WASM module must be
installed, and the WASM interface active in FSUIPC7.
ipc.writeSB(offset, value) Writes the value provided as an 8-bit signed byte value at the given
IPC offset. The offset can be specified in Lua format hexadecimal,
e.g. 0x0AEC, or in decimal, or as a string e.g. “0AEC”.
ipc.writeSD(offset, value) Writes the value provided as a 32-bit signed integer value at the
given IPC offset.
The offset can be specified in Lua format hexadecimal, e.g.
0x0AEC, or in decimal, or as a string e.g. “0AEC”.
ipc.writeSTR(offset, “string”) Writes the string at the given IPC offset, either with the same
ipc.writeSTR(offset, “string”, length or extended or truncated to the length optionally specified.
length) The string will have a zero terminator added, so allow for this if
you don't specify a length. If it is extended it is with zeroes.
The string can contain any byte values, including zeroes. It is not
restricted to being ASCII. In this respect it can be considered as a
block of offsets, or a structure without named elements.
The offset can be specified in Lua format hexadecimal, e.g.
0x0AEC, or in decimal, or as a string e.g. “0AEC”.
ipc.writeStruct(offset, Writes multiple values from one or more groups of successive IPC
valuelist, ...)
11
for multiple groups: offsets, each starting with the one given explicitly.
ipc.writeStruct(offset1, The offset can be specified in Lua format hexadecimal, e.g.
valuelist1, offset2, 0x0AEC, or in decimal, or as a string e.g. “0AEC”.
valuelist2, ...)
The list consists of one of more entries defining numbers and types
of values, as ‘nTYPE’. Types supported are:
UB unsigned 8-bit byte
UW unsigned 16-bit word
UD unsigned 32-bit dword
SB signed 8-bit byte
SW signed 16-bit word
SD signed 32-bit dword
DD signed 64-bit value
DBL 64-bit double floating point
FLT 32-bit single floating point
STR string of ASCII characters (in this case the preceding number,
n, gives the length not a repeat count)
t = os.date("!*t")
ipc.writeStruct(0x023B, "1UB", t.hour,
"3UW", t.min, t.yday, t.year)
ipc.writeSW(offset, value) Writes the value provided as a 16-bit signed word value at the
given IPC offset.
The offset can be specified in Lua format hexadecimal, e.g.
0x0AEC, or in decimal, or as a string e.g. “0AEC”.
ipc.writeUB(offset, value) Writes the value provided as an 8 bit unsigned byte value at the
given IPC offset.
The offset can be specified in Lua format hexadecimal, e.g.
0x0AEC, or in decimal, or as a string e.g. “0AEC”.
ipc.writeUD(offset, value) Writes the value provided as a 32-bit unsigned integer value at the
given IPC offset.
The offset can be specified in Lua format hexadecimal, e.g.
0x0AEC, or in decimal, or as a string e.g. “0AEC”.
ipc.writeUW(offset, value) Writes the value provided as a 16-bit unsigned word value at the
given IPC offset.
The offset can be specified in Lua format hexadecimal, e.g.
0x0AEC, or in decimal, or as a string e.g. “0AEC”.
12
The Logic Library (also WideClient)
Note that the names of all the functions provided in the logic library begin with a capitalised letter. This is important.
It prevents Lua interpreter errors arising from the use of the reserved words “and”, “or” and “not”.
Note that all of these functions handle 32-bit unsigned values, no matter how the parameters are provided.
13
The Mouse Library (not WideClient)
This library provides some functions for manipulating the mouse, in order to access parts of add-on panels that no
other methods appear to reach!
It can also be used to do all sorts of fancy things in conjunction with the extensive mouse events detectable using the
event library. In particular, see the example plug-in supplied called "mrudder.lua".
x, y Windows screen coordinates, or 'absolute' position, relative to the top left of the top left-most screen.
xr, yr FS's window coordinates, relative to the top left position of its main window (not including title bar, menu
(if present) or borders (if present). If required, this pair can also be pointing to a position outside of the FS
window
xp, yp A position inside the FS window denoted by the percentage of its width across (xp, left to right) and down
(yp, top to bottom). This can only ever be in the FS window, values 0-100. The getpos function may return
other values when the mouse pointer is outside the window, but these cannot be used within the positioning
functions.
The percentage positions are useful in situations where you might resize the FS window, but the positions of
elements you wish to control stay correctly positions proportionally. The other methods would generally be better if
you use full screen all the time.
mouse.wheel(n) Turns the mouse wheel forward (+n) or back (–n) the
specified number of 'clicks'.
14
The EXT Library (also WideClient)
ext.focus(handle) This does its level best to make the identified program the
ext.focus(0) or ext.focus() current foreground program, receiving keystrokes and mouse
clicks. The program must be one started by ext.run or
ext.runif.
Using the function without a parameter, or 0, forces focus
back to FS or WideClient.
ext.position(handle, x, y, cx, Moves and sizes the top level Window of the named program.
cy, screen) The position can be on any attached screen (identified by
ext.position("name", x, y, cx, 'screen', with 0=default, and 1, 2, 3 ... being the numbers
cy, screen) shown by Windows monitor settings when using 'identify').
If the 'screen' parameter is omitted, the default screen is
where 'screen' can be omitted for assumed.
15
default or only screen. The x and y coordinates are for the top left corner, and the cx,
cy specify the width and height, and all four are in terms of a
percentage of screen width and height respectively, and so are
independent of actual screen size or resolution. For example
25,25,50,50 would position the window at half the screen's
size in both dimensions and in the dead centre.
The program can be identified in one of three ways:
* Handle: from ext.run, ext.runif or ext.gethandle.
* Name of the process (i.e. "program.exe")
* Title of the top-level Window. ("my window")
handle = ext.gethandle("name") This attempts to get an ext library type handle for the
specified process or Window title. Check the handle returned.
If it is 0 then the attempt failed.
The process can be specified as a program name (complete
with the .exe or whatever, but without any path detailed), or a
Window title. There may of course be no such process
running, or there may be more than one. In the latter case a
handle to the first one listed by Windows will be attached.
The handle can be used in any of the ext library functions
which can use a handle, but theyt won't necessarily work.
Since we don't actually "own" said process, there are limits to
what can be done. You'd need to experiment a little.
bool = ext.hasfocus() This tests whether a specific program currently has the focus
(or, more accurately, is the owner of the current foreground
window).
bool = ext.hasfocus(handle)
If no parameter is provided, it is a test for the flight sim
having focus. Otherwise you can provide a handle from the
bool = ext.hasfocus("progname") ext.run or ext.gethandle functions, or you can provide the
executable name for the program being tested.
handle, error = Runs the program specified by a full pathname, including the
ext.run("pathname") EXE or COM filetype (or whatever). If it needs command line
handle, error = parameters provide these as a separate string, as the second
ext.run("pathname", "command line parameter.
parameters")
Check the handle returned. If it is 0 then the attempt failed
and 'error' will contain the error number returned by
Windows, or, if negative, one of these:
–2 = memory problem assigning control block
–3 = bad string supplied, cannot use
Both can have up to four extra You can add up to four more parameters, selecting options
parameters giving options -- see from the following:
opposite.
EXT_HIDE to start the program hidden
EXT_MIN to start the program minimised
EXT_NRML to start it normally (defaulted anyway)
EXT_MAX to start the program maximised
EXT_LOW run at Low priority (using only idle time)
EXT_HIGH run at High priority
EXT_CLOSE close this automatically when FS (or
WideClient) closes
EXT_KILL terminate this forcibly when FS (or
WideClient) closes
16
EXT_FOCUS Transfer focus to the resulting top window,
if possible. (If this is omitted, focus will be
returned to the previous owner, probably
FS, even though the program will grab it
initially unless hidden).
handle, error = Uses the Windows Shell to execute or otherwise process the
ext.shell("pathname") program or file specified by a full pathname. If this needs
handle, error = command line parameters provide these as a separate string,
ext.shell("pathname", "command as the second parameter.
line parameters")
The normal action carried out will be 'open', bt others can be
specified using the EXT_ keywords in the extra parameters,
as described below. Of course not all options will be
applicable to all file types.
Check the handle returned. If it is 0 then the attempt failed
Both can have up to four extra and 'error' will contain the error number returned by
parameters giving options -- see Windows, or, if negative, one of these:
opposite. –2 = memory problem assigning control block
–3 = bad string supplied, cannot use
17
This is the default action.
EXT_EDIT Attempt to open an appropriate editor with
this file loaded.
EXT_EXPLORE Open the folder in Explorer
EXT_PRINT Attempt to print the file
EXT_FIND Attempt to open Explorer to find a file
EXT_PROPS Attempt to display the file's properties.
Note that not all files are susceptible to all of these.
Handles returned by ext.shell are not local to the current Lua,
but global for this FSUIPC or WideClient session, so can be
saved in Lua global variables (see ipc.get and ipc.set) and
that way passed among Lua plug-ins.
handle, error = ext.runif(...) This is identical to ext.run, above, except that the program is
not run if it is already running. In other words it's equivalent
to performing an ext.isrunning before an ext.run and
See ext.run for details bypassing the latter on a TRUE result.
If the program is not run because it is already running, the
handle is 0 and the error number is –1.
ext.size(handle, cx, cy, screen) Sizes the top level Window of the named program. The
ext.size("name", cx, cy, screen) position can be on any attached screen (identified by 'screen',
with 0=default, and 1, 2, 3 ... being the numbers shown by
Windows monitor settings when using 'identify').
where 'screen' can be omitted for
default or only screen.
If the 'screen' parameter is omitted, the default screen is
assumed.
The cx, cy specify the width and height in terms of a
percentage of screen width and height respectively, and so are
independent of actual screen size or resolution. For example
50,50 would make the window half the screen's size in both
dimensions.
The program can be identified in one of three ways:
* Handle: from ext.run, ext.runif, or ext.gethandle.
* Name of the process (i.e. "program.exe")
* Title of the top-level Window. ("my window")
ext.state(handle, state) Changes the current state of the top level window of the
ext.state("name", state) program identified by 'handle', started previously by an
ext.run or ext.runif call. The 'state' can be one of:
EXT_HIDE, EXT_MIN, EXT_NRML or EXT_MAX
The program can be identified in one of three ways:
* Handle: from ext.run, ext.runif, or ext.gethandle.
* Name of the process (i.e. "program.exe")
* Title of the top-level Window. ("my window")
Note that not all programs are susceptible to these commands.
bool = ext.sendkeys(handle, ...) This sends keypresses to the window associated with the ext
handle. To do this is has to transfer focus to that Window, so
expect it to popup. Focus will be returned to the previous
where for ... you can have any owner afterwards (e.g. FS).
18
number of pairs of parameters Note that not all handles will be associated with a Window --
denoting either: in particular those returned by ext.gethandle and ext.shell
virtual keycode, will often not be. In this case the result returned will be false.
shift code Otherwise it will be true, and the keystrokes wil be sent: but if
or "string",
the focus is not on a Window which can accept them, do not
shift code expect to see them!
The pairs of parameters can be mixed between keycode+shifts
and string+shifts as you need. The virtual keycodes are listed
on the next page, as are the shift codes.
The second of the pair for the last set can be omitted if no
shifts are required, as 0 is then assumed. However, if there is
more than one pair the intermediate shifts must be given, even
if 0.
bool = ext.postkeys(handle, ...) This posts keypresses to the window associated with the ext
handle. Posting keyboard messages in this way does not
require any change of focus, so may be more attractive on the
FS PC. However, this method does not work with many
programs. Best to try it first.
Apart from posting instead of sending, this function is the
same as ext.sendkeys, so please refer to the extra information
for that.
bool = ext.postmessage(handle, This is for the programmers among you. It sends the specified
Message, wParam, lParam) Windows message (which you'll need to look up the number
for) with the parameters given.
19
KeyCodes and Shifts
223 `¬¦ is top left, just left of the main keyboard 1 key
189 -_ is also in the top row, just to the right of the 0 key
187 =+ is to the right of 189
219 [{ is in the 2nd row down, to the right of the alpha keys.
221 ]} is to the right of 219
186 ;: is in the 3rd row down, to the right of the alpha keys.
192 '@ is to the right of 186
222 #~ is to the right of 192 (tucked in with the Enter key)
220 \| is in the 4th row down, to the left of all the alpha keys
188 ,< is also in the 4th row down, to the right of the alpha keys
190 .> is to the right of 188
191 /? is to the right of 190
The shifts value is a combination (add them) of the following values, as needed:
1 Shift
2 Control
4 Tab
8 not used
16 Alt (take care with this one—it invokes the Menu)
32 Windows key (left or right)
64 Apps Menu key (the application key, to the right of the right Windows key)
NOTE that this is different to previously documented shifts – the earlier list was in error, having ‘Tab’ at value 8 and a second ‘Alt’ at value 4.
20
The COM Library (also WideClient)
Note that this now handles both normal COM port serial transfers, whether via a USB serial adapter or direct via a
COM port, but also HID (Human Interface Device) transfers, normally related exclusively to USB connections.
Routine template Description
handle, rd, rdf, wr, initreport = This opens the HID device identified either by the VendorID
com.openhid(VID, PID, unit, and ProductID, or by names or partial names identifying the
repno)
same things. In the “vendor”, “product” form the string will
Or be used to match anywhere in the actual device details, so
handle, rd, rdf, wr, initreport =
“Widget” will match “American Widgets Inc”, as an example.
com.openhid(“vendor”, “product”, Numerical VIDs and PIDs must match exactly, and are
unit, repno) usually given in hexadecimal (0xXXXX). These can be found
from the Device Manager details in Windows, or by using
extra logging in FSUIPC or WideClient (see note at the end of
this section).
The unit parameter identifies one of several identical units,
counting from 0. The unit numbers are assigned in the order
in which Windows enumerates them, which probably depends
on how they are plugged in. This parameter, along with the
following one, can be omitted to default to unit 0 (okay for 1
unit), and Report #1 (the usual default).
The repno value identifies the default input report number to
be requested for the initial state.
As you can see, there are several returned values. You do not
have to use them all, of course.
The handle returned will be zero if the device could not be
opened.
The ‘rd’, ‘rdf’ and ‘wr’ values provide the device-defined
fixed sizes of input reports, SetFeature data, and output
reports, respectively. You should use these values to define
the size of data being read and written.
The ‘initreport’ value is a string of bytes providing the first
input report after opening. This gives you the initial state –
usually switch positions and the like.
For joystick type HID devices the additional data processing
facilities embodied in the following functions should be used.
The first three of these operate on Input Reports (length 'rd'):
com.gethidvalue
com.gethidbuttons
com.testhidbutton
com.gethidcount
handle = com.open("port", speed, This opens the serial comms port named "port" (e.g.
handshake) "COM1"), with settings:
Speed = baudrate, e.g. 115200 for VRInsight devices, often
4800 or 9600 for GPSs.
Handshake defines the protocol for controlling the flow:
0 = none
1 = RTS / DTR line levels
2 = XON / XOFF
3 = Both of the above
The port is always opened in 8-bit no parity mode.
The handle returned will be zero if the port could not be
opened. If the port is already opened by FSUIPC for use in its
handling of VRInsight devices, the com.open call will
succeed and be granted access to the same port.
com.close(handle) This simply closes the port represented by the given Handle.
It should always be used before the Lua program terminates.
n = com.connected(handle) Returns an integer relating the state of the HID device
identified by the handle ‘dev’ returned by the com.openhid
function. This is an integer from 0-3 as follows:
1 disconnected, no change from last query
[Not WideClient]
2 connected, no change from last query
3 now disconnected
4 now re-connected
Initially the device must be connected, as otherwise the
openhid would fail and you would not get a proper handle.
n = com.test(handle) Returns the number of bytes of data available to be read on
the port represented by the given Handle.
str, n = com.read(handle,max) Reads up to 'max' bytes from the port, returning them as a
str, n = com.read(handle,max,min) string in 'str' with the number actually read returned in 'n'.
str, n = com.read(handle,max,min, If the 'min' parameter is also given, this returns a null string
term) and n=0 until at least that minimum number of bytes are
available. It does not block waiting for them. If you specify -1
as the minimum then the terminating character ('term') must
be seen before the function returns a non-zero result, unless of
course the 'max' size is reached first.
The 'term' parameter specifies an ASCII value (0 to 255)
which is to be treated as a terminator for each block. This
character is included in the returned count and string.
Note that you can use the event library function, event.com
to perform reads and call your Lua back when there is data to
process. This can be more efficient and tidier than a program
which uses continuous loops to scan the input.
str, n = com.readfeature(handle, Reads the feature bytes from the HID device via the
repno) “GetFeature” call. The report ID to be used is given as
“repno”, or 0 if none are used.
The returned value gives the data returned by the device, with
the report ID in the first byte. “n” is zero if there was an error.
str, n = com.readreport(handle, Reads the input report bytes from the HID device via the
repno) “ReadInputReport” call. The report ID to be used is given as
“repno”, or 0 if none are used.
The returned value gives the data returned by the device, with
the report ID in the first byte. “n” is zero if there was an error.
str, n = com.readlast(handle, This is the same as com.read, above, but with a fixed block
len) size assumed (given by 'len'), and with all currently available
str, n, discards = blocks discarded except the last, which is supplied.
com.readlast(handle, len)
The number of discarded blocks is returned as a third result
should it be wanted.
This function might be useful in polling situations where the
rate at which data arrives might exceed the polling rate or
capabilities of the Lua system. HID joysticks scanning is a
prime example. Rather than process older records and get a
larger unwanted lag that is necessary it enables an efficient
way of only processing the most recently received state.
n = com.write(handle, "string") Writes the string to the port. If the length parameter is
n = com.write(handle, "string", provided, the string is either extended by zero bytes to that
len) length, or truncated, whichever is the more appropriate.
The returned value gives the number of bytes actually sent (or
at least, placed in the buffer).
n = com.writefeature(handle, Writes the string to the HID device via the “SetFeature” call.
“string”, len) The length should equal the ‘wrf’ value returned by the
com.openhid function.
The returned value gives the number of bytes actually sent
(or at least, placed in the buffer).
n = com.gethidvalue(handle, If the open HID device is a joystick type, this can be used to
"axis", str) read any analogue (axis) or POV value it might return. The
n1, n2, ... = 'str' parameter refers to the data, of length 'rd' (see
com.gethidvalue(handle, "axis", com.openhid), returned by com.read or com.readlast,
str) The "axis" parameter is one of the following axis names:
(up to 16 results) "X", "Y", "Z", "R" (or "RZ"), "U" (or "RX"), "V" (or "RY"),
"POV" (or "HAT"), "Rudder", "Slider", "Dial", "Wheel", or
"Throttle".
A HID device might support any number of each of these.
The com library supports up to 16 axes of each of these types.
Alternatively you can give a one-byte "usage" code for non-
standard analogue values, ones not even supported by
DirectInput.
Use the com.gethidcount function to retrieve the numbers of
any of the named axis types and the maximum value it can
return.
N = com.gethidbuttoncount(handle) Returns the number of buttons on the optn HID device.
X = com.gethidbuttons(handle, If the open HID device is a joystick type, this can be used to
str) read the state of all the buttons it might support, up to a
maximum of 256 buttons. The 'str' parameter refers to the
data, of length 'rd' (see com.openhid), returned by com.read
X1, X2, ... =
com.gethidbuttons(handle, str)
or com.readlast,
X = com.testhidbutton(handle, If the open HID device is a joystick type, this can be used to
btn, str) test the state of 256 buttons, numbered 0-255. The 'str'
parameter refers to the data, of length 'rd' (see com.openhid),
returned by com.read or com.readlast,
The return is true or false.
n, max = com.gethidcount(handle, This returns information about the analogue value (axis)
"axis") named. 'n' gives the number of such axes supported (which
may be 0) and 'max' gives the maximum value they can
return.
The axis names which can be used are
"X", "Y", "Z", "R" (or "RZ"), "U" (or "RX"), "V" (or "RY"),
"POV" (or "HAT"), "Rudder", "Slider", "Dial", "Wheel", or
"Throttle".
The com library supports up to 16 of each of these axis types.
You can get a list of all HID devices connected to your PC, as well as their comings and goings, by setting the Custom log value
(available from the Log menu) to x200.
To do the same in WideClient, change the Log= parameter in the [user] section to “Log=HID”.
The Event Library (also WideClient, but not for all events, as noted)
Events allow you to build plug-ins which rather than running continuously in a loop in order to interrogate things
can be set to stay loaded but dormant waiting for those things to occur. Almost anything which can be done in a
continuously running loop can be done more tidily and pleasingly using events instead.
Events rely on you specifying two things: what it is you want to monitor, and which pre-defined function, in your
program (or called up by Require) you want to run when the monitored event occurs. There is no specific
restriction on how many different events you can monitor in one program, nor how many times you can trap the
same event for different functions. But note that, whilst FSUIPC does keep track of separate events, it does not
queue multiple identical events. If a button is pressed 20 times before you process it, you only see it once. Therefore
if you are monitoring things which can happen repetitively you will need to keep your processing short enough if
you hope to catch them all.
The function name provided as a string in the Lua event function calls can now be functions in tables. This enables
functions in Modules, brought in by the require function, to be used for event processing, because Modules so
enabled provide tables of functions (and other values) for access in the current program. The format of the function
reference string must be <table>.<function>, so if the Module is named (or equated to) "M", say, then function "fn"
inside it would be referred to as "M.fn" in the event function. (The alternative form "M[fn]" is not allowed). The
facility is actually extended to handle tables within tables, to no set limit other than the entire string name must be
less than 64 characters (between the "").
A Lua plug-in with any events being monitored stays running (or rather dormant, awaiting those events) until it
either explicitly terminates (via ipc.exit), fails through some error, or cancels its last outstanding event monitor.
event.intercept(offset, “type”, Executes the named function (named as a string, “...”), which
“function-name”) must be defined before this line, when the specified FSUIPC
event.intercept(offset, “STR”, offset is written to by any FSUIPC or WideFS client
length, “function-name”) application or internal module or gauge. The write is
intercepted—i.e. prevented from actually affecting the
specified offset. It is then up to the intercepting Lua function
Your processing function: to decide whether to write the (possibly modified) value to the
function-name(offset, value) same offset or not. If it does it must actively do it using the
appropriate ipc.writeXXX() function as described earlier.
[Not WideClient]
Note that the offset write is only intercepted if it is explicitly
addressed in the request from the FSUIPC client. If the client
writes to the offset as part of a larger area, with an earlier
starting point, the intercept will not occur. However, for all
practical applications this should not present any problems.
The offset can be specified in Lua format hexadecimal, e.g.
0x0AEC, or in decimal, or as a string e.g. “0AEC”.
The type is one of these:
UB unsigned 8-bit byte
UW unsigned 16-bit word
UD unsigned 32-bit dword
SB signed 8-bit byte
SW signed 16-bit word
SD signed 32-bit dword
DD signed 64-bit value
DBL 64-bit double floating point
FLT 32-bit single floating point
STR string of ASCII characters
event.mouselefttrap("function-
name") This is identical to the event.mouseleft function above except
that the action of the mouse is trapped -- it is not passed on to
event.mouselefttrap(method, FS or other programs further down the chain.
"function-name")
If you use this facility and you want to pass on the action in
Your processing function: some circumstances you would need to use the mouse.click
function to pass it down.
function-name(x, y, move, flags)
event.mousemiddle("function- This causes the function to be called whenever the middle
name") mouse button is pressed or released whilst within the FS
event.mousemiddle(method, window which has the mouse focus.
"function-name")
The parameters and results are all as described for
event.mouseleft, above.
Your processing function:
function-name(x, y, move, flags)
event.mousemiddletrap("function-
name") This is identical to the event.mousemiddlefunction above
except that the action of the mouse is trapped -- it is not
event.mousemiddletrap(method, passed on to FS or other programs further down the chain.
"function-name")
If you use this facility and you want to pass on the action in
Your processing function: some circumstances you would need to use the mouse.click
function to pass it down.
function-name(x, y, move, flags)
event.mousemove("function-name") This causes the function to be called whenever the mouse is
event.mousemove(method, moved whilst within the FS window which has the mouse
"function-name") focus.
The parameters and results are all as described for
Your processing function:
event.mouseleft, above.
event.mouserighttrap("function-
name") This is identical to the event.mouseright function above
except that the action of the mouse is trapped -- it is not
event.mouserighttrap(method, passed on to FS or other programs further down the chain.
"function-name")
If you use this facility and you want to pass on the action in
Your processing function: some circumstances you would need to use the mouse.click
function to pass it down.
function-name(x, y, move, flags)
event.mousewheeltrap("function-
name") This is identical to the event.mousewheel function above
except that the action of the mouse is trapped -- it is not
event.mousewheeltrap(method, passed on to FS or other programs further down the chain.
"function-name")
If you use this facility and you want to pass on the action in
Your processing function: some circumstances you would need to use the mouse.wheel
function to pass it down.
function-name(x, y, move, flags)
event.offset(offset, "type", Executes the named function (named as a string, “...”), which
"function-name") must be defined before this line, when the specified FSUIPC
event.offset(offset, "STR", offset changes
length, "function-name")
The function is also executed initially, when the plugin is first
run, in order to initialise things. This saves using an explicit
Your processing function: call to do the same.
function-name(offset, value) The offset can be specified in Lua format hexadecimal, e.g.
0x0AEC, or in decimal, or as a string e.g. “0AEC”.
The type is one of these:
UB unsigned 8-bit byte
UW unsigned 16-bit word
UD unsigned 32-bit dword
SB signed 8-bit byte
SW signed 16-bit word
SD signed 32-bit dword
DD signed 64-bit value
DBL 64-bit double floating point
FLT 32-bit single floating point
STR string of ASCII characters
The length parameter is omitted (or ignored) except for the
“STR” type, where it can optionally define the string length
(max 256). If the length is omitted for the STR type then the
string will be zero terminated and will have a maximum
length of 255 not including the final zero.
The function is called with the offset, so that the same
function can, if desired, be used for more than one such event,
and also the current (new) value in that offset. This will be a
Lua number for all types except STR where it will be a string.
event.offsetmask(offset, mask, Executes the named function (named as a string, “...”), which
"type", "function-name") must be defined before this line, when the specified FSUIPC
offset changes only in the bits set in the mask value -- i.e. the
value given by logic.And(offsetvalue, mask) changes.
Your processing function:
function-name(offset, value)
The function is also executed initially, when the plugin is first
run, in order to initialise things. This saves using an explicit
call to do the same.
The offset can be specified in Lua format hexadecimal, e.g.
0x0AEC, or in decimal, or as a string e.g. “0AEC”.
The type is one of these:
UB unsigned 8-bit byte
UW unsigned 16-bit word
UD unsigned 32-bit dword
SB signed 8-bit byte
SW signed 16-bit word
SD signed 32-bit dword
event.param(“function-name”) The calls the declared function when the ipcPARAM variable
for this plug-in is changed externally to the plug-n code. That
is by use of the LuaValue <name-of-plugin> control. If this
Your processing function: is assigned to an Axis in FSUIPC axis assignments it provides
function-name(param) the value from that axis, otherwise it is the parameter given in
the button or key assignment.
The value 'param' provided as the parameter to the called
function is also stored in the ipcPARAM variable.
Note that if the LuaValue control for this plug-in is assigned
to multiple sources there is no way to distinguish how the
parameter value arose.
event.sim(event-type, “function- This executes the named function when a specific type of
name”) event occurs in the Simulator. The types currently available
are:
Your processing function: CLOSE: the flight simulator is closing down (or, in the case
function-name(event-type) of WideClient, WideClient is closing down or the
simulator is closing down (you can’t tell which).
This gives the plug-in a chance to tidy things up before
exiting tidily with an ipc.exit call. Note that if the tidy-
up involves logging or sending stuff to a device, you
may need an ipc.sleep call before the exit in order to
allow those things to clear.
FLIGHTLOAD: a flight has just been loaded.
FLIGHTSAVE: a flight has just been saved
AIRCRAFTCHANGE: the aircraft has been changed
ANY: any of the above—use the parameter to determine
which.
Note that the ANY method is unlikely to catch all
events. Only one event can be signalled at a time, but
loading a flight often means an aircraft change too.
ANY would only catch one of those. Similarly a flight
save often occurs just before FS closes. Only one of
those might be seen. Therefore, if catching everything is
crucial, it is best to use the individual events.
event.textmenu(type, "function- This event instructs FSUIPC7 to intercept text and menu calls
name" into SimConnect and send the details on to WideClient.
Your processing function:
Note that menus via SimConnect are currently not working
Function-name(type, colour, with MSFS.
scroll, delay, id, n, msgs)
At present it is not possible to suppress the display of menus
on screen. Well, it can be done, but then SimConnect never
sends the user selection back to the application. You can have
the menu made smaller and moved top left, maybe out of the
way a bit.
This library provides full facilities for reading inputs from Go-Flight devices and writing to their displays. It is
currently programmed to cover the following devices ("models". note the model code, which is used when
addressing the model type in all functions, including the event.gfd function already described.
* The TPM is currently not recognised because of missing support in GFDev.DLL, and no information available on
its data formats.
As with FSUIPC's GoFlight button support, you need GFDev.dll installed on the FS PC to use this library.
Normally it is installed for you by the GoFlight installer—in this case it should be in the same folder as your
GFconfig program, probably in Program Files\GoFlight. When installed correctly, FSUIPC should be able to find it
automatically, via the GFconfig installed registry entry. If not, you will have to place GFDev.dll in an accessible
place. For FSX this can be the FSX Modules folder. For FS9 and before do NOT, repeat NOT, put it into the
Modules folder or you will crash FS. Try the main Windows folder.
The list above is based on the latest version of GFDev.dll available at the time of publication: 1.92.0.8, dated 30th
November 2009. The latest version I have is always available from my Support Forum.
Another important point to know when trying to operate GoFlight displays and indicators, whether using GFdisplay.exe or these
new Lua facilities, is that (at present at least), the GoFlight drivers do not co-operate well with other using programs. By all
means you can share access to knobs and switches, but the GF drivers seem to want to write to all displays and indicators on a
module even if only configred to use some of them. For each GoFlight unit you may have to make the choice: GF driver or
Lua/FSUIPC plug-in.
The full reference to the functions available in the Library is tabulated on the next page.
The GoFlight coverage may be revised from time to time. The test program (gfdDisplay.lua) supplied with this
package will show you what is covered. If you run this test program (i.e. assign a keypress or button to the drop-
down entry "Lua gfddisplay.lua" and use it), this is what you should expect, with a descriptive display in a "Lua
display" window on screen:
n = gfd.Buttons() Returns the state of all buttons supplied by the last call to
or, for devices with more than 32 gfd.GetValues, described below. The states of up to 32
'buttons' (switch inputs really) or 64 buttons or switches are provided, and these are
as on the GFDIO: represented by one bit each in the returned values. Bit 0 (2^0,
n1, n2 = gfd.Buttons() worth 1) is the first button, bit 1 (2^1, worth 2) is the second,
and so on. When two resluts are read the second contains
buttons 32 to 63.
gfd.ClearLight(model, unit, id) This simply turns off the indicator light identified by the id
or, for multi-coloured units: number, on the specified model and unit.
gfd.ClearLight(model, unit, id, For multi-coloured indicators other than the GF-WP6 you
1) should use the second form. For example, the gear LEDs on
the LGT would have 'ids' 1, 2 and 3 using the second form.
n = gfd.GetName(model) This returns the string name of the device of type 'model'. For
instance, the name of the model type GFMCPPRO is
"GFMCPPRO".
gfd.GetValues(model, id) This obtains all of the current input values from the identified
device. These values are subsequently accessible using these
separate functions:
gfd.Buttons() gfd.Selector(id)
gfd.Dial(id) gfd.TestButton(id)
gfd.Lever(id)
n = gfd.Lever(id) Returns the input value from the lever axis identified by 'id'
(0–7) in the input data supplied by the last call to
gfd.GetValues, described above.
n = gfd.ReadLights(model, unit) This reads the state of all the indicators on the specified
module, if this is actually possible on this module. Indicators
are numbered 0 to 31, with 0 being 2^0, worth 1 and so on.
If there is an error the value returned will be negative, as
follows:
-1 = unknown model
-2 = not a connected unit
-3 = indicator reads not supported on this module
Note that some versions of the LGT2 and RP48 modules
(notably the "mouse edition" of the latter) have firmware
deficiencies which cause the return here to be always zero.
n = gfd.Selector(id) Returns the numeric position of the selector switch (multi-
position switch) identified by 'id' (0–7) in the input data
supplied by the last call to gfd.GetValues, described
above.
gfd.SetBright(model, unit, n) This sets the unit's display and indicator brightness, n=0 being
off and n=15 being brightest.
gfd.SetDisplay(model, unit, id, This attempts to write the given text (truncated if necessary)
"display text") to the display identified by the id number, on the specified
model and unit.
gfd.SetColour(model, unit, id, n) This is currently only supported for the GF-WP6,
or and pre-sets the colour of indicator number 'id' either
to the pre-determined colour 'n' (0-7, see below), or
gfd.SetColour(model, unit, id, red, to the colour represented by separate red green and
green, blue)
blue values, each one being a value from 0 - 100.
gfd.SetLight(model, unit, id) This simply turns on the indicator light identified by
or, for multi-coloured units: the id number, on the specified model and unit.
gfd.SetLight(model, unit, id, val) For multi-coloured indicators other than the GF-WP6
you should use the second form. For example, the
gear LEDs on the LGT would have 'ids' 1, 2 and 3
using the second form, with "val" set as follows:
1 = red, 2 = green, 3 = amber
For the GF-WP6 you can pre-set the colour using
gfd.SetColour, above.
gfd.SetLights(model, unit, on, off) This sets selected indicator lights on or off, on the
specified model and unit.
The 'on' and 'off' parameters are masks to determine
those indicators to be turned on (bits set in 'on') and
those to be turned off (bits set in 'off') Indicators not
referenced by bits in either mask are unchanged.
Indicators are numbered 0 to 31, with 0 being 2^0,
worth 1 and so on. These numbers correspond to the
indicator ids used in SetLight and ClearLight.
n = gfd.TestButton(id) Returns true or false depending on the button/switch
setting (0–63) in the input data supplied by the last
call to gfd.GetValues, described above.
The Wnd Library
wnd.title(w, “new title”) Changes the title for the already opened window.
bool = wnd.textcol(w, 0xRGB) Sets the text colour of window w. Returns 'true' if
okay, or 'false' if window w doesn't exist.
The colour is given as 3 hexadecimal digits, 0x000 to
0xFFF, with the digits representing the amount of
Red, Green and Blue in 16 steps. Thus 0x000 is
black and 0xFFF is white.
The text colour applies text drawn from then on,
until changed. You can mix text colours on screen.
bool = wnd.font(w, face, size) Sets the text font details. Returns 'true' if okay, or
or 'false' if window w doesn't exist.
bool = wnd.font(w, face, size, options) The 'face' is one of
WND_ARIAL default
WND_TIMES Times New Roman
WND_COURIER Courier New, fixed space
The size is usually given in points, ranging from 4.0
to 300.0, default 12.0, but you can have it computed
automatically to provide n lines between the current
line and the end of the current Window. For the latter
use –n for the size, where n is the number of lines.
The options can be any mix of these (add them
together):
WND_BOLD, WND_ITALIC, WND_UNDER,
WND_STRIKE.
The font details apply for text drawn from then until
the font is changed again, so any mix can be used in
one window.
EXAMPLE
This small Lua plug-in, saved as, say, "showtext.lua" in the same folder as WideClient, is used on my own system
instead of ShowText.exe, to show the Radar Contact menu:
A much more advanced example of the power of this library, along with functions from the ext library, is included
with the latest releases of WideFS and WideClient. An assortment of Windows showing data from different sources
can be handled and selected by FSUIPC assignments using the package provided. A separate document explaining
things is included.
The Display Library (WideClient only, added at version 6.895)
Here's an example of such a display, this one created using the supplied example 'MyDisplay.lua":