SDL
SDL
enables fflive
to use input devices such as
keyboard,
mouse, and
joysticks.
A global constructor SDL()
is built-in to the quickjs
engine.
This is a simple wrapper around SDL
functionality.
This page is mostly based on SDL
documentation itself.
NOTE: Currently, you need to explicitly poll for the events.
I plan on moving this to using
async
functions
in the future.
NOTE2: SDL
support only works with fflive
(and not ffgac
or ffedit
).
SDL Constructor
The new SDL()
constructor is used to create a new SDL
object.
Syntax
new SDL()
Return value
The new SDL
object.
Examples
const sdl = new SDL();
if ( sdl )
print("SDL initialized");
SDL.prototype.numJoysticks()
This is a wrapper around SDL_NumJoysticks().
Syntax
numJoysticks()
Return value
Returns the number of attached joysticks on success or a negative error code on failure.
Examples
const sdl = new SDL();
const numJoysticks = sdl.numJoysticks();
print(`numJoysticks: ${numJoysticks}`);
SDL.prototype.joystickOpen()
This is a wrapper around SDL_JoystickOpen().
NOTE: The resulting object is kept internally in the SDL
object.
Syntax
joystickOpen(device_index)
Parameters
device_index
is the index of the joystick to query.
Return value
Nothing useful.
Examples
const sdl = new SDL();
sdl.joystickOpen(0);
SDL.prototype.joystickClose()
This is a wrapper around SDL_JoystickClose().
NOTE: The input parameter is obtained internally from the SDL
object
(joystickOpen()
must have already been called).
Syntax
joystickClose()
Return value
Nothing useful.
Examples
const sdl = new SDL();
sdl.joystickOpen(0);
sdl.joystickClose();
SDL.prototype.gameControllerOpen()
This is a wrapper around SDL_GameControllerOpen().
NOTE: The resulting object is kept internally in the SDL
object.
Syntax
gameControllerOpen(joystick_index)
Parameters
joystick_index
is the device_index of a device, up to SDL_NumJoysticks()
.
Return value
Nothing useful.
Examples
const sdl = new SDL();
sdl.gameControllerOpen(0);
SDL.prototype.gameControllerClose()
This is a wrapper around SDL_GameControllerClose().
NOTE: The input parameter is obtained internally fromt the SDL
object
(gameControllerOpen()
must have already been called).
Syntax
gameControllerClose()
Return value
Nothing useful.
Examples
const sdl = new SDL();
sdl.gameControllerOpen(0);
sdl.gameControllerClose();
SDL.prototype.getEvent()
This is a poll-based abstraction around SDL_PeepEvents().
You should call this function repeatedly and process the resulting SDL_Event
until the function returns null
.
Syntax
getEvent()
Return value
An SDL_Event
(defined below) if available, null
otherwise.
Examples
const sdl = new SDL();
sdl.joystickOpen(0);
while ( true )
{
const e = sdl.getEvent();
if ( e === null )
break;
print(JSON.stringify(e));
}
sdl.joystickClose();
SDL_Event
The SDL_Event
s returned by getEvent()
are a representation of the
SDL_Event
structure from SDL
.
The structure is different depending on the type
of event.
SDL_KeyboardEvent
TODO: number
:
SDL.SDL_KEYDOWN
or SDL.SDL_KEYUP
.
TODO: number
:
Event timestamp, in milliseconds.
TODO: number
:
SDL.SDL_PRESSED
or SDL.SDL_RELEASED
.
TODO: number
:
Non-zero if this is a key repeat.
TODO: number
:
SDL
physical key code - see SDL_Scancode
for details.
- The key codes are available in the global
SDL
object, i.e.:SDL.SDL_SCANCODE_UNKNOWN
.
TODO: number
:
SDL
virtual key code - see SDL_Keycode
for details.
- The key codes are available in the global
SDL
object, i.e.:SDL.SDLK_UNKNOWN
.
TODO: number
:
Current key modifiers.
SDL_JoyAxisEvent
TODO: number
:
SDL.SDL_JOYAXISMOTION
.
TODO: number
:
Event timestamp, in milliseconds.
TODO: number
:
The joystick instance id.
TODO: number
:
The joystick axis index.
TODO: number
:
The axis value (range: -32768
to 32767
).
SDL_JoyBallEvent
TODO: number
:
SDL.SDL_JOYBALLMOTION
.
TODO: number
:
Event timestamp, in milliseconds.
TODO: number
:
The joystick instance id.
TODO: number
:
The joystick trackball index.
TODO: number
:
The relative motion in the X direction.
TODO: number
:
The relative motion in the Y direction.
SDL_JoyHatEvent
TODO: number
:
SDL.SDL_JOYHATMOTION
.
TODO: number
:
Event timestamp, in milliseconds.
TODO: number
:
The joystick instance id.
TODO: number
:
The joystick trackball index.
TODO: number
:
The hat position value.
SDL_JoyButtonEvent
TODO: number
:
SDL.SDL_JOYBUTTONDOWN
or SDL.SDL_JOYBUTTONUP
.
TODO: number
:
Event timestamp, in milliseconds.
TODO: number
:
The joystick instance id.
number
:
The joystick button index.
TODO: number
:
SDL.SDL_PRESSED
or SDL.SDL_RELEASED
.
SDL_ControllerAxisEvent
TODO: number
:
SDL.SDL_CONTROLLERAXISMOTION
.
TODO: number
:
Event timestamp, in milliseconds.
TODO: number
:
The joystick instance id.
TODO: number
:
The controller axis (SDL_GameControllerAxis
).
TODO: number
:
The axis value (range: -32768
to 32767
).
SDL_ControllerButtonEvent
TODO: number
:
SDL.SDL_CONTROLLERBUTTONDOWN
or SDL.SDL_CONTROLLERBUTTONUP
.
TODO: number
:
Event timestamp, in milliseconds.
TODO: number
:
The joystick instance id.
number
:
The controller button (SDL_GameControllerButton
).
TODO: number
:
SDL.SDL_PRESSED
or SDL.SDL_RELEASED
.
Full Example
This example will open the first joystick found (I use a cheap SNES USB
controller),
and use the arrow keys to add motion to the entire frame.
let sdl;
let cur_pan_mv = new MV(0,0);
let step = 0;
export function setup(args)
{
// select motion vectors
args.features = [ "mv" ];
// parse params from command line (a number is expected)
if ( !("params" in args) )
throw new Error("A parameter is expected for the step in the command line (use -sp <step>).");
step = args.params;
// initialize SDL with first joystick
sdl = new SDL();
const numJoysticks = sdl.numJoysticks();
console.log(`numJoysticks: ${numJoysticks}`);
if ( numJoysticks > 0 )
sdl.joystickOpen(0);
}
export function glitch_frame(frame)
{
const fwd_mvs = frame.mv?.forward;
if ( !fwd_mvs )
return;
// set motion vector overflow behaviour in ffglitch to "truncate"
frame.mv.overflow = "truncate";
// parse all SDL events
while ( true )
{
const event = sdl.getEvent();
if ( event === null )
break;
// Uncomment the following line to debug the event structure.
// console.log(JSON.stringify(event));
if ( event.type === SDL.SDL_JOYAXISMOTION )
{
// Update current MV on arrow keys
switch ( event.value )
{
case -32768: cur_pan_mv[event.axis] += step; break;
case 32767: cur_pan_mv[event.axis] -= step; break;
}
}
}
// pan entire frame with current MV
fwd_mvs.add(cur_pan_mv);
}
Run it with:
$ fflive -i input.avi -s script.js -sp 3