bw logo

Chapter 2. User Input

The BigWorld client uses a combination of Windows messages and the Windows raw input API for keyboard and mouse input. It reads key-up, key-down, and character press events from the keyboard as well as high resolution movement events from the mouse. It uses the DirectInput API to read button and axis movement events from joysticks.

2.1. Key events

Key events, encapsulated by the KeyEvent object (BigWorld.KeyEvent in Python), are generated by devices that have keys or buttons. This includes the keyboard, mouse buttons, and joystick buttons.

The two basic types of key events are key-down and key-up.

2.1.1. Character events

If a KeyEvent is generated by the keyboard, it may have a character attached to it. The character generated by a particular key is determined by the currently set locale and input language in the operating system, and is represented by the KeyEvent.character member (a Unicode string).

Dead character keys are supported (e.g. in Spanish, a user can type the letter é by first pressing the apostrophe key followed by the e key). In this case the first key press will not have a character associated with it, and the second key press will have the final character.

The BigWorld client supports advanced Input Method Editors (IME). See Input Method Editors (IME) for details on using an IME in your game.

2.1.2. Auto-repeat

The keyboard will generate auto-repeat events when keys are held down, based on the user's operating system settings (e.g. repeat delay). The mouse and joystick do not generate auto-repeat events.

Auto-repeat events are sent as additional key-down events, however scripts that do not want to handle repeat events can call the KeyEvent.isRepeatedEvent method to determine whther or not it is an auto-repeat event.

2.1.3. Sequence of events

When the user presses a button (keyboard, mouse or joystick), the sequence of events are:

  • The first key-down event.

  • If the key is held down, multiple key-down events are raised due to auto-repeat (keyboard only).

  • A key-up event is triggered when the user releases the button.

The output from the user input module is processed by a number of other modules, which take it in turn to examine events and either consume or ignore them. If an event is not consumed by any module then it is discarded. The order of modules that get a turn at the events is as follows:

  • Debug — Special keys, consoles, etc.

  • Personality script — Global keys.

  • Application — Hard-coded keys such as QUIT.

  • Player script — The rest, which is the major part of the processing.

Note

Note that the GUI system does not automatically receive input, instead it is up to the script write to choose when. This could be either in the personality script, or in the player script. The most obvious place is in the personality script callbacks, for example in the personality script's handleKeyEvent, you should call GUI.handleKeyEvent() and check the return value.

Similarly, the active camera also does not automatically receive input events. It is up to the Python scripts to decide when and where the camera receives user input.

2.1.4. Sinking events

The BigWorld client performs event matching to ensure consistent module behaviour. If a key-down event is consumed by a module, that module's identifier is recorded as the sink of the event's key number. When the corresponding auto-repeat and key-up event arrives, it is delivered directly to that module. For example, if a chat console is brought up (and inserted into the list) while the player is running, and the user subsequently releases the run key, then the player script will still get the key-up event for that key, and be able to stop the run action.

In some cases it may be desired to temporarily block certain key events from being passed into the scripts. For example, the GUI scripts may handle a key down event by removing the current GUI screen and replacing it with a new GUI screen. By default, since the new GUI screen has become the active screen by the time handleKeyEvent returns, any associated auto-repeat and key-up events will be posted to the new GUI screen creating possibly unwanted behaviour.

The BigWorld.sinkKeyEvents function can be used to stop all key events for the given key-code from reaching the scripts until (and including) the next key-up. See the Python API guide for details.

2.1.5. Mouse cursor position

It is often a requirement to know where the mouse was when a key event occured (i.e. rather than where the mouse is at the time of handling the event), especially when processing mouse button events. Therefore, the mouse cursor position is available via the KeyEvent.cursorPosition property, and should be used instead of GUI.mcursor().position where ever possible.

2.2. Mouse

2.2.1. Movement

High resolution mouse movement events are sent to the scripts as a MouseEvent. This object exposes three direction deltas.

  • The dx and dy members are signed integers indicating movement of the mouse in the X and Y directions.

  • The dz member represents movement of the mouse wheel.

    Note

    If multiple mouse deltas arrive from the driver within a single frame, they are accumulated into a single MouseEvent.

Similar to the KeyEvent object, the mouse cursor position for when the event occured is available as a member of the MouseEvent object.

2.2.2. Buttons

Mouse buttons are sent as a KeyEvent, however they do not generate auto-repeat events. See Key events for details.

2.3. Joystick

The BigWorld client will automatically detect the first joystick device attached to the system, and is been designed to be used with dual-stick style joypads.

2.3.1. Axis events

When axis events occur, they will be sent to the scripts as an AxisEvent object via the handleAxisEvent personality script function.

2.3.2. Buttons

Joystick buttons are sent as a KeyEvent, however they do not generate auto-repeat events. See Key events for details.

2.3.3. Controlling player direction

The C++ engine will automatically pass axis events to the active cursor, so the direction cursor can be joystick controlled by setting it as the active cursor using BigWorld.setCursor. The direction cursor will process any events generated by the right axis.

2.3.4. Avatar movement

The C++ engine will also give the physics subsystem a chance to handle axis events. The physics treats axis input as a special case and will scale movement speed by how far the user as pushed the joystick forward.

In order to enable joystick support on movement physics, set the Physics.joystickEnabled property to True and be sure to set joystickFwdSpeed and joystickBackSpeed properties to values appropriate for your game.