- patch to ticket 472
git-svn-id: https://svn.code.sf.net/p/speed-dreams/code/trunk@6869 30fe4595-0a0c-4342-8851-515496e4dcbd Former-commit-id: 04a28a03b9f8d23fb0acdf8894a02c25339c7dcc Former-commit-id: 1315920c6fdf0ff6e2b492007f4c456096814ec2
This commit is contained in:
parent
bab48decfd
commit
a2b7e34cc3
1 changed files with 199 additions and 163 deletions
|
@ -16,7 +16,7 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
/* Mimics the behavior of the GLUT callback system.
|
||||
/* Mimics the behavior of the GLUT callback system.
|
||||
The idea was to minimize code changes when switching form GLUT to SDL */
|
||||
|
||||
#include <map>
|
||||
|
@ -31,48 +31,61 @@ class GfEventLoop::Private
|
|||
{
|
||||
public:
|
||||
|
||||
//! Constructor.
|
||||
Private();
|
||||
|
||||
//! Translation function from SDL key to unicode if possible (or SDL key sym otherwise)
|
||||
int translateKeySym(int code, int modifier, int unicode);
|
||||
//! Constructor.
|
||||
Private();
|
||||
|
||||
//! SDL-callable wrapper for the timer callback function.
|
||||
static Uint32 callTimerCB(Uint32 interval, void *pEvLoopPriv);
|
||||
//! Translation function from SDL key to unicode if possible (or SDL key sym otherwise)
|
||||
int translateKeySym(int code, int modifier, int unicode);
|
||||
|
||||
//! SDL-callable wrapper for the timer callback function.
|
||||
static Uint32 callTimerCB(Uint32 interval, void *pEvLoopPriv);
|
||||
|
||||
public: // Public data members.
|
||||
|
||||
// Callback function pointers.
|
||||
void (*cbKeyboardDown)(int key, int modifiers, int x, int y);
|
||||
void (*cbKeyboardUp)(int key, int modifiers, int x, int y);
|
||||
|
||||
void (*cbRecompute)(void);
|
||||
|
||||
void (*cbTimer)(int value);
|
||||
|
||||
// Variables.
|
||||
bool bQuit; // Flag to go to the end of event loop.
|
||||
// Callback function pointers.
|
||||
void (*cbKeyboardDown)(int key, int modifiers, int x, int y);
|
||||
void (*cbKeyboardUp)(int key, int modifiers, int x, int y);
|
||||
|
||||
void (*cbRecompute)(void);
|
||||
|
||||
void (*cbTimer)(int value);
|
||||
|
||||
// Variables.
|
||||
bool bQuit; // Flag to go to the end of event loop.
|
||||
|
||||
//! Current "locked" key modifiers. // Caps-Lock bug
|
||||
int nLockedModifiers;
|
||||
|
||||
private: // Private data members.
|
||||
|
||||
//! Initialization flag for the underlying software layers.
|
||||
static bool _bInitialized;
|
||||
//! Initialization flag for the underlying software layers.
|
||||
static bool _bInitialized;
|
||||
|
||||
//! Unicode for each typed SDL key sym + modifier
|
||||
std::map<Uint32, Uint16> _mapUnicodes;
|
||||
//! Unicode for each typed SDL key sym + modifier
|
||||
std::map<Uint32, Uint16> _mapUnicodes;
|
||||
};
|
||||
|
||||
GfEventLoop::Private::Private()
|
||||
: cbKeyboardDown(0), cbKeyboardUp(0), cbRecompute(0), cbTimer(0), bQuit(false)
|
||||
{
|
||||
static bool bInitialized = false;
|
||||
if (!bInitialized)
|
||||
{
|
||||
static bool bInitialized = false;
|
||||
if (!bInitialized)
|
||||
{
|
||||
#if SDL_MAJOR_VERSION < 2
|
||||
SDL_EnableUNICODE(/*enable=*/1); // For keyboard "key press" event key code translation
|
||||
// Enable "key press" event unicode translation.
|
||||
SDL_EnableUNICODE(/*enable=*/1);
|
||||
//SDL_WM_GrabInput(SDL_GRAB_ON); // Caps-Lock bug : Not better if On.
|
||||
|
||||
// Caps-Lock bug
|
||||
// Get initial state for locked modifiers (mainly Caps and Num-Lock).
|
||||
// Note: SDL fails at taking further hits of Caps and Num-Lock keys into account,
|
||||
// so we have to do it ourselves (see operator ()).
|
||||
nLockedModifiers = SDL_GetModState();
|
||||
|
||||
// Done once and for all.
|
||||
#endif
|
||||
bInitialized = true;
|
||||
}
|
||||
bInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Translation function from SDL key to unicode if possible (or SDL key sym otherwise)
|
||||
|
@ -89,219 +102,242 @@ GfEventLoop::Private::Private()
|
|||
int GfEventLoop::Private::translateKeySym(int code, int modifier, int unicode)
|
||||
{
|
||||
#if SDL_MAJOR_VERSION < 2
|
||||
// Generate the key Id from its code and modifier.
|
||||
const Uint32 keyId = ((Uint32)code & 0x1FF) | (((Uint32)modifier) << 9);
|
||||
// Generate the key Id from its code and modifier.
|
||||
const Uint32 keyId = ((Uint32)code & 0x1FF) | (((Uint32)modifier) << 9);
|
||||
|
||||
// Search it in our unicode map.
|
||||
// Search it in our unicode map.
|
||||
const std::map<Uint32, Uint16>::const_iterator itUnicode = _mapUnicodes.find(keyId);
|
||||
|
||||
// If not found, update the map for next times.
|
||||
int keyUnicode;
|
||||
// If not found, update the map for next times.
|
||||
int keyUnicode;
|
||||
if (itUnicode == _mapUnicodes.end())
|
||||
{
|
||||
// Truncate unicodes above GF_MAX_KEYCODE (no need for more).
|
||||
keyUnicode = unicode ? (unicode & GF_MAX_KEYCODE) : code;
|
||||
_mapUnicodes[keyId] = (unsigned short)keyUnicode;
|
||||
GfLogDebug("translateKeySym(c=%X, m=%X, u=%X) : '%c', id=%X, ucode=%X (nk=%d)\n",
|
||||
code, modifier, unicode, // Truncate high bits for MSVC 2010 bugs.
|
||||
(keyUnicode > 0 && keyUnicode < 128 && isprint(keyUnicode & 0x7F))
|
||||
? (char)(keyUnicode & 0x7F) : ' ',
|
||||
keyId, keyUnicode, _mapUnicodes.size());
|
||||
}
|
||||
{
|
||||
// Truncate unicodes above GF_MAX_KEYCODE (no need for more).
|
||||
keyUnicode = unicode ? (unicode & GF_MAX_KEYCODE) : code;
|
||||
_mapUnicodes[keyId] = (unsigned short)keyUnicode;
|
||||
GfLogDebug("translateKeySym(c=%X, m=%X, u=%X) : '%c', id=%X, ucode=%X (nk=%d), ms=%X\n",
|
||||
code, modifier, unicode, // Truncate high bits for MSVC 2010 bugs.
|
||||
(keyUnicode > 0 && keyUnicode < 128 && isprint(keyUnicode & 0x7F))
|
||||
? (char)(keyUnicode & 0x7F) : ' ',
|
||||
keyId, keyUnicode, _mapUnicodes.size(), SDL_GetModState());
|
||||
}
|
||||
|
||||
// If found, get the unicode from the map.
|
||||
else
|
||||
keyUnicode = (*itUnicode).second;
|
||||
// If found, get the unicode from the map.
|
||||
else
|
||||
keyUnicode = (*itUnicode).second;
|
||||
|
||||
// Done.
|
||||
return keyUnicode;
|
||||
// Done.
|
||||
return keyUnicode;
|
||||
#else
|
||||
int keyUnicode = code; //default to returning code
|
||||
int keyUnicode = code; //default to returning code
|
||||
|
||||
// Make the Numpad <Enter> key behave like the regular <Enter> key
|
||||
if(SDLK_KP_ENTER == code)
|
||||
keyUnicode = SDLK_RETURN;
|
||||
// Make the Numpad <Enter> key behave like the regular <Enter> key
|
||||
if(SDLK_KP_ENTER == code)
|
||||
keyUnicode = SDLK_RETURN;
|
||||
|
||||
else
|
||||
{
|
||||
const Uint32 keyId = ((Uint32)code & GF_MAX_KEYCODE) | (((Uint32)modifier) << 9);
|
||||
else
|
||||
{
|
||||
const Uint32 keyId = ((Uint32)code & GF_MAX_KEYCODE) | (((Uint32)modifier) << 9);
|
||||
|
||||
// If unicode - add to the map...
|
||||
if(unicode)
|
||||
{
|
||||
// Truncate unicodes above GF_MAX_KEYCODE (no need for more).
|
||||
keyUnicode = (unsigned short)(unicode & GF_MAX_KEYCODE);
|
||||
_mapUnicodes[keyId] = (unsigned short)keyUnicode;
|
||||
GfLogDebug("translateKeySym(c=%X, m=%X, u=%X) : '%c', id=%X, ucode=%X (nk=%d)\n",
|
||||
code, modifier, unicode, // Truncate high bits for MSVC 2010 bugs.
|
||||
(keyUnicode > 0 && keyUnicode < 128 && isprint(keyUnicode & 0x7F))
|
||||
? (char)(keyUnicode & 0x7F) : ' ',
|
||||
keyId, keyUnicode, _mapUnicodes.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Search it in our unicode map.
|
||||
const std::map<Uint32, Uint16>::const_iterator itUnicode = _mapUnicodes.find(keyId);
|
||||
if (itUnicode != _mapUnicodes.end())
|
||||
{
|
||||
keyUnicode = (*itUnicode).second;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If unicode - add to the map...
|
||||
if(unicode)
|
||||
{
|
||||
// Truncate unicodes above GF_MAX_KEYCODE (no need for more).
|
||||
keyUnicode = (unsigned short)(unicode & GF_MAX_KEYCODE);
|
||||
_mapUnicodes[keyId] = (unsigned short)keyUnicode;
|
||||
GfLogDebug("translateKeySym(c=%X, m=%X, u=%X) : '%c', id=%X, ucode=%X (nk=%d)\n",
|
||||
code, modifier, unicode, // Truncate high bits for MSVC 2010 bugs.
|
||||
(keyUnicode > 0 && keyUnicode < 128 && isprint(keyUnicode & 0x7F))
|
||||
? (char)(keyUnicode & 0x7F) : ' ',
|
||||
keyId, keyUnicode, _mapUnicodes.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Search it in our unicode map.
|
||||
const std::map<Uint32, Uint16>::const_iterator itUnicode = _mapUnicodes.find(keyId);
|
||||
if (itUnicode != _mapUnicodes.end())
|
||||
{
|
||||
keyUnicode = (*itUnicode).second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return keyUnicode;
|
||||
return keyUnicode;
|
||||
#endif
|
||||
}
|
||||
|
||||
Uint32 GfEventLoop::Private::callTimerCB(Uint32 interval, void *pEvLoopPriv)
|
||||
{
|
||||
Private* pPriv = reinterpret_cast<Private*>(pEvLoopPriv);
|
||||
if (pPriv->cbTimer)
|
||||
pPriv->cbTimer(1);
|
||||
Private* pPriv = reinterpret_cast<Private*>(pEvLoopPriv);
|
||||
if (pPriv->cbTimer)
|
||||
pPriv->cbTimer(1);
|
||||
|
||||
// Returning zero will prevent the callback from being called again.
|
||||
return 0;
|
||||
// Returning zero will prevent the callback from being called again.
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// GfEventLoop class ============================================================
|
||||
|
||||
|
||||
GfEventLoop::GfEventLoop()
|
||||
{
|
||||
_pPrivate = new Private;
|
||||
_pPrivate = new Private;
|
||||
}
|
||||
|
||||
GfEventLoop::~GfEventLoop()
|
||||
{
|
||||
delete _pPrivate;
|
||||
delete _pPrivate;
|
||||
}
|
||||
|
||||
void GfEventLoop::injectKeyboardEvent(int code, int modifier, int state,
|
||||
int unicode, int x, int y)
|
||||
int unicode, int x, int y)
|
||||
{
|
||||
// Translate KMOD_RXX modifiers to KMOD_LXX (we make no difference)
|
||||
// and ignore modifiers other than SHIFT, ALT, CTRL and META.
|
||||
if (modifier)
|
||||
{
|
||||
if (modifier & KMOD_RSHIFT) modifier |= KMOD_LSHIFT;
|
||||
if (modifier & KMOD_RCTRL) modifier |= KMOD_LCTRL;
|
||||
if (modifier & KMOD_RALT) modifier |= KMOD_LALT;
|
||||
// Update locked modifiers state, as SDL doesn't always do it. // Caps-Lock bug
|
||||
switch (code)
|
||||
{
|
||||
case SDLK_CAPSLOCK:
|
||||
_pPrivate->nLockedModifiers ^= KMOD_CAPS;
|
||||
GfLogDebug("injectKeyboardEvent(c=%X) : lockedMod=%X (SDL says %X)\n",
|
||||
code, _pPrivate->nLockedModifiers, SDL_GetModState());
|
||||
return;
|
||||
case SDLK_NUMLOCKCLEAR:
|
||||
_pPrivate->nLockedModifiers ^= KMOD_NUM;
|
||||
GfLogDebug("injectKeyboardEvent(c=%X) : lockedMod=%X (SDL says %X)\n",
|
||||
code, _pPrivate->nLockedModifiers, SDL_GetModState());
|
||||
return;
|
||||
}
|
||||
// Translate KMOD_RXX modifiers to KMOD_LXX (we make no difference)
|
||||
// and ignore modifiers other than SHIFT, ALT, CTRL and META.
|
||||
if (modifier)
|
||||
{
|
||||
if (modifier & KMOD_RSHIFT) modifier |= KMOD_LSHIFT;
|
||||
if (modifier & KMOD_RCTRL) modifier |= KMOD_LCTRL;
|
||||
if (modifier & KMOD_RALT) modifier |= KMOD_LALT;
|
||||
#if SDL_MAJOR_VERSION < 2
|
||||
if (modifier & KMOD_RMETA) modifier |= KMOD_LMETA;
|
||||
if (modifier & KMOD_RMETA) modifier |= KMOD_LMETA;
|
||||
|
||||
modifier &= (KMOD_LSHIFT | KMOD_LCTRL | KMOD_LALT | KMOD_LMETA);
|
||||
modifier &= (KMOD_LSHIFT | KMOD_LCTRL | KMOD_LALT | KMOD_LMETA);
|
||||
#else
|
||||
if (modifier & KMOD_RGUI) modifier |= KMOD_LGUI;
|
||||
if (modifier & KMOD_RGUI) modifier |= KMOD_LGUI;
|
||||
|
||||
modifier &= (KMOD_LSHIFT | KMOD_LCTRL | KMOD_LALT | KMOD_LGUI);
|
||||
modifier &= (KMOD_LSHIFT | KMOD_LCTRL | KMOD_LALT | KMOD_LGUI);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Call the relevant call-back funtion if any registered.
|
||||
if (state == 0)
|
||||
{
|
||||
if (_pPrivate->cbKeyboardDown)
|
||||
_pPrivate->cbKeyboardDown(_pPrivate->translateKeySym(code, modifier, unicode),
|
||||
modifier, x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_pPrivate->cbKeyboardUp)
|
||||
_pPrivate->cbKeyboardUp(_pPrivate->translateKeySym(code, modifier, unicode),
|
||||
modifier, x, y);
|
||||
}
|
||||
// Toggle the Shift modifier if the Caps-Lock key is on. // Caps-Lock bug
|
||||
if (_pPrivate->nLockedModifiers & KMOD_CAPS)
|
||||
{
|
||||
GfLogDebug("injectKeyboardEvent(c=%X, m=%X, u=%X)",
|
||||
code, modifier, unicode);
|
||||
modifier ^= KMOD_LSHIFT;
|
||||
GfLogDebug(" => m=%X\n", modifier);
|
||||
}
|
||||
|
||||
// Call the relevant call-back funtion if any registered.
|
||||
if (state == 0)
|
||||
{
|
||||
if (_pPrivate->cbKeyboardDown)
|
||||
_pPrivate->cbKeyboardDown(_pPrivate->translateKeySym(code, modifier, unicode),
|
||||
modifier, x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_pPrivate->cbKeyboardUp)
|
||||
_pPrivate->cbKeyboardUp(_pPrivate->translateKeySym(code, modifier, unicode),
|
||||
modifier, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
// The event loop itself.
|
||||
void GfEventLoop::operator()()
|
||||
{
|
||||
SDL_Event event; // Event structure
|
||||
|
||||
// Check for events.
|
||||
while (!_pPrivate->bQuit)
|
||||
{
|
||||
// Loop until there are no events left in the queue.
|
||||
while (!_pPrivate->bQuit && SDL_PollEvent(&event))
|
||||
{
|
||||
// Process events we care about, and ignore the others.
|
||||
switch(event.type)
|
||||
{
|
||||
case SDL_KEYDOWN:
|
||||
injectKeyboardEvent(event.key.keysym.sym, event.key.keysym.mod, 0,
|
||||
SDL_Event event; // Event structure
|
||||
|
||||
// Check for events.
|
||||
while (!_pPrivate->bQuit)
|
||||
{
|
||||
// Loop until there are no events left in the queue.
|
||||
while (!_pPrivate->bQuit && SDL_PollEvent(&event))
|
||||
{
|
||||
// Process events we care about, and ignore the others.
|
||||
switch(event.type)
|
||||
{
|
||||
case SDL_KEYDOWN:
|
||||
injectKeyboardEvent(event.key.keysym.sym, event.key.keysym.mod, 0,
|
||||
#if SDL_MAJOR_VERSION < 2
|
||||
event.key.keysym.unicode);
|
||||
event.key.keysym.unicode);
|
||||
#else
|
||||
0);
|
||||
0);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case SDL_KEYUP:
|
||||
injectKeyboardEvent(event.key.keysym.sym, event.key.keysym.mod, 1,
|
||||
break;
|
||||
|
||||
case SDL_KEYUP:
|
||||
injectKeyboardEvent(event.key.keysym.sym, event.key.keysym.mod, 1,
|
||||
#if SDL_MAJOR_VERSION < 2
|
||||
event.key.keysym.unicode);
|
||||
event.key.keysym.unicode);
|
||||
#else
|
||||
0);
|
||||
0);
|
||||
#endif
|
||||
break;
|
||||
break;
|
||||
|
||||
case SDL_QUIT:
|
||||
postQuit();
|
||||
break;
|
||||
case SDL_QUIT:
|
||||
postQuit();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_pPrivate->bQuit)
|
||||
{
|
||||
// Recompute if anything to.
|
||||
recompute();
|
||||
}
|
||||
}
|
||||
if (!_pPrivate->bQuit)
|
||||
{
|
||||
// Recompute if anything to.
|
||||
recompute();
|
||||
}
|
||||
}
|
||||
|
||||
GfLogTrace("Quitting event loop.\n");
|
||||
GfLogTrace("Quitting event loop.\n");
|
||||
}
|
||||
|
||||
void GfEventLoop::setKeyboardDownCB(void (*func)(int key, int modifiers, int x, int y))
|
||||
{
|
||||
_pPrivate->cbKeyboardDown = func;
|
||||
_pPrivate->cbKeyboardDown = func;
|
||||
}
|
||||
|
||||
void GfEventLoop::setKeyboardUpCB(void (*func)(int key, int modifiers, int x, int y))
|
||||
{
|
||||
_pPrivate->cbKeyboardUp = func;
|
||||
_pPrivate->cbKeyboardUp = func;
|
||||
}
|
||||
|
||||
void GfEventLoop::setRecomputeCB(void (*func)(void))
|
||||
{
|
||||
_pPrivate->cbRecompute = func;
|
||||
_pPrivate->cbRecompute = func;
|
||||
}
|
||||
|
||||
void GfEventLoop::setTimerCB(unsigned int millis, void (*func)(int value))
|
||||
{
|
||||
_pPrivate->cbTimer = func;
|
||||
SDL_AddTimer(millis, Private::callTimerCB, (void*)_pPrivate);
|
||||
_pPrivate->cbTimer = func;
|
||||
SDL_AddTimer(millis, Private::callTimerCB, (void*)_pPrivate);
|
||||
}
|
||||
|
||||
void GfEventLoop::postQuit()
|
||||
{
|
||||
_pPrivate->bQuit = true;
|
||||
_pPrivate->bQuit = true;
|
||||
}
|
||||
|
||||
bool GfEventLoop::quitRequested() const
|
||||
{
|
||||
return _pPrivate->bQuit;
|
||||
return _pPrivate->bQuit;
|
||||
}
|
||||
|
||||
void GfEventLoop::recompute()
|
||||
{
|
||||
// Call the 'recompute' callback if any.
|
||||
if (_pPrivate->cbRecompute)
|
||||
_pPrivate->cbRecompute();
|
||||
|
||||
// ... otherwise let the CPU take breath (and fans stay at low and quiet speed,
|
||||
// which would not be the case if really doing nothing).
|
||||
else
|
||||
SDL_Delay(1); // ms.
|
||||
// Call the 'recompute' callback if any.
|
||||
if (_pPrivate->cbRecompute)
|
||||
_pPrivate->cbRecompute();
|
||||
|
||||
// ... otherwise let the CPU take breath (and fans stay at low and quiet speed,
|
||||
// which would not be the case if really doing nothing).
|
||||
else
|
||||
SDL_Delay(1); // ms.
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue