The Beginner Guide to Injecting Inputs

From CEGUI Wiki - Crazy Eddie's Gui System for Games (Open Source)
Jump to: navigation, search

Written for CEGUI 0.6


Works with versions 0.6.x (obsolete)

The Beginner Guide series

This page is part of a series, use links above to easily navigate through all chapters of the series.


This tutorial is for CEGUI versions up to 0.6.2. For later releases, see the tutorials in the main documentation.


Having read the previous tutorials in this series, you now have your GUI rendering setup, the files loaded, and even have a window on the screen - however you are probably wanting to have some user interaction too. This is the subject of this final tutorial in the series; here we will show the required tasks in order to end up with a complete functioning GUI in your application. (CrazyEddie's joke: Alternatively, you got tired of waiting 15 months for this tutorial and worked it out for yourself!).

Contents

Introduction to input for CEGUI

First the bad news

It shocks some people to discover that CEGUI does not do any automatic collection of user input; it is the applications job to tell CEGUI about any events that it should know about. This means that you have to tell CEGUI each time a key is pressed, or the mouse moves, and so on. While this may seem strange at first, it actually affords you a lot more power - we are not tying you down to any particular system for your inputs, and you may also filter inputs before they get to CEGUI, although those are more advanced concepts best left for another time.


Get your inputs fuel injected stylee!

In order to tell CEGUI about the input events going on around it, we have an input injection interface. This consists of a set of members in the CEGUI::System class - there is one member function for each type of base input we accept:

bool injectMouseMove( float delta_x, float delta_y );
bool injectMousePosition( float x_pos, float y_pos );
bool injectMouseLeaves( void );
bool injectMouseButtonDown( MouseButton button );
bool injectMouseButtonUp( MouseButton button );
bool injectKeyDown( uint key_code );
bool injectKeyUp( uint key_code );
bool injectChar( utf32 code_point );
bool injectMouseWheelChange( float delta );
bool injectTimePulse( float timeElapsed );

Yes, that's quite a collection! The first thing that you might notice is that there appears to be some repetition - things like 'mouse move' and 'mouse position', 'key down' and 'char'. For the mouse, we offer the possibility of injecting a relative movement of the mouse from its last injected location or an absolute position - which you choose will largely depend upon the type of inputs that your input library provides you with for the mouse. For keys, it is required that both up/down strokes and also characters are injected - there are a couple of reasons for this; first, not all keys generate a character code (like shift, alt, and so on), and second, it allows you to do your own custom (or operating system supplied) key-mapping and key auto-repeat (since CEGUI does not currently offer these functions).

The other thing to notice is the boolean return value from the injector functions. This is used to relay back to your application whether or not CEGUI actually consumed the input. If this returns false, it means that CEGUI did nothing useful with the input, and that your application may like to perform some action based on it instead.


A little more detail - what each injector is used for

Here we will offer a brief description of what each injection function is used for, the data it expects, and what, in general, is done with the input.


bool injectMouseMove( float delta_x, float delta_y )

This is used to inject relative mouse movements. The inputs 'delta_x' and 'delta_y' specify the direction and number of screen pixels the mouse has moved on the x axis and y axis respectively. This causes the mouse to move by the specified amount (the actual amount moved can be changed by setting a mouse scaling factor via CEGUI::System::setMouseMoveScaling). If you use this, you generally do not need to use injectMousePosition.


bool injectMousePosition( float x_pos, float y_pos )

This is used to inject the current absolute position of the mouse. The inputs 'x_pos' and 'y_pos' specify the position of the mouse in pixels, with (0, 0) representing the top-left hand corner of the CEGUI display (so if you're in windowed mode, it's the corner of the window and not the whole screen). The CEGUI mouse cursor will be set to the new position. If you use this, you generally do not need to use injectMouseMove.


bool injectMouseLeaves( void )

This function informs CEGUI that the mouse cursor has left the system application window which CEGUI considers its rendering area. This is useful if running in windowed mode to inform widgets that the mouse has actually left the CEGUI display completely (otherwise it may not get to know, since under some systems no more mouse events are generated for a OS window once the mouse has left it).


bool injectMouseButtonDown( MouseButton button )

This tells CEGUI that a mouse button has been pressed down. The value 'button' is one of the CEGUI::MouseButton enumerated values, which are as follows:

enum MouseButton
{
   LeftButton,
   RightButton,
   MiddleButton,
   X1Button,
   X2Button,
   MouseButtonCount,
   NoButton
};

If the values from your input library do not match these, you will have to perform a translation step. Also note that the value NoButton is not 0.


bool injectMouseButtonUp( MouseButton button )

This tells CEGUI that a mouse button has been released. As for the injectMouseButtonDown function, the value 'button' is one of the MouseButton enumerated values.


bool injectKeyDown( uint key_code )

This tells CEGUI that a key has been pressed. The value 'key_code' is a scan code for the key - note that this is not an ASCII or other text encoding value. The available scan codes are defined in the CEGUI::Key::Scan enumeration. If you are using Microsoft DirectInput, then our scan codes are the same ones output by that library, in other cases you may be required to perform some translation. Note that for current releases, and depending upon your expected use, it may not be required to inject all key down/up strokes - the most common ones that you likely will need are for backspace, delete, enter, the shift keys and the arrow keys.

At present no automatic key mapping for generation of character codes is performed, also no key auto-repeat functionality is available - although these functions may appear in future releases. If you need key auto-repeat then you will need to either use an input library that offers that ability, or implement something directly. Of course you will almost certainly need character input, so for that look at the injectChar function below.


bool injectKeyUp( uint key_code )

This tells CEGUI that a key has been released. As for the injectKeyDown function, the value 'key_code' is a scan code for the key - and again note that this is not an ASCII or other text encoding value - see above for a more detailed description of the key scan codes.


bool injectChar( utf32 code_point )

This function tells CEGUI that a character key has been pressed - you will need this in order to input text into CEGUI widgets. The 'code_point' input is a Unicode UTF32 code point (see the unicode website for information about unicode). How you obtain this value is something that is dependant upon the input library that you are using - for many people, who just wish to use ASCII values, you can just pass in your ASCII codes unmodified, since Unicode values between 0 and 127 are the same as the standard ASCII codes. For other uses, you will need to consult the API documentation for your input library (it is possible, for example, to get the Microsoft Windows message pump to send you key codes in UTF32 form, though exactly how it is done is beyond the scope of this introductory tutorial.


bool injectMouseWheelChange( float delta )

This function is used to tell CEGUI about the use of the mouse wheel or scroll wheel (whatever you like to call it). Use positive values for forward movement (rolling the wheel away from the user), and negative values for backwards movement (rolling the wheel towards the user).


bool injectTimePulse( float timeElapsed )

This function is used to keep CEGUI informed about time (CEGUI doesn't have a watch, you see!). The 'timeElapsed' is a floating point number that indicates the number of seconds - or part seconds - that have passed since the last time the injector was called (or since CEGUI was started). The use of this function is becoming more and more important - it now controls things such as fades and timing for tool-tip widgets, menus, and also auto-repeat for mouse buttons.


Conclusion

Here we have seen the general idiom that CEGUI uses for obtaining externally generated input events. We have seen the methods for passing these inputs to CEGUI, and type and format of the information to be passed.

Unlike some of the other tutorials in this series, we did not provide concrete code examples. The main reason for this was to keep the tutorial reasonably short; to prevent it becoming a jumble of code for every possible combination of input system, and in the process causing more confusion. The use of any individual input library could easily fill a tutorial of its own.


To see some concrete examples, there are two immediate sources of information:


  • The samples framework code: see the files in cegui_mk2/Samples/common/src:
    • Win32AppHelper.cpp - contains a windows message procedure injecting mouse and character inputs into CEGUI, and using DirectInput for keyboard up and down messages.
    • CEGuiOgreBaseApplication.cpp - contains an example Ogre::FrameListener class which takes inputs generated by the OIS Library and injects these into CEGUI.
    • CEGuiOpenGLBaseApplication.cpp - registers callback functions with glut to process inputs, and also shows the use of a key translation table.


Additionally, Irrlicht users can use the supplied Irrlicht event pusher - whenever an event comes your way from Irrlicht you can use the OnEvent member in the Irrlicht Renderer to forward this to CEGUI (you then just have to inject time pulses).


CrazyEddie 03:46, 9 February 2008 (PST)