F-Gen Tutorial 01 - Basic Scripting
F-Gen uses a scripting language called "Squirrel". This first tutorial will
teach you first how to test a simple script file, then how to add some simple
Falcon force effects. Finally, it will teach you how to attach a script file
to a Windows application.
Table of Contents:
Part 1 - Running a Script
Part 2 - Detecting Buttons and Keyboard Keys
Part 3 - Scripting a Recoil Force
Part 4 - Scripting a Continuous Force
Part 5 - Scripting a Default Control Box
Part 6 - Creating Your Own Functions
Part 7 - Creating a Force Whose Direction You Can Change
Part 8 - Attaching Your Script to an Application
Part 9 - Creating a Tuning Slider
Part 10 - Tuning Keyboard Settings
Part 11 - Sending Keyboard Commands from a Script
Part 12 - Getting the Current Falcon Position
Part 13 - Accessing a Plugin
Part 14 - Creating a Plugin (requires some C++ knowledge)
Part 1 - Running a Script
This part of the tutorial will first teach you how to test a simple script,
and then walk you through the basics of that script.
First, download the test script: tutorial script.
Unzip the file to a location of your choice (the Windows Desktop works fine).
When you open the new "fgen_tutorial" directory, you will see two files.
"fgen_tutorial.nut" is the script file. You will also see a shortcut to a
tool called "fgsq.exe". This tool allows you to test a script.
NOTE: if you installed F-Gen to someplace other than
the default location of "C:/Program Files/Novint" you will need to search
your computer for "fgsq.exe" and replace this shortcut.
Now, lets give the script a test run. Make sure your Falcon is plugged in,
and run the F-Gen Manager (you don't actually need to run the Manager, but
its a good way to make sure the Falcon is running properly).
Now, drag and drop the script file (fgen_tutorial.nut) onto the shortcut for
fgsq.exe. You will likely see the Falcon light blink, and a popup console
will appear, looking like this:
In general, the comments in red are messages from F-Gen, while most comments
in white are comments from the script. Now hit "ENTER" on the keyboard to
shutdown the script, which will now look like this:
Anytime you want to test your scripts, you can just drag and drop the script
onto the shortcut to fgsq.exe.
Now its time to take a look at the script. Open "fgen_tutorial.nut" in your
favorite text editor. Windows Notepad works fine (which is included with
all versions of Windows... you can find it by clicking on the Desktop START
button, bringing up the program list, and looking under "Accessories and
System").
You should see five "functions" in the script, along with several "print"
calls and some comments (anything after a "//" is a comment... something
ignored by the script, but allowing you to add descriptions). These five
"functions" are called by F-Gen at particular times when your script is in
use.
function HapticsInitialize - this function is called exactly
once, when the script is first loaded. It is called before any other
function, and can be used to set up anything your script needs.
function HapticsActivated - this function is called whenever
your script becomes active. Thus, it is called just after HapticsInitialize,
as well as any time you switch to another window and then return to the
application running the script (in this case fgsq.exe).
function HapticsThink - this function is called repeatedly
when your script is active. It is inside this function that you will do
most of your scripting.
function HapticsDeactivated - this function is called whenever
the script stops being active (such as switching focus to a different
window).
function HapticsShutdown - this function is called exactly
once, when the script is shut down (this usually happens when the application
running the script is closed).
Notice that inside several of the functions there are "print" calls,
which match the text displayed in fgsq.exe. For example, in
HapticsInitialize, there is a call that looks like
"print("Initialize Script\n");"
- this prints the words "Initialize Script" to the fgsq.exe console. The
"\n" at the end of the text means add a new line at the end (the next print
call will start on the next line). Also note the ";" at the very end of
the print call. All individual script instructions need to end with a
semicolon (this tells the script that the instruction is complete).
Now on to part 2 of the script... detecting buttons and keyboard keys in
your script.
Part 2 - Detecting Buttons and Keyboard Keys
This part of the tutorial guides you through detecting Falcon button and
keyboard keys, and using them to print messages to the console. To see
what the finished script should look like once you are done with this
part of the tutorial, download it here:
fgen_tutorial_01b_btns.nut.
Now add the following to your HapticsThink function:
if (devicewasbuttonjustpressed(deviceHandle, FALCON_LOGO))
{
print(" ...Falcon LOGO button was just pressed\n");
}
else if (devicewasbuttonjustreleased(deviceHandle, FALCON_LOGO))
{
print(" ...Falcon LOGO button was just released\n");
}
Now run your script in fgsq.exe. Once the script is active, start clicking
the Falcon's main (logo) button. You should see a message every time you
click down on the button, and another message every time you release the
button.
This introduces a new scripting concept... the "if" and "if...else" script
commands. The "if" command says that if the command after the "if" is
true, then do the things in the brackets following. You can then add an
"else" if needed, to say what to do if the command after the "if" was false.
Now add this into the HapticsThink function:
if (devicebuttonisdown(deviceHandle, FALCON_TRIANGLE))
{
print(" ... Falcon TRIANGLE button is currently down\n");
}
Now run the script, and click the Falcon left (triangle) button. As long as
the button is down, you should see a steady stream of messages in the
fgsq.exe console. Using these three commands (devicebuttonisdown,
devicewasbuttonjustpressed, and devicewasbuttonjustreleased),
you can check the status of any of the four Falcon buttons.
Time now to detect keyboard presses... add the following to the top of your
script (before the HapticsInitialize function):
// create a keyboard listener
gKeyInput <- inputlistener();
This creates a keyboard "listener" you can use to get information about the
keyboard. Now add the following to your HapticsThink function:
// update the keyboard listener before checking keyboard values
gKeyInput.update();
if (gKeyInput.wasinputjustpressed(KEY_1))
{
print(" ... 1 key was just pressed\n");
}
else if (gKeyInput.wasinputjustreleased(KEY_1))
{
print(" ... 1 key was just released\n");
}
if (gKeyInput.isinputdown(KEY_0))
{
print(" ... zero key is currently down\n");
}
This new script code first updates the keyboard listener (making sure the
keyboard values are current), and then uses the commands isinputdown,
wasinputjustpressed, and wasinputjustreleased to check
keyboard keys. If you now run your script, you should see that if you hit
the "1" key, you get a fgsq.exe console message every time the "1" key
is pressed or released. If you hit the zero key, you should get a steady
stream of messages as long as the zero key is down.
Now that you can detect buttons and the keyboard, its time to move on to the
next part of the tutorial, where you will add your first Falcon force.
Part 3 - Scripting a Recoil Force
This part of the tutorial guides you through setting up and adding a simple
recoil force to your script. To see what the final script should look like,
download it here:
fgen_tutorial_01c_recoil.nut.
To generate a Falcon force effect, you first have to do some setup. At the
top of your script file (before the HapticsInitialize function) add
the following:
// creating default Falcon effect stack
gEffectsStack <- effectstack("effects", 1.0);
// registering envelope effect.
gEnvelopeEffectID <- registereffect("Envelope");
This creates a list, or "stack", of empty Falcon effects, and then defines
a type of effect, in this case an "envelope" effect. An envelope effect is
an effect that follows a pattern of forces.
Now add this to your HapticsActivated function:
// unlocking the device list on stack
gEffectsStack.setdevicelock(false);
// adding the device to the stack input slot 0
gEffectsStack.adddevice(deviceHandle, 0);
// locking the device list on stack
gEffectsStack.setdevicelock(true);
// connect the stack to the device for output
deviceconnectstack(deviceHandle, gEffectsStack);
This set of four commands activates your "stack" of effects (don't worry for
now about the details of what each of these commands does). Now add the
following to your HapticsDeactivated function:
// unlocking the device list on stack
gEffectsStack.setdevicelock(false);
// removing the device from the stack input slot 0
gEffectsStack.removedevice(deviceHandle, 0);
// locking the device list on stack
gEffectsStack.setdevicelock(true);
// disconnecting the stack output from the device
devicedisconnectstack(deviceHandle, gEffectsStack);
This set of four commands deactivates your effects stack.
We are now ready to define a simple recoil effect. Above the
HapticsInitialize function, but after defining the effects stack
and "envelope" effect type, add the following:
// create a simple recoil effect and set its parameters.
gSimpleRecoil <- effectparameters(gEnvelopeEffectID, gEffectsStack); // create the effect
gSimpleRecoil.setvarelement("force", 0, 0); // 0 newtons right-wards
gSimpleRecoil.setvarelement("force", 1, 0); // 0 newtons upwards
gSimpleRecoil.setvarelement("force", 2, 20); // 20 newtons backwards
gSimpleRecoil.setvar("attack", 30); // ramp up to the force over 30 milliseconds.
gSimpleRecoil.setvar("hold", 0); // no hold time once at maximum force
gSimpleRecoil.setvar("decay", 0); // no fall off time at end of effect
This creates an envelope type effect, and sets how it runs. The 1st line
creates the effect, the next three lines define the direction and size of
the force (in this case no sideways or vertical forces, but a force of 20
newtons backwards). The remaining three lines set how fast the effect
ramps up, how long it holds at maximum, and how fast it then ramps down
(in this case, ramp up over 30 milliseconds, and then no hold or ramp-down
time).
One final step left. In your HapticsThink function, add
"gSimpleRecoil.fire();" into
the "if" command that checks if the Falcon LOGO button has just been
pressed:
if (devicewasbuttonjustpressed(deviceHandle, FALCON_LOGO))
{
print(" ...Falcon LOGO button was just pressed\n");
// launch the simple recoil effect
gSimpleRecoil.fire();
}
else....
Now run the script in fgsq.exe. Every time you click the Falcon LOGO button
you should feel a recoil force.
Part 4 - Scripting a Continuous Force
This part of the tutorial will first show you how to use keyboard keys to
select between several several force effects, and then show you how to
create a second effect that loops the recoil. To see what the final script
should look like, download it here:
fgen_tutorial_01d_looprecoil.nut.
To start, add the following somewhere at the top of your script (above the
HapticsInitialize function);
// variable to store which type of recoil effect to use
gEffectType <- 1; // 0 = no effect, 1 = simple recoil, 2 = looping recoil... init to 1
This creates a "global" variable called gEffectType, that holds an initial
value of 1. A global variable is a variable that retains its value permanently
unless changed. Now modify the portion of the script that detects if the
LOGO button was just pressed (and fires off the simple recoil) to look like
this:
if (devicewasbuttonjustpressed(deviceHandle, FALCON_LOGO))
{
print(" ...Falcon LOGO button was just pressed\n");
if (gEffectType == 1)
{ // firing a single recoil
// launch the simple recoil effect
gSimpleRecoil.fire();
}
}
else...
What this addition does is tell the script to only launch the simple recoil
effect if the effect type is set to 1.
Next, we need to modify the keyboard checking so that keyboard keys will
change gEffectType. Make the keyboard part of HapticsThink look like
this:
// update the keyboard listener before checking keyboard values
gKeyInput.update();
if (gKeyInput.wasinputjustpressed(KEY_0))
{
print(" ... select no recoil\n");
// set effect type to no recoil
gEffectType = 0;
}
else if (gKeyInput.wasinputjustpressed(KEY_1))
{
print(" ... select simple recoil\n");
// set effect type to single recoil
gEffectType = 1;
}
else if (gKeyInput.wasinputjustpressed(KEY_2))
{
print(" ... select looping recoil\n");
// set effect type to looping recoil
gEffectType = 2;
}
Give the script a quick test... you will now notice that if you hit the "0"
or "2" keyboard keys, the recoil when you hit the Falcon LOGO button stops
occuring. If you then hit the "1" key, the recoil returns.
Now its time to add a second force effect... a looping recoil that will
occur when gEffectType is set to 2 and you hold down the Falcon LOGO
button. The way we are going to do this is to create some timing code
that will allow us to repeatedly call the simple recoil. At the top of
the script (above HapticsInitialize), add the following:
// setup event timing
gScriptTime <- timekeeper(); // setup time checker
gLoopRecoilTimer <- 0.0; // timer to use for looping a recoil effect (initially set to zero)
This creates a way to grab timing values (through gScriptTime), and adds
a global variable (gLoopRecoilTimer) that holds the amount of time (in
fractions of a second) until the next recoil. Next, at the top of the
HapticsThink function, before you do anything else, add this:
// update the time checker
gScriptTime.update();
// grab the time (in seconds) since the last call to HapticsThink
local elapsedTime = gScriptTime.elapsedseconds();
This updates the script timing, and then creates a "local" variable called
elapsedTime that holds the amount of time (in fractions of a second) since
the last time HapticsThink was called. A local variable is a temporary
variable inside a function, whose value gets erased once the function exits.
Finally, adjust the part of HapticsThink that checks if the Falcon
TRIANGLE button is down to look like the following. Note that the first
change is to have it now check for the Falcon LOGO button instead:
if (devicebuttonisdown(deviceHandle, FALCON_LOGO))
{
print(" ... Falcon LOGO button is currently down\n");
if (gEffectType == 2)
{ // firing a looping recoil
// count down to next time to fire off a recoil
gLoopRecoilTimer -= elapsedTime; // subtract elasped time from the timer
if (gLoopRecoilTimer <= 0.0)
{ // time to fire off another recoil
gSimpleRecoil.fire();
// reset timer... fire off a recoil every tenth of a second
gLoopRecoilTimer += 0.1; // increase timer by a tenth of a second
}
}
}
This addition checks if the LOGO button is being held down... if so, it
subtracts the elapsed time from the gLoopRecoilTimer. If the timer is now
zero or less, then we fire off a recoil effect and reset the timer for
another tenth of a second wait.
Run the script in fgsq.exe, and now if you hit the "2" key on the keyboard
and then hold down the Falcon LOGO button, you will get a repeating
recoil until you let go of the button.
Part 5 - Scripting a Default Control Box
This part of the tutorial will show how to create a "Control Box". A Control
Box is a special type of Falcon effect that adds mouse control to the script,
as well as soft force walls to the left, right, top, and bottom of the Falcon
movement space. If you move the Falcon within these walls, you control the
mouse cursor directly. If you press into one of the walls, then the cursor is
pushed in that direction. If you've played around with the F-Gen Manager
and using the Falcon to control the mouse cursor in Windows, then you should
already have an idea of how this works.
To see what the final script should look like, grab it here:
fgen_tutorial_01e_controlbox.nut.
The first thing we are going to do is create a seperate effects stack for
the control box. We could just use the current effects stack (which we are
using for the recoils), but eventually we may want to be able to tune the
control box seperately from other effects. Add the following to the top of
your script:
// creating a seperate Falcon effect stack for the control box
gControlBoxStack <- effectstack("control", 1.0);
// registering a control box effect
gControlBoxEffectID <- registereffect("ControlBox");
gControlBox <- null; // variable to store the control box in
Then, in the HapticsActivated function, add what's needed to activate
the new control effects stack:
// unlocking the device list on control stack
gControlBoxStack.setdevicelock(false);
// adding the device to the control stack input slot 0
gControlBoxStack.adddevice(deviceHandle, 0);
// locking the device list on control stack
gControlBoxStack.setdevicelock(true);
// connect the control stack to the device for output
deviceconnectstack(deviceHandle, gControlBoxStack);
Next, add what's needed to deactivate the control effects stack in
HapticsDeactivated:
// unlocking the device list on control stack
gControlBoxStack.setdevicelock(false);
// removing the device from the control stack input slot 0
gControlBoxStack.removedevice(deviceHandle, 0);
// locking the device list on control stack
gControlBoxStack.setdevicelock(true);
// disconnecting the control stack output from the device
devicedisconnectstack(deviceHandle, gControlBoxStack);
One final step left... In HapticsInitialize you need to launch the
control box as follows:
// launch the control box
gControlBox = controlbox(effectparameters("_DefaultControlBox", gControlBoxStack), gControlBoxStack);
if (gControlBox != null)
{
setinputeffect(gControlBox);
}
Once again, run your script in fgsq.exe... you should now be able to move the
mouse cursor around the screen using the Falcon.
Part 6 - Creating Your Own Functions
This part of the tutorial will show you how to create and use your own
functions. In the process, we will do a little clean up of your current
script, by moving the activating and deactivating of effects stacks to
a seperate function. To see what the final script will look like, download it
here: fgen_tutorial_01f_functions.nut.
Just before the HapticsInitialize function, add the following:
//-------------------------------------------------------------
// activate or deactivate the effects stacks
//-------------------------------------------------------------
function ConnectOrDisconnectStacks (deviceHandle, bConnect)
{
}
This creates a (so far) empty function with two "parameters" or values that
are passed in to the function. The first paramenter (deviceHandle) references
the Falcon, and the second parameter (bConnect) will be either "true" or "false"
depending on whether you want to activate or deactivate the effects stacks.
Now look at the script instructions you have in HapticsActivated and
HapticsDeactivated. For each effects stacks (so far gEffectsStack
and gControlBoxStack), there are four instructions used to activate and
deactivate them... for example, to activate the gEffectsStack effects, you
call the following four commands:
gEffectsStack.setdevicelock(false);
gEffectsStack.adddevice(deviceHandle, 0);
gEffectsStack.setdevicelock(true);
deviceconnectstack(deviceHandle, gEffectsStack);
To deactivate the gEffectsStack effects, you would replace the call to
"adddevice" with a call to "removedevice", and replace the call to
"deviceconnectstack" with "devicedisconnectstack". Thus, your new function
ConnectOrDisconnectStacks should end up looking like this:
//-------------------------------------------------------------
// activate or deactivate the effects stacks
//-------------------------------------------------------------
function ConnectOrDisconnectStacks (deviceHandle, bConnect)
{
// unlocking the device list on stacks
gEffectsStack.setdevicelock(false);
gControlBoxStack.setdevicelock(false);
if (bConnect == true)
{ // add the device to the stacks, input slot 0
gEffectsStack.adddevice(deviceHandle, 0);
gControlBoxStack.adddevice(deviceHandle, 0);
}
else
{ // remove the device from the stacks, input slot 0
gEffectsStack.removedevice(deviceHandle, 0);
gControlBoxStack.removedevice(deviceHandle, 0);
}
// lock the device list on the stacks
gEffectsStack.setdevicelock(true);
gControlBoxStack.setdevicelock(true);
if (bConnect == true)
{ // connect the stacks to the device for output
deviceconnectstack(deviceHandle, gEffectsStack);
deviceconnectstack(deviceHandle, gControlBoxStack);
}
else
{ // disconnect the stacks from the device
devicedisconnectstack(deviceHandle, gEffectsStack);
devicedisconnectstack(deviceHandle, gControlBoxStack);
}
}
Now, go to HapticsActivated, remove all the effects stacks instructions
in the function, and replace them with a call to your new function:
// activate the effects stacks
ConnectOrDisconnectStacks(deviceHandle, true);
Do the same in HapticsDeactivated, though changing the "true" to "false":
// deactivate the effects stacks
ConnectOrDisconnectStacks(deviceHandle, false);
We have now greatly simplified the HapticsActivated and
HapticsDeactivated functions, as well as providing a central location
for dealing with effects stacks (the function ConnectOrDisconnectStacks).
Note that you can create your own functions to do anything you might need.
Part 7 - Creating a Force Whose Direction You Can Change
This part of the tutorial will teach you how to create a "constant" force,
whose force vector you can change based on keyboard presses. To see the final
script for this part, download it here:
fgen_tutorial_01g_constForce.nut
First we will create a new, third effects stack for this new effect. At the
top of your script, add the following:
// create a seperate effects stack for "movement" forces
gMovementStack <- effectstack("movement", 1.0);
// create a constant effect type
gConstantEffectID <- registereffect("Constant");
Next, add "gMovementStack" to ConnectOrDisconnectStacks. By now it
should be pretty obvious how to do this, but if you have trouble, take a
look at the final script for this tutorial part.
Now create the effect parameters for the movement effect, as well as a
variable to hold the effect. Just after defining "gMovementStack" and
"gConstantEffectID", add the following:
// create the paramenters for a constant effect for use as a movement force
gMovementEffectParameters <- effectparameters(gConstantEffectID, gMovementStack);
gMovementForce <- null;
Next we need to launch the movement force. In HapticsActivated, add
this:
// launch the movement force
gMovementForce = constantforce(gMovementEffectParameters, gMovementStack);
Then in HapticsDeactivated, deactivate the force:
// remove the movement force
gMovementForce.dispose();
gMovementForce = null;
Now lets give the movement force a quick test. Add the following to
HapticsThink:
// now adjust the movement effect based on button presses
if (gKeyInput.isinputdown(KEY_A))
{
gMovementForce.setforce(-4, 0, 0);
}
else
{
gMovementForce.setforce(0, 0, 0);
}
Run the script... if you now hold down the "A" key on the keyboard, you
should feel a force to the left. If you let go of the "A" key, the force
goes away. From here its easy to expand this code to handle keyboard
keys that set the force in any direction:
// now adjust the movement effect based on button presses
local moveX = 0;
local moveY = 0;
local moveZ = 0;
if (gKeyInput.isinputdown(KEY_A))
{
}
if (gKeyInput.isinputdown(KEY_D))
{
}
if (gKeyInput.isinputdown(KEY_S))
{
}
if (gKeyInput.isinputdown(KEY_W))
{
}
if (gKeyInput.isinputdown(KEY_E))
{
}
if (gKeyInput.isinputdown(KEY_Z))
{
}
gMovementForce.setforce(moveX, moveY, moveZ);
When you now run the script, you can use the "A" and "D" keys to push
left and right, the "W" and "S" keys to push up and down, and the "E" and
"Z" keys to push forward or back. You can also do combinations... hold
both "A" and "W" down at the same time to push both left and up.
Part 8 - Attaching Your Script to an Application
Now it is time to attach the script you have now built to a Windows
application.
First, bring up the F-Gen Manager, and click on the "NEW" button at the
bottom:
This will bring up a "create a new profile" window:
Now you just need to fill out the profile. First give it a name (I picked
"FGen_Tutorial"). Next, click the "Application Profile" button, and then
browse for the application executable of your choice (I picked Windows
Notepad, which you should be able to find in "C:\WINDOWS\System32\notepad.exe").
Finally, go to the bottom of the ProfileCreator, and browse for your script
file (which, for me, was in Desktop/tutorial_script/fgen_tutorial.nut). Save
the profile.
Now, if you have the F-Gen Manager running, everytime you launch the
application you chose (Notepad, for me), the Falcon will restart and run
using your script. You may need to exit out of the F-Gen Manager and
restart it before F-Gen recognizes your new profile, however.
Part 9 - Creating a Tuning Slider
Now that you have your script attached to an application through the F-Gen
Manager, you can create adjustable settings that you can access through the
F-Gen Mamager "Forces" tab. To start, we will create a slider for adjusting
the strength of the recoil forces. To see the final script for this part,
download it here: fgen_tutorial_01i_slider.nut
First, at the very top of your script (before creating the effects stacks),
add the following:
gRecoilTuneScale <- regvar("recoilScale", 1.0, "Recoil Scale", "The scale of recoil forces.", 0.0, 2.0, ui(UI_SLIDER));
This creates the slider, with a range between 0.0 and 2.0, set at a default
setting of 1.0. The current value of the slider is loaded into the variable
"gRecoilTuneScale" when the script is run. To then use this value to adjust
the recoil forces, change the line of the script that sets up the recoil
effects stack... replace the "1.0" with this variable, as follows:
// creating default Falcon effect stack
gEffectsStack <- effectstack("effects", gRecoilTuneScale.value());
Now, when you access the F-Gen Manager profile that uses your script, and
then click on the "Forces" tab, you should see the slider.
You should now be able to create a second slider for the movement effects
stack (see the script for this tutorial part if you have any trouble).
Part 10 - Tuning Keyboard Settings
This part of the tuturial will show you how to set up tunable keyboard
settings, so you can change the keys used to do actions in your script,
using the F-Gen Manager. To see the final script for this part, download it
here: fgen_tutorial_01j_tunekeys.nut
We are going to create settings to change the keys used for selecting what
type of recoil (currently, your script uses "0", "1" and "2"). At the
top of your script, add the following:
// keyboard tunings
gRecoilType <- regenum("Recoil", "Recoil",
regvalue("NoRecoil", KEY_0, "No Recoil Effect"),
regvalue("SimpleRecoil", KEY_1, "Simple Recoil Effect"),
regvalue("LoopRecoil", KEY_2, "Looping Recoil Effect"));
gKeyBindingUIRecoil <-regenumitem("keyBindingUIRecoil", "Recoil Keys", "Assign keys to switch recoil effect", gRecoilType, "SimpleRecoil", ui(UI_KEYBINDING));
This creates a list of three tunable key items, and then places them in a
drop-down list you can access in the F-Gen Manager "Forces" tab.
Next, we need to load the current values for each key setting into variables
we can access in the script:
// setup keyboard settings
gKeyBinds <- { };
gKeyBinds.noRecoil <- gRecoilType.value(0);
gKeyBinds.simpleRecoil <- gRecoilType.value(1);
gKeyBinds.loopRecoil <- gRecoilType.value(2);
Finally, replace the keyboard keys you use to select the recoil type in
HapticsThink with these new variables:
if (gKeyInput.wasinputjustpressed(gKeyBinds.noRecoil))
{
print(" ... select no recoil\n");
// set effect type to no recoil
gEffectType = 0;
}
else if (gKeyInput.wasinputjustpressed(gKeyBinds.simpleRecoil))
{
print(" ... select simple recoil\n");
// set effect type to single recoil
gEffectType = 1;
}
else if (gKeyInput.wasinputjustpressed(gKeyBinds.loopRecoil))
{
print(" ... select looping recoil\n");
// set effect type to looping recoil
gEffectType = 2;
}
Now if you access a F-Gen Manager profile that uses this script and then
click on the "Forces" tab, you will see a drop-down box that lets you
select each keyboard action and change which key is used for that action.
Part 11 - Sending Keyboard Commands from a Script
If you need to send keyboard keys from a script (especially complex keyboard
commands you can't set up in the F-Gen Manager), you can do it in your script.
This chapter will show you how to use a Falcon button to send a multi-key
command. Download the tutorial script here:
fgen_tutorial_02_sendkeys.nut
This test script will show you how to send "CTRL + Y" from your script.
The first thing for emulating keyboard keys is to set up global variables for
each key you want to use. At the top of your script, create the following:
// ---- setup keyboard settings
gSendCTRL <- inputsender(KEY_LCONTROL);
gSendY <- inputsender(KEY_Y);
The "inputsender" command creates the key setup for each key you want to control
(in this case, the left-ctrl key, and the Y key).
You can create a script function that will send the "Ctrl + Y" command"... this
function will press both keyboard keys, then release both keys.
//-------------------------------------------------------------
// tap Ctrl+Y
//-------------------------------------------------------------
function TapCTRLandY ()
{
gSendCTRL.press();
gSendY.press();
gSendY.release();
gSendCTRL.release();
}
Call this function anytime you need to trigger a "Ctrl + Y" keyboard command...
for example, to hit this keyboard combo anytime you tap the top Falcon button,
you might add the following to your HapticsThink function:
if (devicewasbuttonjustpressed(deviceHandle, FALCON_LIGHTNING))
{ // pressed top falcon button... hit keyboard Ctrl + Y
}
Part 12 - Getting the Current Falcon Position
This will be a very short chapter. If you ever need to get the current position of
the Falcon handle, here is how to do it. Download the tutorial script here:
fgen_tutorial_02_FalconPos.nut
To grab the position of the Falcon handle at any time, you simply need to use the
command "deviceaxis". You need to pass in the deviceHandle of the Falcon (usually
passed in by the core script functions like HapticsThink), and the number
of the axis. For example:
//-------------------------------------------------------------
// Run this script
// Called repeatedly while this acript is active
//-------------------------------------------------------------
function HapticsThink (deviceHandle)
{
local falcon_X = deviceaxis(deviceHandle, 0); // 0 = X axis (left/right)
local falcon_Y = deviceaxis(deviceHandle, 1); // 1 = Y axis (up/down)
local falcon_Z = deviceaxis(deviceHandle, 2); // 2 = Z axis (in/out)
// do stuff with the Falcon position here....
}
Part 13 - Accessing a Plugin
You can access various plugins in your scripts. These plugins add features to
F-Gen. This tutorial will show you how to access a simple plugin and use it.
Download the plugin and script for this tutorial here:
fgen_tutorial_02_plugin.zip
Inside the ZIP file, you will find two files... the squirrel script for this
tutorial, and a DLL. This DLL file is the plugin. Copy the DLL to your
"Program Files/Novint/F-Gen/plugins" directory.
This particular test plugin adds the ability to send debugging information to
a log file, adding the following new functions to F-Gen:
debugLog_open() - creates the log file
debugLog_close() - closes the log file
debugLog_print("text") - prints a text string to the log file
debugLog_printInt(value) - prints an integer value to the log file
debugLog_printFloat(value) - prints a floating point value to the log file
debugLog_printVector(valueX, valueY, valueZ) - prints a floating point vector to the log file
It also adds one other test function (testAddInts), which simply adds two
integers together returns the result (I know you can do this directly in the
scripts, but its just an example of how to get a return value from a plugin
function).
At the top of the script, tell your script that you want to use this plugin,
by adding:
// load the test plugin
loadplugin("SQTestDLL.dll");
Note that "debugLog_open()" is called in the HapticsActivated function,
and that "debugLog_close()" is called in the HapticsDeactivated
function.
The rest of the tutorial script should be fairly obvious... at the top of
HapticsThink I increment a frame counter (using the plugin function),
and then if you tap the Falcon LOGO button, the script prints out the
current frame count and the Falcon handle position to the log file.
The log file can then be found in "Program Files/Novint/F-Gen", called
"testScriptLOG.txt".
Part 14 - Creating a Plugin (requires some C++ knowledge)
You can create your own plugins for F-Gen, though it requires some knowledge of
C++ programming. You will need a copy of Microsoft Visual Studio C++ and
it helps if you have an idea what a DLL, or Dynamically Loaded Library is.
You can find the Visual Studio project for the "SQTestDLL.dll" plugin used
in the previous tutorial part (Part 13) here:
fgen_tutorial_pluginDLL.zip
Open the project (the SQTestDLL.vcproj file), which should launch Visual
Studio. First look under "Header Files" and open "SQTestDLL.h". Note that
each of the functions the plugin creates is defined using "SQ_GLOBAL_METHOD".
The first parameter is the name of the function. The second parameter is
an integer defining how many inputs the function has, and then the remaining
parameters (if any) define those inputs.
Now open "SQTestDLL.cpp" under "Source Files". You will see each of the
functions defined in SQTestDLL.h. Note that each one has an "SQ_" in front
of the function name, and each function returns "SQRESULT". Also notice
that the first input to each function is a "HSQUIRREVM v"... this allows
access to the squirrel script when returning values. Finally, notice each
function has an associated "SQ_BIND_GLOBAL_METHOD" call.
If a function does not return a value (such as the debugLog_open function),
it just returns "SQ_OK".
If a function does return a value (such as the testAddInts function), then
you must first push the return result on the script stack (using something
like "sq_pushinteger" or "sq_pushfloat"), and then return the number of
returned values.
You can get more information about plugins, including things like exporting
classes to a script, in the F-Gen SDK Examples directory.