Scripting

Hans Jorgensen edited this page Aug 4, 2016 · 8 revisions

Scripts are the primary way of interacting with FreePIE. Using scripts, you can specify not only the 1-to-1 button mappings common of most input mappers, but also the more nuanced, game-to-game logic for interpreting more complex inputs such as motion controller gestures or voice commands.

FreePIE 0.4.211.0 and later bases its scripting engine on Python. Like in most programming languages, execution in Python occurs line by line from top to bottom - each statement, whether it be a function call, variable assignment, or control instruction, happens one after the other. Relatively unique to Python is its use of whitespace: rather than use the curly braces and semicolons common of other languages, each statement always ends with a new line, and to indicate a block (such as a function body or if statement body), the "head" statement of the block ends in a colon and the lines underneath are indented:

# Define "doSomething" for later execution
def doSomething():
   x = 1
   y = 2

# Define "giveMeSomething" for later execution
def giveMeSomething():
   return 0

x = giveMeSomething()

if x == 2:
  doSomething()
elif x == 1:
  diagnostics.debug("doSomething already ran!")
else:
  x = 2

As shown above, comments are indicated with a # character, as in Bash scripts or Batch files.

However, unlike normal Python execution and most other programming languages, FreePIE uses a continuous execution model. In other words, rather than running your script once, FreePIE will run your script over and over again until you explicitly stop it. This means that scripts can simply copy data they receive from FreePIE's inputs (such as the keyboard or mouse) and expect to receive the same data every time - it is unnecessary to write while True: loops or other continuous polling constructs. For instance, the above script will first set x to 2, then to 1, and then will print "doSomething already ran!" indefinitely.

In order to counteract some side effects of this, FreePIE also provides a few extra mechanisms to your scripts:

  • Some devices do not update at every iteration (pretty much everything except keyboard and mouse). These devices instead provide update event handlers to which you can add a function to be triggered when that device does update, so that you don't request information from the device that will be the same as it was the last time you checked:
def update():
    #Do stuff
if starting:
    freeTrack.update += update
  • Some actions are only appropriate to take during the first iteration, such as subscribing to event handlers. Hence, FreePIE provides a global boolean variable called starting that is True on the first iteration and False otherwise (see above example).
  • If you need to save data between iterations, use global variables. Python defines global variables using a special syntax that requires each function requesting the global variable to declare its use at the start of the function body. Initialize these variables to whatever they need to be within your if starting: block:
def update():
    global yaw
    yaw = freeTrack.yaw

if starting:
    yaw = 0
    freeTrack.update += update

Other than these differences, FreePIE supports all Python 2 language constructs, including duck-typed variables, functions (including functions with mutable closures), classes/objects, enums (which the FreePIE libraries provide plenty of), etc. These features are well detailed in the Python syntax manual and are highlighted using syntax coloring in the FreePIE script editor.

FreePIE even includes the standard Python libs, importing them automatically so that you can use them in your script - even without using import statements:

yaw = math.degrees(freeTrack.yaw)

The code completion database does not currently support these libraries, though a future version of FreePIE will do so. In the meantime, feel free to consult the Python standard library reference for more details on how to use these libraries in your script. The math library is especially helpful in FreePIE, containing plenty of useful functions for converting units and patterns from input devices into values more useful for simulating other inputs.

Please see the script examples for more ideas.