Skip to content

Using the Razer Hydra Controller Input Events

DavidWyand-GG edited this page Feb 22, 2013 · 15 revisions

The new Torque 3D Razer Hydra input device provides a number of input events that may be used with Torque 3D's action map system. There are a number of different ways to use the Razer Hydra input device, which are set up using global TorqueScript variables.

Action Map Device Type

When binding a TorqueScript function to a Razer Hydra input event using Torque 3D's action map system, the device name to use is razerhydra. As only one Razer Hydra may be used on a computer at a time, there is no need to append a device instance number to the end of the device name. The following is an example of setting up a proper action map binding:

moveMap.bind( razerhydra, rh_trigger1, gamepadFire );

Processing Input Events When Docked

The $RazerHydra::ProcessWhenDocked global TorqueScript variable determines if input events are generated by the Razer Hydra when a controller is docked. A controller is considered docked when it is placed in the Razer Hydra base station. When $RazerHydra::ProcessWhenDocked is false (the default) then no events will be generated by the controller. When this global variable is set to true then all input events will continue to be generated by a docked controller. Please note that a controller's position and rotation values may be warped when it is placed near or on the base station.

Standard Gamepad Input Events

The Razer Hydra provides a full compliment of gamepad buttons and sticks spread across two hand held controllers. Torque 3D provides complete access to all of these input events which behave as you would expect from a Xbox 360 compatible gamepad. The following action map input events are available:

Left Controller

  • rh_thumbx0 - thumb stick x-axis motion in the range of -1.0 to 1.0
  • rh_thumby0 - thumb stick y-axis motion in the range of -1.0 to 1.0
  • rh_trigger0 - trigger motion (sometimes referred to as z-axis motion) in the range of 0.0 to 1.0
  • rh_shoulder0 - shoulder (or bumper) button
  • rh_thumb0 - thumb stick used as a button
  • rh_start0 - start button
  • rh_1button0 - 1 button
  • rh_2button0 - 2 button
  • rh_3button0 - 3 button
  • rh_4button0 - 4 button

Right Controller

  • rh_thumbx1 - thumb stick x-axis motion in the range of -1.0 to 1.0
  • rh_thumby1 - thumb stick y-axis motion in the range of -1.0 to 1.0
  • rh_trigger1 - trigger motion (sometimes referred to as z-axis motion) in the range of 0.0 to 1.0
  • rh_shoulder1 - shoulder (or bumper) button
  • rh_thumb1 - thumb stick used as a button
  • rh_start1 - start button
  • rh_1button1 - 1 button
  • rh_2button1 - 2 button
  • rh_3button1 - 3 button
  • rh_4button1 - 4 button

As with a standard gamepad, each of the thumb stick motions (and even the trigger although it is not usually used this way) are of the AXIS type. This means that additional modifiers may be placed on their inputs, such as defining a dead zone. For example, here is how you could set up the right controller's thumb stick to be used to rotate the player with a slight dead zone around the stick's neutral position:

moveMap.bind( razerhydra, rh_thumbx1, "D", "-0.23 0.23", gamepadYaw );
moveMap.bind( razerhydra, rh_thumby1, "D", "-0.23 0.23", gamepadPitch );

Controller Absolute Position and Rotation Events

The unique feature of the Razer Hydra is being able to detect each the left and right controller's absolute position and rotation in space. When it comes to generating position input events, there are two options available. The first option is to receive each x, y and z axis update as separate events given as rh_posx, rh_posy and rh_posz. You activate this option by setting the global TorqueScript variable $RazerHydra::SeparatePositionEvents to true, which is the default setting. This is similar to how a thumb stick generates separate events for both the x and y axis.

The second option is to receive only a single position event rh_pos that includes each axis as a separate parameter. You activate this mode by setting the global TorqueScript variable $RazerHydra::CombinedPositionEvents to true. The primary advantage of this mode is you generally produce much less input events for Torque 3D to process.

The following action map input events are available (all positions are in millimeters and all rotations are in angled axis format):

Left Controller

  • rh_posx0 - absolute x axis position
  • rh_posy0 - absolute y axis position
  • rh_posz0 - absolute z axis position
  • rh_pos0 - absolute position provided as 3 parameters
  • rh_rot0 - absolute rotation

Right Controller

  • rh_posx1 - absolute x axis position
  • rh_posy1 - absolute y axis position
  • rh_posz1 - absolute z axis position
  • rh_pos1 - absolute position provided as 3 parameters
  • rh_rot1 - absolute rotation

Using Position and Rotation Input Events

You bind Razer Hydra position and rotation events to an action map just like any other input event. Here is an example of making use of the position (the single event version) and rotation events generated by the right controller (place it in scripts/client/default.bind.cs):

function RHPos1(%x, %y, %z)
{
   // Output the absolute position of the right controller to the console:
   echo("Right controller position in millimeters:" SPC %x SPC %y SPC %z);
}

function RHRot1(%x, %y, %z, %a)
{
   // Output the absolute rotation of the right controller to the console:
   echo("Right controller rotation as angled axis:" SPC %x SPC %y SPC %z SPC %a);

   // Convert into a world space forward vector
   %pos = "0 0 0";
   %rot = %x SPC %y SPC %z SPC %a;
   %transform = MatrixCreate( %pos, %rot );
   %forward = MatrixMulVector( %transform, "0 1 0" );
   echo("Right controller world forward vector:" SPC %forward.x SPC %forward.y SPC %forward.z);
}

$RazerHydra::SeparatePositionEvents = false;
$RazerHydra::CombinedPositionEvents= true;
moveMap.bind( razerhydra, rh_pos1, RHPos1);
moveMap.bind( razerhydra, rh_rot1, RHRot1);

Controller as Thumb Stick Input Events

Torque 3D allows a Razer Hydra controller to be used like a gamepad thumb stick. Imagine that a thumb stick is coming out of the top of the controller and you move it by tilting the controller.

To activate these thumb stick input events we set the $RazerHydra::RotationAsAxisEvents global TorqueScript variable to true. With that variable set the following action map input events are available:

Left Controller

  • rh_rotaxisx0 - thumb stick like x-axis motion in the range of -1.0 to 1.0
  • rh_rotaxisy0 - thumb stick like y-axis motion in the range of -1.0 to 1.0

Right Controller

  • rh_rotaxisx1 - thumb stick like x-axis motion in the range of -1.0 to 1.0
  • rh_rotaxisy1 - thumb stick like y-axis motion in the range of -1.0 to 1.0

Internally, these x and y axis values are normalized to ensure the length of their vector is never more than 1, just like a real thumb stick.

In order to calculate the -1.0 to 1.0 range, the tilt of the controller with respect to a vector pointing straight up (technically this vector is normal to the plane of the Razer Hydra's base unit) is used. When this controller to up vector angle reaches the $RazerHydra::MaximumAxisAngle global script variable value (the default is 25 degrees) then the virtual thumb stick is considered all the way over. Adjusting $RazerHydra::MaximumAxisAngle for your application determines how far over the user must tilt their controller for a 100% value.

Whole Frame Input Events

There may be a time when the provided Razer Hydra input events don't quite fit your needs. In these cases you may make use of the Razer Hydra whole frame input event that is available in Torque 3D. To activate this input event you set the $RazerHydra::GenerateWholeFrameEvents global TorqueScript variable to true. When active, you may then receive the rh_frame input event.

The rh_frame event is unique in that it provides a single value that is a SimObject ID to a RazerHydraFrame class instance. You may then use this ID to call the instance's methods and retrieve the frame's data.

Each 'RazerHydraFrame' class instance is automatically stored within the RazerHydraFrameGroup SimGroup. A maximum number of RazerHydraFrame objects are kept at any time as determined by the $RazerHydra::MaximumFramesStored global TorqueScript variable (the default is 30). When a new RazerHydraFrame object is required, the oldest is removed from the RazerHydraFrameGroup and recycled.

The RazerHydraFrame instances are stored newest to oldest, with the newest at index 0 within the group. When you receive a rh_frame event you may safely assume that the frame ID given in the frame's parameter is the first frame in the RazerHydraFrameGroup. To manually retrieve the newest frame and the frame that came just before it (perhaps to perform a delta calculation between the two) you may use the following:

%newestFrame = RazerHydraFrameGroup.getObject(0);
%previousFrame = RazerHydraFrameGroup.getObject(1);

This may be done at any time that your application is running so long as you are collecting whole frames as set with the $RazerHydra::GenerateWholeFrameEvents global variable.

Using Whole Frame Input Events

You bind the Razer Hydra input events to an action map just like any other input event. Specifically, you tie the events to the razerhydra device with the action map bind() method. For example, the following TorqueScript code (placed in scripts/client/default.bind.cs) performs an action against each frame received by the input event:

function RHFrame(%id)
{
   // Output some information about this frame to the console
   echo( "Frame " @ %id @ " time: " @ %id.getFrameRealTime() @ " left controller transform: " @ %id.getControllerTransform(0) );
}

$RazerHydra::GenerateWholeFrameEvents = true;
moveMap.bind( razerhydra, rh_frame, RHFrame);

The 'RazerHydraFrame' class has a large number of methods available for working with a frame's controller data. Please see the bottom of the source code file platform/input/razerHydra/razerHydraFrame.cpp for a complete list of the available methods.

Miscellaneous Input Events

The rh_docked0 and rh_docked1 (for left and right) input events are generated whenever a controller's docked status changes. A controller is docked when it is sitting in the Razer Hydra base station. This event can be useful for changing the application's state, such as pausing when nothing is being tracked by the Razer Hydra controller.

The rh_docked0 and rh_docked1 input events provides a single parameter that has a value of 1 when a controller is docked, and 0 when a controller has been picked up by the user. Here is an example of using this event:

function RHDocked0(%val)
{
   echo("Left controller is docked: " @ %val);
}

// Set up for the left controller
moveMap.bind( razerhydra, rh_docked0, RHDocked0);

We may also check a controller's docked status at any time with the following TorqueScript function:

isRazerHydraControllerDocked( controller );

where the controller parameter is 0 or 1 for the left or right controller. This function returns true if the requested controller is currently docked. As the rh_docked0 and rh_docked1 input events are only generated when a controller's docked status changes, the isRazerHydraControllerDocked() function is useful when your application first starts up to detect a controller's current state.

Order of Input Events

The following is the order in which Razer Hydra input events may be received by the application:

For each controller, starting with the left one

  1. The rh_docked event. If a controller is docked and $RazerHydra::ProcessWhenDocked is set to false then the following controller events will be skipped.
  2. If $RazerHydra::SeparatePositionEvents is true then all individual controller position events.
  3. If $RazerHydra::CombinedPositionEvents is true then the combined controller position event.
  4. The controller's rotation event.
  5. All standard gamepad input events.
  6. If $RazerHydra::RotationAsAxisEvents is true then the controller as thumb stick input events, but only if these values have changed this frame compared to the previous frame. This is the same behavior as with gamepad thumb sticks. When a controller is docked one last input event of this type is sent out with a value of 0.0. This returns the virtual thumb stick to a neutral position.

Following the controllers being processed

  1. If $RazerHydra::GenerateWholeFrameEvents is true then the rh_frame event.