GLFW:Tutorials:CPP Keyreader

From GPWiki

Files:GUITutorial_warn.gif The Game Programming Wiki has moved! Files:GUITutorial_warn.gif

The wiki is now hosted by GameDev.NET at wiki.gamedev.net. All gpwiki.org content has been moved to the new server.

However, the GPWiki forums are still active! Come say hello.

Keyboard Handler

So now I have a keyboard handler using glfw. I prefer glfw because it is a cross-platform approach that doesn't over-complicate things. The entire library has only about 50 functions (most of which are accessors).

All I have to do is register CKeyHandler::KeyHandler with glfwSetKeyCallback, and I'm good to go. There is a slight difficulty with the self-registering classes that forces you to link in a specific order to make sure the base class's members are defined.


keyhandler.h


#ifndef __KEYBOARD_H__
#define __KEYBOARD_H__
 
// The STL will work just fine, for now.
#include <list>
#include <string>
 
using std::string;
using std::list;
 
//
// Base class for any key's handler.  We could also
// Implement this with a map template to help with
// key lookups
//
class CKeyHandler
{
public:
    // ctors and dtors
    CKeyHandler(const string &name, int key);
    virtual ~CKeyHandler();
 
    // accessors and modifiers
    const string &GetName() const;
    bool KeyToggled() const;
    void SetKey(int key);
 
    // event handler method.
    virtual void operator() (int state);
 
    // global keyhandler which executes all current
    // handlers
    static void KeyHandler(int key, int state);
 
private:
    // internal method to set the keystates and submit event.
    void HandleEvent(int state);
 
    // list of all instances of this class
    static list<CKeyHandler *> s_listKeyhandlers;
 
    string m_name;
    int    m_key;
    bool   m_keydown;
    bool   m_keytoggled;
};
 
// A few macros to simplify subclassing our keyhandler.
#define BEGIN_KEY_HANDLER(name, key)        \
class CKeyHandler##name: public CKeyHandler \
{                                           \
    private:                                \
    static CKeyHandler##name s_singleton;   \
                                            \
    public:                                 \
    CKeyHandler##name(): CKeyHandler(#name, key) { } \
    ~CKeyHandler##name() { }                \
                                            \
    void operator() (int state)
 
// Finish the handler class and create an instance to it.
#define END_KEY_HANDLER(name) }; CKeyHandler##name CKeyHandler##name::s_singleton;
 
#endif // __KEYBOARD_H__ 


keyhandler.cpp


#include "keyboard.h"
 
#include <GL/glfw.h>
 
/////////////////////////////////////////////////////////////////
// class CKeyHandler Definitions
/////////////////////////////////////////////////////////////////
 
list<CKeyHandler *> CKeyHandler::s_listKeyhandlers;
 
CKeyHandler::CKeyHandler(const string &name, int key)
{
    m_name       = name;
    m_key        = key;
    m_keydown    = false;
    m_keytoggled = false;
 
    s_listKeyhandlers.push_back(this);
}
 
CKeyHandler::~CKeyHandler()
{
    s_listKeyhandlers.remove(this);
}
 
void CKeyHandler::operator() (int state)
{ state=state; }
 
const string &CKeyHandler::GetName() const
{
    return m_name;
}
 
bool CKeyHandler::KeyToggled() const
{
    return m_keytoggled;
}
 
void CKeyHandler::KeyHandler(int key, int state)
{
    list<CKeyHandler *>::iterator i = s_listKeyhandlers.begin();
    while (i != s_listKeyhandlers.end())
    {
        if ((*i)->m_key == key)
            (*i)->HandleEvent(state);
 
        *i++;
    }
}
 
void CKeyHandler::SetKey(int key)
{
    m_key = key;
}
 
void CKeyHandler::HandleEvent(int state)
{
    // setup the toggled state (key down, then up)
    if (state == GLFW_PRESS)
    {
        m_keydown = true;
    }
    if (state == GLFW_RELEASE && m_keydown)
    {
        m_keydown    = false;
        m_keytoggled = true;
    }
 
    // call the handler
    operator()(state);
 
    m_keytoggled = false;
}
 
////////////////////////////////////////////////////////////////////////////
// KeyHandler Events
////////////////////////////////////////////////////////////////////////////
 
extern bool g_bFinished; // don't forget to define this!
BEGIN_KEY_HANDLER(ExitApplication, GLFW_KEY_ESC)
{
    if (KeyToggled())
        g_bFinished = true;
}
END_KEY_HANDLER(ExitApplication)