MonnieRock, on 28 December 2012 - 01:07 AM, said:
Hello Everyone,
I use the Thrustmaster Warthog HOTAS and Saitek Pro Combat Pedals.
Have always used a stick setup since starting Mech "Piloting"
Last time I looked in the mech cockpit, there are joysticks. Not a mouse
My setup is working pretty good with some cfg editing.
Two wishes:
1) Analog for legs
2) 1:1 for torso. Example:So when you release joystick and it snaps to center, so would your torso.
Thank you,
Monnie
hello
for pts 2 .. you can do this
i use this script on target software for the thrustmaster warthog and it's doing it well => use the flaps selector for choice => 1:1 / autocenter / incremental :
//**************************************************************************
// UNOFFICIAL MECHWARRIOR JOYSTICK SUPPORT
// - For the Thrustmaster Warthog
//
//
// Written by Jason 'Crescent Fresh' Knobler
// (
http://mwomercs.com/...crescent-fresh/)
//
// MechWarrior Online Joystick -> Mouse/Keyboard override
//
//**************************************************************************
include "target.tmh"
float fJOYAXIS_LIMIT = 32767.0;
float fDEFAULT_SENSITIVITY = 10.0;
define UPDATE_RATE 20 // In miliseconds
int g_iAxisXDir; // X-Axis input direction. '-1' = inverted X axis; '1' = normal X axis
int g_iAxisYDir; // Y-Axis input direction. '-1' = inverted Y axis; '1' = normal Y axis
int g_bIsShutdown; // While true, Warthog throttle considers the mech shutdown, and must use Throttle[EORIGN] to power on.
// While false, Warthog thottle considers the mech powered up, and must use Throttle[EORMOTOR] to shut down.
float g_fSensMod; // Sensitivity modifier on FC Throttle.
int g_iSlugStage; // What stage [1-5] on how to apply procedural sensitiviy. Indicated by LED lights.
float g_fDeadZone; // User setting centering deadzone variable
struct sMWOAxis
{
//
// All the below data members belong to each X and Y axis
//
float fJoy; // The basic (converted) input value from the joystick
float fJoyPrev; // 'fJoy's previous value in the last update
int iMouse; // The emulated, absolute coordinate of the mouse
float fSlugPerc; // Procedural sensitivity that gains as input persists when in 'JOYSTATE_SLUGGISH'
int bSnapDir; // Determines whether the joystick is moving away or towards the center when in 'JOYSTATE_SNAP' state. [1 == away; 0 == centering]
int bHasPulseCenter;// Used in 'JOYSTATE_ABSOLUTE' to determine when to center torso
}
define AXIS_X 0
define AXIS_Y 1
define NUM_AXIS 2
sMWOAxis g_AxisData[NUM_AXIS]; // Stores per axis data used to manipulate raw joystick input (X and Y axis)
define SLUG_INCREMENTS 0.01 // Sluggish inc/dec amount per stage. Defaults at stage/LED '3'
define SLUG_DEFAULT_STAGE 5
//////////////////////////
// JOYSTICK STATES
// - NORM: Simply taking raw joystick values and converting them 1:1 to "MWO Units".
// - SLUGGISH: Over a specified duration, a linearly increasing percentage of the input is applied. This resets anytime the joystick is centered.
// - SNAP: Input motions moving away from joystick center are accelerated, and moving back towards center are slowed.
// - ABSOLUTE: The current input of the joystick maps directly to the yaw/pitch of the torso
//
// NOTE: All joystick states can be tweeked by applying a global sensitiviy modifer using Throttle[THR_FC].
//////////////////////////
define JOYSTATE_NORM (1 << 0) // = 1
define JOYSTATE_SLUGGISH (1 << 1) // = 2
define JOYSTATE_SNAP (1 << 2) // = 4
define JOYSTATE_ABSOLUTE (1 << 3) // = 8
// The negates of the states above. (no '~' operator?)
define JOYSTATE_NORM_OFF 4294967294 // = ~JOYSTATE_NORM
define JOYSTATE_SLUGGISH_OFF 4294967293 // = ~JOYSTATE_SLUGGISH
define JOYSTATE_SNAP_OFF 4294967291 // = ~JOYSTATE_SNAP
define JOYSTATE_ABSOLUTE_OFF 4294967287 // = ~JOYSTATE_ABSOLUTE
int g_iJoyStates; // A bitmask to represent what JOYSTATE_*'s are enabled
int InitAxis(int iIndex)
{
g_AxisData[iIndex].fJoy = 0.0;
g_AxisData[iIndex].fJoyPrev = 0.0;
g_AxisData[iIndex].iMouse = 0;
g_AxisData[iIndex].fSlugPerc = 0.01;
g_AxisData[iIndex].bSnapDir = 0;
g_AxisData[iIndex].bHasPulseCenter = 0;
}
// Program Startup
int main()
{
if(Init(&EventHandle)) return 1; // declare the event handler, return on error
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Initialization code is below:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
g_iAxisXDir = 1; // X-Axis defaults to NOT inverted
g_iAxisYDir = -1; // Y-Axis defaults to inverted
g_iJoyStates = JOYSTATE_NORM;
// Start, assuming mech is not shutdown
g_bIsShutdown = 0;
g_fSensMod = fDEFAULT_SENSITIVITY;
g_iSlugStage = SLUG_DEFAULT_STAGE;
ActKey(PULSE+KEYON+LED(&Throttle, LED_ONOFF, LED_CURRENT-LED1-LED2-LED3-LED4-LED5));
g_fDeadZone = 0.25;
InitAxis(AXIS_X);
InitAxis(AXIS_Y);
//--------------------------------------------
// AXIS MAPPINGS
//--------------------------------------------
// We only need to assign the main throttle to be interpreted by MWO, which will control the mech's velocity.
// The joystick and THR_FC will be handled in (this) software. Joystick values are converted and used to move mouse.
MapAxis(&Throttle, THR_RIGHT, DX_Z_AXIS);
//--------------------------------------------
// JOYSTICK MAPPINGS
//--------------------------------------------
// Firing weapons
MapKey(&Joystick, TG1, '1'); // Wep. group #1
// MapKey(&Joystick, TG2, ''); // Wep. group #
MapKey(&Joystick, H2U, '2'); // Wep. group #2
MapKey(&Joystick, H2D, '3'); // Wep. group #3
MapKey(&Joystick, H2R, '4'); // Wep. group #4
MapKey(&Joystick, H2L, '5'); // Wep. group #5
MapKey(&Joystick, S1, '6'); // Wep. group #6
MapKey(&Joystick, S2, USB[0x31]); // '\' alpha strike
// Hold for cockpit look
MapKey(&Joystick, S3, L_CTL);
// Weapon group toggles
MapKey(&Joystick, H4U, PULSE+USB[0x52]); // Up
MapKey(&Joystick, H4R, PULSE+USB[0x4F]); // Right
MapKey(&Joystick, H4D, PULSE+USB[0x51]); // Down
MapKey(&Joystick, H4L, PULSE+USB[0x50]); // Left
MapKey(&Joystick, H4P, PULSE+R_CTL); // Press -TOGGLE-
// Jump Jets
// MapKey(&Joystick, S4, USB[0x2C]); // Spacebar
MapKey(&Joystick, S4, SPC); // Spacebar
// Digital aimmer --Joystick round HAT
MapKey(&Joystick, H1U, REXEC(3, UPDATE_RATE, "g_AxisData[AXIS_Y].iMouse = g_AxisData[AXIS_Y].iMouse + (g_iAxisYDir * g_fSensMod * 0.5); DXAxis(MOUSE_Y_AXIS, g_AxisData[AXIS_Y].iMouse);"));
MapKey(&Joystick, H1D, REXEC(3, UPDATE_RATE, "g_AxisData[AXIS_Y].iMouse = g_AxisData[AXIS_Y].iMouse - (g_iAxisYDir * g_fSensMod * 0.5); DXAxis(MOUSE_Y_AXIS, g_AxisData[AXIS_Y].iMouse);"));
MapKey(&Joystick, H1L, REXEC(3, UPDATE_RATE, "g_AxisData[AXIS_X].iMouse = g_AxisData[AXIS_X].iMouse - (g_iAxisXDir * g_fSensMod * 0.5); DXAxis(MOUSE_X_AXIS, g_AxisData[AXIS_X].iMouse);"));
MapKey(&Joystick, H1R, REXEC(3, UPDATE_RATE, "g_AxisData[AXIS_X].iMouse = g_AxisData[AXIS_X].iMouse + (g_iAxisXDir * g_fSensMod * 0.5); DXAxis(MOUSE_X_AXIS, g_AxisData[AXIS_X].iMouse);"));
// Fine percision aimmer --Joystick DPAD
MapKey(&Joystick, H3U, REXEC(3, UPDATE_RATE, "g_AxisData[AXIS_Y].iMouse = g_AxisData[AXIS_Y].iMouse + g_iAxisYDir; DXAxis(MOUSE_Y_AXIS, g_AxisData[AXIS_Y].iMouse);"));
MapKey(&Joystick, H3D, REXEC(3, UPDATE_RATE, "g_AxisData[AXIS_Y].iMouse = g_AxisData[AXIS_Y].iMouse - g_iAxisYDir; DXAxis(MOUSE_Y_AXIS, g_AxisData[AXIS_Y].iMouse);"));
MapKey(&Joystick, H3L, REXEC(3, UPDATE_RATE, "g_AxisData[AXIS_X].iMouse = g_AxisData[AXIS_X].iMouse - g_iAxisXDir; DXAxis(MOUSE_X_AXIS, g_AxisData[AXIS_X].iMouse);"));
MapKey(&Joystick, H3R, REXEC(3, UPDATE_RATE, "g_AxisData[AXIS_X].iMouse = g_AxisData[AXIS_X].iMouse + g_iAxisXDir; DXAxis(MOUSE_X_AXIS, g_AxisData[AXIS_X].iMouse);"));
//--------------------------------------------
// THROTTLE MAPPINGS
//--------------------------------------------
// Map Throttle Turning the mech --Throttle side HAT
// MapKey(&Throttle, MSL, 'a'); // left
// MapKey(&Throttle, MSR, 'd'); // right
// Map Throttle up - down --Throttle side HAT
// MapKey(&Throttle, MSU, ''); // up
// MapKey(&Throttle, MSD, ''); // down
// Map Throttle push --Throttle side HAT--
// MapKey(&Throttle, MSP, PULSE+BSP); // push for chainfire on
MapKey(&Throttle, MSP, PULSE+'v'); // pip zoom
// Target Enemy
MapKey(&Throttle, SC, PULSE+'r'); // push to target
// Torso Center
// MapKey(&Throttle, LTB, PULSE+'c');
// MapKey(&Throttle, LTB, PULSE+BSP); // push for chainfire on
MapKey(&Throttle, LTB, PULSE+'j'); // ecm enable or disable eccm
// Toggle zoom
MapKey(&Throttle, CSD, PULSE+'z');
// TEAM SPEAK chat toggle (F8)
MapKey(&Throttle, CSU, USB[0x41]); // F8
// MapKey(&Throttle, CSU, PULSE+'v'); // pip zoom
// Show scores
MapKey(&Throttle, SPDF, USB[0x2B]);
// Show map
MapKey(&Throttle, SPDB, PULSE+'b');
// Map Throttle CHB, Toggle Friend Name Info
MapKey(&Throttle, CHB, 'q');
// Map Throttle CHM Push
// MapKey(&Throttle, CHM, PULSE+''); //
// Map Throttle CHF, ecm enable or disable eccm
// MapKey(&Throttle, CHF, PULSE+'j'); // ecm enable or disable eccm
// MapKey(&Throttle, CHF, PULSE+'v'); // pip zoom
MapKey(&Throttle, CHF, PULSE+BSP); // push for chainfire on
// Thermal vision toggle
MapKey(&Throttle, BSF, PULSE+'h');
MapKeyR(&Throttle, BSF, PULSE+'h');
// Map Throttle BSM Push
// MapKey(&Throttle, BSM, PULSE+''); //
// Night vision toggle
MapKey(&Throttle, BSB, PULSE+'n');
MapKeyR(&Throttle, BSB, PULSE+'n');
// Map Throttle Switch EAC and RDR
MapKey(&Throttle, EACON, '5'); // Engage TAG On
// MapKey(&Throttle, EACOFF, PULSE+''); // Default
MapKey(&Throttle, RDRNRM, PULSE+'/'); // Open-Close missile door
MapKey(&Throttle, RDRDIS, PULSE+'/'); // Open-Close missile door
// Shutdown switch toggle
// MapKey(&Throttle, EORMOTOR, EXEC("if(!g_bIsShutdown){ ActKey(PULSE+KEYON+'p'); g_bIsShutdown = 1; }"));
// MapKey(&Throttle, EORIGN, EXEC("if(g_bIsShutdown){ ActKey(PULSE+KEYON+'p'); g_bIsShutdown = 0; }"));
MapKey(&Throttle, EORMOTOR, PULSE+'o');
MapKey(&Throttle, EORIGN, PULSE+'p');
// Activate 'Shutdown Override' repeat (**** down for always 'ON')
// ActKey(PULSE+KEYON+REXEC(1, 700, "ActKey(PULSE+KEYON+'o');"));
// MapKey(&Throttle, EFROVER, REXEC(0, 700, "ActKey(PULSE+KEYON+'o');"));
// MapKey(&Throttle, EFRNORM, EXEC("StopHeatOverrideRepeat();"));
// Toggle 'JOYSTATE_SLUGGISH' indicated by shutting off all LED sluggish state lights.
MapKey(&Throttle, EFLNORM, EXEC("SlugToggle(1);"));
MapKey(&Throttle, EFLOVER, EXEC("SlugToggle(0);"));
// Cycle 'JOYSTATE_SLUGGISH's duration parameter, indicated by LED lights.
MapKey(&Throttle, LDGH, EXEC("SlugDuration(1);"));
// Set text chat COMMS to associate with auto-pilot controls.
// MapKey(&Throttle, APENG, SEQ('y', ENT)); // Default
// MapKey(&Throttle, APPAT, EXEC("MapKey(&Throttle, APENG, SEQ('g', ENT));"));
// MapKey(&Throttle, APAH, EXEC("MapKey(&Throttle, APENG, SEQ('t', ENT));"));
// MapKey(&Throttle, APALT, EXEC("MapKey(&Throttle, APENG, SEQ('u', ENT));"));
// User settings for how much "deadzone" when stick is centered.
MapKey(&Throttle, PSF, EXEC("g_fDeadZone = 0.3;"));
MapKey(&Throttle, PSM, EXEC("g_fDeadZone = 0.25;"));
MapKey(&Throttle, PSB, EXEC("g_fDeadZone = 0.15;"));
// User settings for which JOYSTATE's to enable
MapKey(&Throttle, FLAPU, EXEC("SetJoyState(JOYSTATE_SNAP);"));
MapKey(&Throttle, FLAPM, EXEC("SetJoyState(JOYSTATE_NORM);"));
MapKey(&Throttle, FLAPD, EXEC("SetJoyState(JOYSTATE_ABSOLUTE);"));
// User settings for Joystick Axis directions
MapKey(&Throttle, EOLMOTOR, EXEC("g_iAxisYDir = 1;")); // Set Y-Axis to normal direction
MapKey(&Throttle, EOLNORM, EXEC("g_iAxisYDir = -1;")); // Set Y-Axis to inverted diection
MapKey(&Throttle, EOLIGN, EXEC("g_iAxisXDir = g_iAxisXDir * -1;")); // Toggle/**** X-Axis direction
//--------------------------------------------
// START UPDATE LOOP
//--------------------------------------------
// Enable Joystick->Mouse - Throttle[APU]
MapKey(&Throttle, APUON, REXEC(2, UPDATE_RATE, "UpdateJoystick();"));
printf("All systems nominal!");
}
int SetJoyState(int iState)
{
if(0 != (iState & JOYSTATE_NORM))// Throttle[FLAPM]
{
// Disable JOYSTATE_SNAP and JOYSTATE_ABSOLUTE
g_iJoyStates = g_iJoyStates & JOYSTATE_SNAP_OFF;
g_iJoyStates = g_iJoyStates & JOYSTATE_ABSOLUTE_OFF;
// Enable JOYSTATE_NORM
g_iJoyStates = g_iJoyStates | JOYSTATE_NORM;
}
else if(iState == JOYSTATE_SNAP)// Throttle[FLAPU]
{
// Disable JOYSTATE_ABSOLUTE
g_iJoyStates = g_iJoyStates & JOYSTATE_ABSOLUTE_OFF;
// Enable JOYSTATE_SNAP and JOYSTATE_NORM
g_iJoyStates = g_iJoyStates | JOYSTATE_SNAP | JOYSTATE_NORM;
}
if(iState == JOYSTATE_ABSOLUTE)// Throttle[FLAPD]
{
// Disable JOYSTATE_NORM and JOYSTATE_SNAP
g_iJoyStates = g_iJoyStates & JOYSTATE_NORM_OFF;
g_iJoyStates = g_iJoyStates & JOYSTATE_SNAP_OFF;
// Enable JOYSTATE_ABSOLUTE
g_iJoyStates = g_iJoyStates | JOYSTATE_ABSOLUTE;
g_AxisData[AXIS_X].bHasPulseCenter = 0;
g_AxisData[AXIS_Y].bHasPulseCenter = 0;
}
}
int SlugDuration(int iStageOffset)
{
g_iSlugStage = g_iSlugStage + iStageOffset;
// Loop stages
if(g_iSlugStage > 5)
g_iSlugStage = 1;
if(0 != (g_iJoyStates & JOYSTATE_SLUGGISH))
{
// Set appropriate LED light indicator // No 'switch' statement available in TARGET
![:)](https://static.mwomercs.com/forums/public/style_emoticons/default/sad.png)
if(1 == g_iSlugStage)
ActKey(PULSE+KEYON+LED(&Throttle, LED_ONOFF, LED_CURRENT-LED1-LED2-LED3-LED4+LED5));
else if(2 == g_iSlugStage)
ActKey(PULSE+KEYON+LED(&Throttle, LED_ONOFF, LED_CURRENT-LED1-LED2-LED3+LED4+LED5));
else if(3 == g_iSlugStage)
ActKey(PULSE+KEYON+LED(&Throttle, LED_ONOFF, LED_CURRENT-LED1-LED2+LED3+LED4+LED5));
else if(4 == g_iSlugStage)
ActKey(PULSE+KEYON+LED(&Throttle, LED_ONOFF, LED_CURRENT-LED1+LED2+LED3+LED4+LED5));
else
ActKey(PULSE+KEYON+LED(&Throttle, LED_ONOFF, LED_CURRENT+LED1+LED2+LED3+LED4+LED5));
}
}
int SlugToggle(int bEnable)
{
if(bEnable == 1)
{
g_iJoyStates = g_iJoyStates | JOYSTATE_SLUGGISH;
SlugDuration(0);
}
else
{
// Disable the Sluggish effect and turn off all LED's
g_iJoyStates = g_iJoyStates & JOYSTATE_SLUGGISH_OFF;
ActKey(PULSE+KEYON+LED(&Throttle, LED_ONOFF, LED_CURRENT-LED1-LED2-LED3-LED4-LED5));
}
}
int StopHeatOverrideRepeat()
{
StopAutoRepeat(1);
}
int UpdateJoystick()
{
UpdateJoystickAxis(AXIS_X);
UpdateJoystickAxis(AXIS_Y);
// Store current fJoy into fJoyPrev to be used next Update()
g_AxisData[AXIS_X].fJoyPrev = g_AxisData[AXIS_X].fJoy;
g_AxisData[AXIS_Y].fJoyPrev = g_AxisData[AXIS_Y].fJoy;
}
int UpdateJoystickAxis(int iIndex)
{
// Whether or not to apply this Update()
int bUpdateAxis = 1;
// How much to move the mouse this Update()
float fMouseDelta = 0.0;
//--------------------------------------------
// Check to see if this axis's input value (fJoy)
// is lower than the user specified deadzone (g_fDeadZone)
//--------------------------------------------
if(abs(g_AxisData[iIndex].fJoy) < g_fDeadZone)
{
g_AxisData[iIndex].fSlugPerc = 0.01;
g_AxisData[iIndex].bSnapDir = 0;
if(0 != (g_iJoyStates & JOYSTATE_ABSOLUTE))
{
// Only center torso if both X and Y axis hasn't Pulsed and both X and Y are centered
if(g_AxisData[AXIS_X].bHasPulseCenter == 0 & g_AxisData[AXIS_Y].bHasPulseCenter == 0)
{
if(abs(g_AxisData[AXIS_X].fJoy) < g_fDeadZone & abs(g_AxisData[AXIS_Y].fJoy) < g_fDeadZone)
{
ActKey(PULSE+KEYON+'c');
g_AxisData[AXIS_X].bHasPulseCenter = 1;
g_AxisData[AXIS_Y].bHasPulseCenter = 1;
}
}
}
bUpdateAxis = 0;
}
else
{
//--------------------------------------------
// Apply 'SLUGGISH' if state enabled
//--------------------------------------------
if(0 != (g_iJoyStates & JOYSTATE_SLUGGISH))
{
g_AxisData[iIndex].fSlugPerc = g_AxisData[iIndex].fSlugPerc + SLUG_INCREMENTS + (g_iSlugStage * SLUG_INCREMENTS);
if(g_AxisData[iIndex].fSlugPerc > 1.0)
{
g_AxisData[iIndex].fSlugPerc = 1.0; // clamp proc sens at 1.0
}
fMouseDelta = fMouseDelta + (g_AxisData[iIndex].fJoy * g_AxisData[iIndex].fSlugPerc);
}
else if(0 != (g_iJoyStates & JOYSTATE_NORM))
fMouseDelta = fMouseDelta + g_AxisData[iIndex].fJoy;
//--------------------------------------------
// Apply 'SNAP' if state enabled
//--------------------------------------------
if(0 != (g_iJoyStates & JOYSTATE_SNAP))
{
if(g_AxisData[iIndex].fJoy > 0.0)
{
if(g_AxisData[iIndex].fJoy >= g_AxisData[iIndex].fJoyPrev)
g_AxisData[iIndex].bSnapDir = 1; // Moving away from center
else
g_AxisData[iIndex].bSnapDir = 0; // Moving towards from center
}
else
{
if(g_AxisData[iIndex].fJoy <= g_AxisData[iIndex].fJoyPrev)
g_AxisData[iIndex].bSnapDir = 1; // Moving away from center
else
g_AxisData[iIndex].bSnapDir = 0; // Moving towards from center
}
if(g_AxisData[iIndex].bSnapDir == 1)
fMouseDelta = fMouseDelta * 2.0;
else
fMouseDelta = fMouseDelta * 0.5;
}
//--------------------------------------------
// Apply 'ABSOLUTE' if state enabled
//--------------------------------------------
if(0 != (g_iJoyStates & JOYSTATE_ABSOLUTE))
{
g_AxisData[iIndex].bHasPulseCenter = 0;
fMouseDelta = g_AxisData[iIndex].fJoy - g_AxisData[iIndex].fJoyPrev;
fMouseDelta = fMouseDelta * 100.0;
}
}
// Manually set mouse position if passes above checks
if(bUpdateAxis)
{
g_AxisData[iIndex].iMouse = g_AxisData[iIndex].iMouse + fMouseDelta;
if(iIndex == AXIS_X)
DXAxis(MOUSE_X_AXIS, g_AxisData[iIndex].iMouse);
else
DXAxis(MOUSE_Y_AXIS, g_AxisData[iIndex].iMouse);
}
return 0;
}
//event handler
int EventHandle(int type, alias o, int x)
{
if(&o == &Joystick & (x == JOYX | x == JOYY)) // if the event came from Joystick X or Y axis
{
g_AxisData[AXIS_X].fJoy = Joystick[JOYX] * g_iAxisXDir;
g_AxisData[AXIS_X].fJoy = g_AxisData[AXIS_X].fJoy / fJOYAXIS_LIMIT;
g_AxisData[AXIS_X].fJoy = g_AxisData[AXIS_X].fJoy * g_fSensMod;
g_AxisData[AXIS_Y].fJoy = Joystick[JOYY] * g_iAxisYDir;
g_AxisData[AXIS_Y].fJoy = g_AxisData[AXIS_Y].fJoy / fJOYAXIS_LIMIT;
g_AxisData[AXIS_Y].fJoy = g_AxisData[AXIS_Y].fJoy * g_fSensMod;
}
else if(&o == &Throttle & x == THR_FC) // if the event came from the Throttle's friction control trim wheel
{
g_fSensMod = -Throttle[THR_FC];
g_fSensMod = g_fSensMod / fJOYAXIS_LIMIT;
g_fSensMod = (g_fSensMod * fDEFAULT_SENSITIVITY) + fDEFAULT_SENSITIVITY;
}
// Allow the system to handle incoming events and do its thing.
DefaultMapping(&o, x);
}