Input System Overview

CryInput's main purpose is to provide an abstraction over obtaining input/status from different input device such as a keyboard, mouse, joysticks, 360/PS3 gamepads, etc.

It also has support for sending feedback events back to the input devices, for example in the form of force feedback events.

The common interfaces for the input system can be found in IInput.h, in the CryCommon project.

IInput

The main interface to the input system is IInput. An instance implementing this interface is created during system initialisation automatically in the InitInput function (InitSystem.cpp in CrySystem, see also CryInput.cpp in CryInput).

Only one instance of this interface will be created. The updating and shutdown of the input system will also be managed by CrySystem.

This IInput instance will be stored in the SSystemGlobalEnvironment structure gEnv, and can be accessed through gEnv->pInput or alternatively through the system interface by GetISystem()->GetIInput(). Access through the gEnv variable is the most commonly used method.

IInputListener

One of the most common use cases in relation with the input system is to create listener classes in other modules ( e.g. CryGame ) by inheriting from IInputEventListener and registering/unregistering the listener class with the input system to receive notifications on input events.

For example, the Action Map System registers itself as an input listener and forwards game events only for the keys defined in the profile configuration files to further abstract the player input from device->game.

SInputEvent

This is the structure that encapsulates information created by any input device and are received by all input event listeners.

InputDevice

InputDevices normally relate directly to the physical input devices such as a joypads, mouse, keyboard, etc. To create a new input device all that's needed is to implement all functions in the IInputDevice interface and registering an instance of it with the Input System via the AddInputDevice function.

The input system will handle the deleting of the pointer to the input device, so it may lead to problems if created in a different module.

The Init function will be called when registering the IInputDevice with the Input System, so there's no need to call it manually when creating the input devices.

The Update function will be called at every update of the Input System, and this is generally where the state of the device should be checked/updated and the Input Events generated and forwarded to the InputSystem.

It's common for Input Devices to create and store list of SInputSymbol for each symbol the input device is able to generate in the Init function, and then in the update function lookup the symbol for the button/axis that have changed and use those ( via their AssignTo function ) to fill in most of information needed for the events and forward them to the input system.

Example:

// function from CInputDevice ( accessible only within CryInput )
MapSymbol( ... )
{
     SInputSymbol\* pSymbol = new SInputSymbol( deviceSpecificId, keyId, name, type );
     pSymbol->user = user;
     pSymbol->deviceId = m_deviceId;
     m_idToInfo\[ keyId \] = pSymbol;
     m_devSpecIdToSymbol\[ deviceSpecificId \] = pSymbol;
     m_nameToId\[ name \] = deviceSpecificId;
     m_nameToInfo\[ name \] = pSymbol;

     return pSymbol;
}
bool CMyKeyboardInputDevice::Init()
{
      ...
     //CreateDeviceEtc();
      ...
     m_symbols\[ DIK_1 \] = MapSymbol( DIK_1, eKI_1, "1" );
     m_symbols\[ DIK_2 \] = MapSymbol( DIK_2, eKI_2, "2" );
      ...
}
void CMyKeyboardInputDevice::Update( ... )
{
     // Acquire device if necessary
      ...
     // Will want to check for all keys probably, so the following section might be part of a loop
     SInputSymbol\* pSymbol = m_symbols\[ deviceKeyId \];
      ...
     // check if state changed
      ...
     // This is an example for when pressed, see ChangeEvent function for axis type symbols
     pSymbol->PressEvent( true );
 
     SInputEvent event;
     pSymbol->AssignTo( event, modifiers );
 
     gEnv->pInput->PostInputEvent( event );
}

To forward events to the input system so that event listeners can receive them, use the PostInputEvent function from IInput.

If adding your input device to CryInput, it may be useful to inherit directly from CInputDevice as it already provides a generic implementation for most functions in IInputDevice.

This file is included with the full source of CryEngine and is not available in the FreeSDK or GameCodeOnly solutions. For these licenses please derive from IInputDevice directly.

输入系统总览

CryInput 的主要目的是提供抽象概念以从诸如键盘、鼠标、操纵杆、xbox/ps3 joypads 等不同的输入设备中获取输入/状态。它也支持将反馈事件发送回至输入设备,例如以强制反馈事件的形式发送。

输入系统的通用界面可以在 CryCommon 项目的 IInput.h 中找到。

IInput

输入系统的主界面是 IInput。在初始化输入函数(可以参阅 CrySystem 中的 InitSystem.cpp,也可以参阅 CryInput 中的 CryInput.cpp)中系统自动初始化时可以创建实现这个界面的实例。将仅创建这个界面的一个实例。CrySystem 也将管理输入系统的更新和停止。

这个 IInput 实例将保存于 SSystemGlobalEnvironment structure gEnv 中,可以通过 gEnv->pInput 或通过 GetISystem()->GetIInput() 系统界面访问。最常用的方法是通过 gEnv 变量访问。

IInputListener

关于输入系统的最常见用例之一是通过使用输入系统从 IInputEventListener 和注册/取消注册监听器类中继承,在其他模块(例如 CryGame)中创建监听器类,以接收输入事件的通知。

例如,动作(输入)映射表系统寄存器自身作为输入监听器和仅转发在配置文件中定义的关键帧的游戏事件,以进一步将设备中的玩家输入抽象到游戏中。

SInputEvent

这是任意输入设备创建的压缩信息结构,可以被所有输入事件监听器接收。

InputDevice

输入设备通常与诸如 joypads、鼠标、键盘等的物理输入设备直接相关。若要创建新的输入设备,所需做的是实现 IInput 设备界面的所有函数和通过 AddInputDevice 函数使用输入系统注册该界面的实例。

使用输入系统注册 IInputDevice 时将调用初始化函数,因此创建输入设备时不需要手动调用该函数。

输入系统每次更新时都将调用更新函数,并且这通常是应该检查/更新设备状态和生成输入事件以及转发到输入系统的位置。

输入设备通常创建并保存 SInputSymbol 列表,初始化函数中的输入设备能够生成每个符号,然后在更新函数查找中已更改的按钮/轴符号,并使用那些符号(通过其 AssignTo 函数)填充 这些事件所需的大部分信息并将其转发至输入系统。

示例:

// function from CInputDevice ( accessible only within CryInput )
MapSymbol( ... )
{
     SInputSymbol\* pSymbol = new SInputSymbol( deviceSpecificId, keyId, name, type );
     pSymbol->user = user;
     pSymbol->deviceId = m_deviceId;
     m_idToInfo\[ keyId \] = pSymbol;
     m_devSpecIdToSymbol\[ deviceSpecificId \] = pSymbol;
     m_nameToId\[ name \] = deviceSpecificId;
     m_nameToInfo\[ name \] = pSymbol;

     return pSymbol;
}
bool CMyKeyboardInputDevice::Init()
{
      ...
     //CreateDeviceEtc();
      ...
     m_symbols\[ DIK_1 \] = MapSymbol( DIK_1, eKI_1, "1" );
     m_symbols\[ DIK_2 \] = MapSymbol( DIK_2, eKI_2, "2" );
      ...
}
void CMyKeyboardInputDevice::Update( ... )
{
     // Acquire device if necessary
      ...
     // Will want to check for all keys probably, so the following section might be part of a loop
     SInputSymbol\* pSymbol = m_symbols\[ deviceKeyId \];
      ...
     // check if state changed
      ...
     // This is an example for when pressed, see ChangeEvent function for axis type symbols
     pSymbol->PressEvent( true );
 
     SInputEvent event;
     pSymbol->AssignTo( event, modifiers );
 
     gEnv->pInput->PostInputEvent( event );
}

若要转发事件至输入系统以便事件监听器可以接收这些事件,可以使用 IInput 中的 PostInputEvent 函数。

若添加您的输入设备至 CryInput,直接从 CInput 设备中继承可能有用,因为其已为多数 IInput设备中的函数提供通用实现。

这个文件只包含在完整引擎源代码中。FreeSDK和GameCodeOnly解决方案不包含此文件。请此类用户直接从IInputDevice类继承并实现相应功能。