Skip to content
This repository has been archived by the owner on Oct 20, 2020. It is now read-only.

InputManager

Rémy Bouquet edited this page Feb 13, 2018 · 1 revision

Input Manager

OSGJS has a custom way to handle the inputs. For an overview of the system please watch this presentation

Architecture

The Input Manager will listen to native events and will transform them in composite events. They will be placed in prioritised event queues and dispatched to their listeners during each update loop.

Native events are handled by input sources (Mouse, Keyboard, touch screen, etc).

It also provide an input group system that allows to enable or disable a set of inputs in one go.

The Input Manager is instantiated by the viewer. So there is one input manager for each created viewer.

API

InputManager

addInputSource(source): registers an InputSource with the input manager

getInputSource(name): returns an InputSource registered with the InputManager with the given name. Note that the name is defined in the input as the geName() returned value. Stock input sources and their names are:

  • InputSourceMouse: 'Mouse'
  • InputSourceKeyboard: 'Keyboard'
  • InputSourceTouchScreen: 'TouchScreen'
  • InputSourceDeviceOrientation: 'DeviceOrientation'
  • InputSourceWebVR: 'WebVR'
  • InputSourceGamePad: 'GamePad'

group(groupName): gets or creates a group It's recommended to maintain a hierarchical name space style of name for groups. See existing group names in InputConstants.js

addMappings(mappings): adds an input mapping to the InputManager See addMappings in the usage section and in the examples section for more information

setEnable(groupName, enable): enables or disables a group of inputs.

setPriority(eventName, priority): sets the priority of an event or the priority of all the events in a group see usage section for more information

getHigherPriority(groupName): return a priority value that is higher than the one of the given group name.

setParam(paramName, value): sets a parameter on the input manager that can be retrieved with getParam()

getParam(paramName): gets a parameter that has previsously been set with setParam()

cleanup(): disable all groups of this input manager and remove all event listener from the input sources targets

dumpGroups(filter, onlyEnabled): display all the registered groups in the console. Also available anytime as window.dumpInputGroups()

dumpEventSequence(filter, onlyEnabled): display all events registered with the input manager sorted by priority.
Also available as window.dumpEventSequence(filter, onlyEnabled)

Usage

Get the input manager
viewer.getInputManager();
Create or get a group
inputManager.group('group name');

Note that existing groups are declare as constants in InputConstants.js

Add mappings
inputManager.group('group name').addMappings(
    {
        myMethod: 'nativeevent',
        myMethod2: ['nativeevent2', 'nativeevent3']
    },
    listener
);

or

inputManager.addMappings(
    {
        'group name:myMethod': 'nativeevent',
        'group name:myMethod2': ['nativeevent2', 'nativeevent3']
    },
    listener
)

Note that this notation will result in the creation of a group 'group name' if it doesn't already exist.
In both examples the inputManager will try to find methods myMethod and myMethod2 in the listener instance

You can also directly bind a function callback

var myCallback = function(ev){
    console.log(ev);    
};

inputmanager.addMappings(
    {
        'group name:aName': 'nativeevent'
    },
    myCallback
)
Choosing a group name, for easy enabling disabling

Group names should be namespaces. For example in osgjs, the input groups for the manipulators are under a master group called "scene": For example, let's say we have those 3 groups.

scene.manipulatros.orbit.mousekeyboard
scene.manipulators.fps.mousekeyboard
scene.manipulators.cad.mousekeyboard

This way ou can disable all the manipulators by calling `` Even is scene.manipulators is not a physical group. Note that this will not remove all the listeners from the canvas but, prevent the event for being placed in the event queues. The groups will have a 'scene.manipulatros' mask.

However doing

inputManager.setEnable('scene.manipulators.orbit.mousekeyboard', false);

Will remove all the listeners from the canvas.

This allows to have complex configurations like this:

scene.manipulatros.orbit.mousekeyboard  (enabled)
scene.manipulators.fps.mousekeyboard  (disabled)
scene.manipulators.cad.mousekeyboard  (enabled)

Calling

inputManager.setEnable('scene.manipulators', false);

Will prevent all events from this groups to reach their listeners. and when calling

inputManager.setEnable('scene.manipulators', true);

All the sub groups will be restored in the state they were before:

scene.manipulatros.orbit.mousekeyboard  (enabled)
scene.manipulators.fps.mousekeyboard  (disabled)
scene.manipulators.cad.mousekeyboard  (enabled)

Events

Supported events
InputSourceMouse
'click',
'contextmenu',
'dblclick',
'mousedown',
'mouseenter',
'mouseleave',
'mousemove',
'mouseover',
'mouseout',
'mouseup',
'wheel'
InputSourceKeyboard
'keydown', 
'keyup', 
'keypress'
InputSourceTouchScreen
'touchstart', 
'touchend', 
'touchcancel', 
'touchmove'

Also all events supported by hammer.js and their derivatives

'pan',
'pinch',
'press',
'rotate',
'swipe',
'singletap',
'doubletap'

for more information on hammer.js event see here

InputSourceDeviceOrientation
'deviceorientation', // device gyroscope change
'orientationchange' // device portrait / landscape change 
InputSourceGamePad
'buttondown',
'buttonup',
'buttonvalue', // value change for analog buttons
'axis', // axis change
'gamepadconnected',
'gamepaddisconnected'
InputSourceWebVR
'vrdisplayposechanged',  // Webvr headset moved
'vrdisplayconnected',  // a new webvr headset has been found
'vrdisplaydisconnected', // a webvr headset disconnected
'vrdisplaynotfound' // no vr display were found

Event data

Composite events resulting from Mouse events and touch events will have the following data:

  • canvasX: The x position of the cursor inside the canvas HTML element.
  • canvasY: The y position of the cursor inside the canvas HTML element.
  • glX: the x position of the cursor in the gl viewport.
  • glX: the y position of the cursor in the gl viewport.

Note that the gl coordinates depends on the pixel ratio used by the viewer. The viewer sets this value as an external parameter on the input manager that is used by the input sources to compute the coordinates.
If you are using a different way of computing the pixel ratio, you can set this parameter yourself on the input manager.

inputManager.setParam('pixelRatio', value);

Then original standard data are copied to the composite event. To see the data contained in standard events please refer to MDN

All composite events contains a _nativeEvent array containing all native events that occured and made this composite event be despatched. This is not recommended to use them except for debugging purpose.

Advanced event mapping

With the InputManager, you can map native events to a callback like this (for example a mousedown):

inputManager.group('group').addMapping(
    {
        start:'mousedown'
    },
    listener
)

This will call the listener.start() method each time there is a mousedown event But you can map more advanced events like:

inputManager.group('group').addMapping(
    {
        start:'mousedown ctrl 2'
    },
    listener
)

This will call the listener.start() method when ever the mousedown event occur on a right click (mouse button 2) and when the ctrl modifier key is pressed.

Mouse event

For mouse events the supported format is:

'eventname <modkey> <button>'
  • eventname is a native event name supported by the InputSourceMouse.
  • modkey is one of the ctrl, shift, alt, meta keyword. If you want to exclude a modifier you can prefix it with '!'
  • button is the button id number and must be a value >=0.

Note that the order of optional params is not important. For the 'wheel' event, the button parameter has no effect.

examples

inputManager.group('group').addMapping(
    {
        startPan:'mousedown ctrl 2', // right click control
        startZoom:'mousedown !ctrl 2', // right click with control specifically not pressed
        startRotate: 'mousedown ctrl shift alt 0' // left click with control shift and alt pressed.
    },
    listener
)
Key event

For keyboard events the supported format is:

'eventname <modkey> <key or code>'
  • eventname is a native event name supported by the InputSourceKeyboard.
  • modkey is one of the ctrl, shift, alt, meta keyword. If you want to exclude a modifier you can prefix it with '!'
  • key or code is the key value (like 'a' for letter a, or a code like 'ArrowUp' exception for the space key that is 'space' and not ' ' ).

Note that the order of optional params is not important.

examples

inputManager.group('group').addMapping(
    {
        selectAll:'keydown ctrl a', // ctrl + a keys
        typeSpace:'keyup space', // release space bar
        selectLeft: 'keydown ArrowLeft alt' // press left arrow with the alt key down.
    },
    listener
)
Touch event

For touch events the supported format is:

'eventname  <number of touches>'
  • eventname is a native event name supported by the InputSourceTouchScreen.
  • number of touches the number of fingers touching the screen.

Note that release events like "touchend 2" will be triggered if there was a touchstart 2 before and that at least one finger has been released.

examples

inputManager.group('group').addMapping(
    {
        startPan:'touchstart 2', // 2 fingers touch on the screen
        rotateEnvironment:'pan 3', // paning with 3 fingers
        flash: 'singletap 2' // Tap event with 2 fingers.
    },
    listener
)
GamePad event

The gamepad Api is not event based. The inputManager will poll the device each frame and generate appropriate events. For now only the standard gamepad layout is supported. For gamepad events the supported format is:

'eventname  <button>'
  • eventname is a native event name supported by the InputSourceGamePad.
  • button the button index

examples

inputManager.group('group').addMapping(
    {
        startPan:'buttondown 2', // button 2 has been pressed
        rotateEnvironment:'buttonvalue 7', // analog button 7 value changed 
        flash: 'axis 2' // axis 2 value changed
    },
    listener
)
Device orientation event

There is no rich recognition for device orientation events

examples

inputManager.group('group').addMapping(
    {
        changeOrientation:'deviceorientation', // the device moved.
        switchScreenOrientation:'orientationchange' // screen orientation changed
    },
    listener
)
Webvr event

There is no rich recognition for webvr events

examples

inputManager.group('group').addMapping(
    {
        changeOrientation:'vrdisplayposechanged', // the device moved.
        registerDevice:'vrdisplayconnected', // a headset has been plugged in
        fallbackMode: 'vrdisplaynotfound' // no vr display found
    },
    listener
)

When initalizing the viewer you can pass a pollInterval parameter. This parameter will define the time the input source will wait between 2 device polling.

InputSources: {
    WebVR: {
        pollInterval: 2000 // will poll for a headset every 2 seconds 
    }    
}

Note that 'vrdisplayconnected' 'vrdisplaydisconnected' events can only be triggered when the input source is in poll mode.

To disable the poll mode you can set a value lower or equal to 0 for the pollInterval parameter. In this mode, the input source won't poll for the device automatically. You can manually poll the device using

inputManager.getInputSource('WebVR').pollHeadset();

This will trigger the 'vrdisplayconnected' if a device is found or else, the 'vrdisplaynotfound'.