Integrating OIS With Irrlicht

OIS is a free object oriented input library that is licensed under the zlib/libpng license.

Why would you use OIS in place of Irrlicht's already platform independent input processing? In addition to handling multiple keyboards and mice, OIS also supports joysticks, game controllers, and feedback devices (e.g. forcefeedback).

Getting OIS

OIS is hosted on sourceforge so you may either download the current source code release at:

or checkout the source code via CVS:

Building OIS on Windows

OIS provides both a Visual Studio solution file and a CodeBlocks (mingw) project for building static libraries on Windows. To build using Visual Studio, open the solution file located in the directory "Win32" off of the OIS installation directory {OIS Install}.

The solution file contains both "debug" and "release" build configurations. Choose the configuration appropriate to your needs. If you build both configurations, the following static libraries will be generated:

  • OIS_static.lib - Release Version
  • OIS_static_d.lib - Debug Version

Both of these libraries will be located in: "{OIS Install}/lib"

Building OIS on Linux

You should be able to find a package in your distro's package manager. If you can't find it, go and complain. You can also install OIS manually using the well-known procedure:

  • ./bootstrap
  • ./configure
  • make && make install

As you may have guessed, this will install libOIS.a and libOIS.so in /usr/local/lib. If you want them in /usr/lib, use --prefix=/usr for ./configure.

Application Integration

Provided in the links at the bottom of this page is a convenience/reference class (COIS) which wraps OIS initialization, processing, and input event handling. If you choose to use COIS, integration is simply a matter of creating/using a class which inherits from COIS and overrides the default event handlers:

class MyOIS: public COIS
{
public:
    MyOIS(IrrlichtDevice* idevice, bool showCursor=true,
        bool enableDebug=true) : COIS(idevice, showCursor, enableDebug) {};

    // override default COIS input event handlers
    bool keyPressed( const OIS::KeyEvent& arg );
    bool keyReleased( const OIS::KeyEvent& arg );
    bool mouseMoved( const OIS::MouseEvent &arg ); 
    bool mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id );
    bool mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id );
    bool buttonPressed( const OIS::JoyStickEvent &arg, int button );
    bool buttonReleased( const OIS::JoyStickEvent &arg, int button );
    bool axisMoved( const OIS::JoyStickEvent &arg, int axis );
    bool povMoved( const OIS::JoyStickEvent &arg, int pov );

};

MyOIS* mois;
bool running=true;
int capNumber=1;

bool MyOIS::keyPressed(const OIS::KeyEvent& arg )
{
    //
    // for default Irrlicht gui event processing
    //
    if(COIS::keyPressed(arg))
        return true;

    switch(arg.key)
    {
    case OIS::KC_ESCAPE:
        running = false;
        return true;

    case OIS::KC_SYSRQ: /* print screen */

        IImage* image = videoDriver->createScreenShot();
        char buf[32];

        sprintf(buf,"cap%.2d.png",capNumber++);

        videoDriver->writeImageToFile(image,buf);

        image->drop();
        break;
    }
    return false;
}

bool MyOIS::keyReleased( const OIS::KeyEvent& arg )...
bool MyOIS::mouseMoved( const OIS::MouseEvent &arg )...
bool MyOIS::mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id )...
bool MyOIS::mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id )...
bool MyOIS::buttonPressed( const OIS::JoyStickEvent &arg, int button )...
bool MyOIS::buttonReleased( const OIS::JoyStickEvent &arg, int button )...
bool MyOIS::axisMoved( const OIS::JoyStickEvent &arg, int axis )...
bool MyOIS::povMoved( const OIS::JoyStickEvent &arg, int pov )...

In your initialization code (after Irrlicht's "device" has been created), you'll need to create an instance of your COIS derived class:


//
// in your initialization code
//
mois = new MyOIS(device);
if(mois->initialize())
    printf("OIS Initialization Error\n");

And finally, you'll need to include OIS input processing/capturing in your main loop:


//
// include OIS processing in your main loop
//

while(device->run() && running)
{
    // capture OIS input
    mois->capture();

    videoDriver->beginScene(true, true, SColor(255,100,101,140));

    sceneManager->drawAll();
    gui->drawAll();

    videoDriver->endScene();
 }

Integration Notes

Irrlicht GUI Event Processing. OIS keyboard and mouse events do NOT directly translate to Irrlicht keyboard and mouse events. In other words, an Irrlicht irr:EKEY_CODE::KEY_RIGHT is not the same as OIS::KeyCode::KC_RIGHT. If you directly feed an OIS::KeyCode into Irrlicht's GUI environment, you'll likely receive unexpected results.

Fortunately COIS contains code that automatically converts OIS Key/Mouse events to the appropriate Irrlicht event and then optionally injects the converted event into Irrlicht's GUI environment. In order for this processing to take place, your code must enable GUI processing and then invoke the default COIS event Handler:

// By default GUI event injection is disabled, so enable it somewhere in your code.
mois->setGUIEnabled(true);

// In your overridden handler, invoke the default COIS handler.  If it returns
// "true", Irrlicht's GUI Environment handled the event.
bool MyOIS::keyPressed(const OIS::KeyEvent& arg )
{
    //
    // for default gui handling
    //
    if(COIS::keyPressed(arg))
        return true;

    // ...

}

Mouse Events. OIS fires pressed/released events for ALL mouse buttons. Currently Irrlicht only contains definitions for LEFT, RIGHT, and MIDDLE mouse buttons. By default, COIS converts non LEFT, RIGHT, and MIDDLE button events to LEFT button events before injecting the mouse event into the GUI environment.

Buffered Input. By default COIS instructs OIS to use buffered input. This behaviour may be modified by setting the "buffered" parameter to "false" in the COIS constructor.

Linux. In order for OIS/COIS to work properly on Linux, The Irrlicht device creation parameter "IgnoreInput" must be set to true.

    static IrrlichtDevice* _createDevice()
    {
        SIrrlichtCreationParameters cp;
        cp.DriverType = m_driverType;
        cp.WindowSize = dimension2d<s32>(WINDOW_SIZE_X,WINDOW_SIZE_Y);
        cp.Bits = DEVICE_BPP;
        cp.Fullscreen = false;
        cp.Vsync = false;
        cp.Stencilbuffer = false;
        cp.AntiAlias = false;
        cp.EventReceiver = 0;
        cp.WindowId = 0;

    #if defined(_IRR_LINUX_PLATFORM_) && defined(_IRR_USE_LINUX_DEVICE_)
        cp.IgnoreInput = true;
    #endif

        return createDeviceEx(cp);
    }

Force Feedback

If you're not familiar with Force Feedback and Effects, MSDN has a little overview on the Basic Concepts of Force Feedback.

OIS provides an interface (ForceFeedback) for managing force feedback effects within your application. The management functions include:

  • Creating different types of effects.
  • Playing effects on a selected device.
  • Stopping effects on a selected device.

Effects. Effects contain parameters which describe the type of force to be played back on a device. These parameters include duration, magnitude, direction, period, and envelope. In OIS, Effects are created and modified via the "Effect" class. OIS also provides additional convenience classes (ConstantEffect, PeriodicEffect, RampEffect, and ConditionalEffect) for manipulating the appropriate parameters of a particular effect.

Sample Code:
OIS::ForceFeedback* m_ff;  // detected and assigned in your OIS initialization code

//
// create the effect and set its parameters
//
OIS::Effect* m_effect = new OIS::Effect(OIS::Effect::ConstantForce, OIS::Effect::Constant);
m_effect->replay_length = 1500 * 1000; // 1.5 seconds - all effects have a duration

OIS::ConstantEffect* ce = (OIS::ConstantEffect*)m_effect->getForceEffect();
ce->level = 5000;  // set the magnitude (-10k -> 10k)

//
// ...somewhere else in your code... in response to an event (collision, firing, etc.)
// you may play the previously created effect:
//
m_ff->upload(m_effect);

//
// if you need to "stop" the effect before the duration expires:
//
m_ff->remove(m_effect);

The sample OIS application (linked below) contains code that creates and plays a "Constant" effect when either the "F" key is pressed or the Joystick/Gamepad button number 7 is pressed.

COIS Source Code Links

In order to compile COIS.cpp, you will need to use Irrlicht 1.5 or newer.

COIS.h View | Download

COIS.cpp View | Download

Sample Application Source Code Links

main.cpp View | Download

OIS Example Application Screenshot: