Device Handling
In this section, the explanation will cover how fsmapper deals with flight sticks and custom control devices.
fsmapper provides a Device
object to abstract various devices, including those supported by the OS and custom-built devices, for unified handling.
Users generate a Device
corresponding to the desired device using mapper.device()
for each device they want to use.
Below is an example of opening a Direct Input game controller device, which was also mentioned in the Tutorial.
device = mapper.device{
name = 'Tutorial',
type = 'dinput',
identifier = {index = 1},
modifiers = {},
}
The argument for mapper.device()
is a table in associative array format, where each key-value pair of the associative array represents an actual argument. Here's a brief overview of each key in the table.
Key | Description | Requirement |
---|---|---|
name | User-assigned name for the Device object | REQUIRED |
type | Type of the device | REQUIRED |
identifier | Information for device identification | REQUIRED |
options | Option parameters for device opening | optional |
modifiers | Event modifier | optional |
Further, we'll delve into the specifics of the values to be specified in this argument and other essential aspects to know for manipulating devices.
Device Type
fsmapper uses pluggable driver modules to handle device-specific operations and absorb differences between devices. The type
parameter for mapper.device()
specifies the device type, i.e., which driver to use.
fsmapper comes with the following built-in drivers.
Type Name | Description |
---|---|
dinput | Game devices supported by DirectInput. This refers to devices listed in the USB Game Controllers found in the control panel, i.e. the devices listed in joy.cpl . |
simhid | Input/output devices that support the SimHID protocol. The SimHID protocol is adopted by controllers like SimHID G1000 that I've DIY'd. |
The interpretation of the identifier
and options
parameters is performed within each driver.
The meaning of the values varies depending on the device type.
The identifier
parameter specifies information necessary for the driver to identify the actual device.
For example, for a dinput
device, it might specify the product name or GUID, while for a simhid
device, it might specify the virtual COM port name.
The 'options' parameter is used to convey driver-specific optional information.
For detailed specifications on what to specify in the identifier
and options
parameters for built-in drivers, please refer to the DirectInput Game Device Specification and the SimHID Device Specification.
For devices provided by plugin modules, refer to the description of those respective modules.
Device Unit
Device Unit refers to the constituent elements of devices with changing states, such as buttons or analog axes on a joystick. Each Device Unit owns attributes including Name, Direction, Value Type, Precision, Value Range.
-
Name
Name corresponds to the ID of each Device Unit, and the naming convention depends on the device type. -
Direction
Direction indicates whether it is Input or Output, signifying whether the state is obtained from the PC or if the state can be altered by the PC.
Device Units of the Input type notify changes in state to the fsmapper system as Events. -
Value Type
Value Type can be Absolute or Relative. Absolute refers to instances where the value of the Device Unit directly corresponds to its position, such as analog axes on joysticks. Relative describes cases like a mouse, where the change in value represents the Device Unit's value. -
Precision
Precision signifies the precision of the Device Unit's state value, represented by either a 32-bit integer or a 64-bit floating-point number. -
Values Range
Value Range indicate the range within which the Device Unit can express values.
The attributes of Device Units corresponding to constituent elements of actual devices vary depending on the device type.
For devices supported by built-in drivers, refer to the DirectInput Game Device Specification and the SimHID Device Specification.
For devices provided by plugin modules, refer to the description of those respective modules.
For Input type Device Units, observing the events generated while manipulating the unit with Show Events and Messages
enabled in the Message Console can aid in understanding the specifications.
Event Modifier
Event Modifier is a mechanism that determines how the state changes of a Device Unit are translated into specific events.
There are three types of Event Modifiers: raw
, button
, and incdec
.
You can specify which modifier to use in the modifiers
parameter of mapper.device()
.
-
raw
This is the default modifier. It triggers achange
event every time the value of the Device Unit changes. The Event Value is directly set as the value of the Device Unit. -
button
This modifier is intended for application to Device Units that can be represented by binary values, such as buttons. Its basic functionality is to generate adown
event to indicate the transition from OFF to ON and anup
event to indicate the transition from ON to OFF.
By specifying in themodparam
parameter, the modifier can trigerdoubleclick
andsingleclick
event to support double-click functionality, trigger alongpress
event when held for an extended duration, or trigerfollow_down
orfollow_up
events to indicate the passage of time afterdown
orup
events occur.
Furthermore, it can be used to specify behaviors similar to key repetition.This modifier can also be employed to enable binary functionality for Device Unit that inherently possess continuous quantities like analog axes.
-
incdec
This modifier is intended for application to Device Units that operate on relative values. It generates anincrement
event when the change is positive and adecrement
event when it is negative. The Event Value represents the absolute value of the Device Unit.
The modifiers
parameter of mapper.device()
specifies the definition of modifiers to apply to each Event Modifier using an array, similar to this code snippet in the sample script.
Here are explanations for each key-value pair within the table representing the definition of a modifier.
Key | Type | Description |
---|---|---|
name | string | Specifies the name of the Device Unit targeted by the modifier. If an Event Modifier is simultaneously defined for the class associated with the Device Unit specified by this parameter, the Event Modifier specified by the name takes precedence. |
class | string | Specifies when applying the same modifier to multiple Device Units with similar characteristics. It specifies one of the following: binary for units with binary value ranges, absolute for units with absolute value ranges, or relative for units with relative value ranges. |
modtype | string | Modifier type. It specifies eather of raw , button , or incdec |
modparam | table | Options specific to the modifier. For detailed information, refer to the Event Modifier Specification. |
Event IDs Table
The necessary Event IDs of Input type Device Units required to define Event-Action mappings can be obtained by referencing the table returned by the Device:get_events()
method.
This table stores Event IDs under the names [Device-Unit-Name].[Event-name]
.
You can register Actions for Events triggered by the Device Units as follows.
device = Device{
name = "SimHID G1000",
type = "simhid",
identifier = {path = 'COM3'},
modifiers = {
{class = "binary", modtype = "button"},
}
}
local events = device:get_events()
mapper:set_primary_mappings{
{
event = events.SW1.down,
action = msfs.mfwasm.rpn_executer('(>K:AP_MASTER)')
}
}
Output Unit IDs Table
You can alter the state of Output type Device Units using the native-actions returned by the Device:send()
method or the Device:sender()
method.
Both methods require specifying an integer value, known as the Output Unit ID, to identify the Device Units.
You can obtain the Output Unit ID by referencing the table returned by the Device.get_upstream_ids()
method, where the Output Unit ID is stored with the Device Units name as the key.
Here's how you can modify the state of Output type Device Units.
device = Device{
name = "SimHID pannel",
type = "simhid",
identifier = {path = 'COM4'},
}
local ids = device:get_upstream_ids()
device:send(ids.LandingGearLeverIndicator, 1)
Lifecycle of Device object
Device
object handling for device operations remains active until either Device:close()
is called or until the object is deleted by garbage collection (GC).
This implies that during device manipulation and while needing to receive events from the device, precautions must be taken to prevent the Device
object from being targeted by GC.
Especially when dealing solely with Input type Device Units, situations where objects or functions managed by fsmapper like Event-Action mappings or Views bind to the Device
object are less likely.
This is why in the code samples provided in this documentation, the Device
object is bound to a global variable.
Supporting Custom Devices
Creating a plugin driver module enables handling devices other than the built-in Device Types. For more details, refer to the Plugin SDK.