Add key repeating back in with Jtk

Problem though: A change in modifiers between key press and release will
lead to a different keyval, which indexes differently into
g_key_statuses, leading to infinite key repeats. So we maybe should
revert to storing modifier state separately from keycode to handle this.
This commit is contained in:
Josh Holtrop 2017-10-01 17:46:30 -04:00
parent 486253d0b6
commit 6ff2faf4af
5 changed files with 66 additions and 54 deletions

View File

@ -5,20 +5,27 @@
#include <iostream>
#include "jes_icon-32x32.h"
#include <unistd.h>
#include <unordered_map>
#define INITIAL_WIDTH 800
#define INITIAL_HEIGHT 800
#define FONT_SIZE 16
#if 0
struct
#define TIMER_TYPE_KEY_REPEAT 1u
struct KeyStatus
{
SDL_TimerID timer_id;
SDL_Keycode keysym;
size_t timer_id;
uint32_t keyval;
bool pressed;
bool event_pending;
} Key_Statuses[SDL_NUM_SCANCODES];
#endif
KeyStatus()
{
pressed = false;
}
};
std::unordered_map<uint32_t, KeyStatus> g_key_statuses;
/**
* Initialize OpenGL.
@ -156,33 +163,6 @@ void Window::run_event_loop()
}
}
#if 0
Uint32 Key_Repeat(Uint32 interval, void * param)
{
if (Key_Statuses[(uintptr_t)param].pressed)
{
if (!Key_Statuses[(uintptr_t)param].event_pending)
{
SDL_Event event;
event.user.code = 0;
event.user.data1 = (void *)(uintptr_t)Key_Statuses[(uintptr_t)param].keysym;
event.user.data2 = param;
event.type = SDL_USEREVENT;
SDL_PushEvent(&event);
Key_Statuses[(uintptr_t)param].event_pending = true;
}
return 25u;
}
else
{
return 0u;
}
}
#endif
/**
* Handle a Jtk event.
*/
@ -197,32 +177,46 @@ void Window::handle_event(Jtk_Event & event)
#endif
case JTK_EVENT_KEY_PRESS:
#if 0
if (event.key.repeat == 0)
{
Key_Statuses[event.key.keysym.scancode].pressed = true;
Key_Statuses[event.key.keysym.scancode].keysym = event.key.keysym.sym;
Key_Statuses[event.key.keysym.scancode].timer_id = SDL_AddTimer(300, Key_Repeat, (void *)event.key.keysym.scancode);
handle_keysym(event.key.keysym.sym);
KeyStatus & key_status = g_key_statuses[event.key.key];
key_status.pressed = true;
key_status.keyval = event.key.key;
key_status.timer_id = Jtk_AddTimer(300u, 25u,
(void *)TIMER_TYPE_KEY_REPEAT, &key_status);
handle_keypress(event.key.key);
}
#endif
handle_keypress(event.key.key);
break;
case JTK_EVENT_KEY_RELEASE:
#if 0
Key_Statuses[event.key.keysym.scancode].pressed = false;
if (Key_Statuses[event.key.keysym.scancode].timer_id != 0)
{
SDL_RemoveTimer(Key_Statuses[event.key.keysym.scancode].timer_id);
Key_Statuses[event.key.keysym.scancode].timer_id = 0;
KeyStatus & key_status = g_key_statuses[event.key.key];
if (key_status.pressed)
{
Jtk_RemoveTimer(key_status.timer_id);
key_status.pressed = false;
}
}
#endif
break;
case JTK_EVENT_WINDOW_EXPOSE:
m_redraw_requested = true;
break;
case JTK_EVENT_TIMER:
switch ((uintptr_t)event.timer.user1)
{
case TIMER_TYPE_KEY_REPEAT:
{
KeyStatus * key_status = (KeyStatus *)event.timer.user2;
if (key_status->pressed)
{
handle_keypress(key_status->keyval);
}
}
break;
}
break;
#if 0
case SDL_WINDOWEVENT:
switch (event.window.event)
@ -237,11 +231,6 @@ void Window::handle_event(Jtk_Event & event)
}
break;
case SDL_USEREVENT:
Key_Statuses[(uintptr_t)event.user.data2].event_pending = false;
handle_keysym((uint32_t)(uintptr_t)event.user.data1);
break;
case SDL_MOUSEWHEEL:
if (event.wheel.y > 0)
{

View File

@ -253,6 +253,8 @@ void Jtk_WaitEvent(Jtk_Event * event)
{
event->type = JTK_EVENT_TIMER;
event->timer.timer_id = timer_id;
event->timer.user1 = Jtk_GetTimerUserData(timer_id, 0u);
event->timer.user2 = Jtk_GetTimerUserData(timer_id, 1u);
Jtk_ServiceTimer(timer_id);
return;
}

View File

@ -25,6 +25,8 @@ typedef struct
typedef struct
{
size_t timer_id;
void * user1;
void * user2;
} Jtk_TimerEvent;
typedef struct

View File

@ -8,6 +8,7 @@ typedef struct
uint64_t next; /**< Time the timer next expires (us). */
uint64_t interval; /**< Timer interval (us). */
size_t id; /**< Timer ID. */
void * user[2]; /**< User data pointers. */
} Timer;
/** Vector used to allocate timer IDs. */
@ -37,11 +38,17 @@ static size_t AllocateTimerID()
* @param interval
* Interval time in milliseconds. A value of 0 indicates that the timer
* is not periodic.
* @param user1
* User data pointer 1. This value is not used by Jtk but can be retrieved by
* the user when a timer expires.
* @param user2
* User data pointer 2. This value is not used by Jtk but can be retrieved by
* the user when a timer expires.
*
* @return
* Timer ID.
*/
size_t Jtk_AddTimer(uint32_t delay, uint32_t interval)
size_t Jtk_AddTimer(uint32_t delay, uint32_t interval, void * user1, void * user2)
{
uint64_t current_system_time = Jtk_UsTime();
size_t timer_id = AllocateTimerID();
@ -49,6 +56,8 @@ size_t Jtk_AddTimer(uint32_t delay, uint32_t interval)
timer->next = current_system_time + (delay * 1000u);
timer->interval = interval * 1000u;
timer->id = timer_id;
timer->user[0] = user1;
timer->user[1] = user2;
g_timers[timer_id] = timer;
g_active_timers.push_back(timer);
return timer_id;
@ -137,3 +146,12 @@ size_t Jtk_GetExpiredTimer()
}
return (size_t)-1;
}
void * Jtk_GetTimerUserData(size_t timer_id, uint8_t index)
{
if (timer_id < g_timers.size())
{
return g_timers[timer_id]->user[index];
}
return nullptr;
}

View File

@ -4,10 +4,11 @@
#include <stdint.h>
#include <stdlib.h>
size_t Jtk_AddTimer(uint32_t delay, uint32_t interval);
size_t Jtk_AddTimer(uint32_t delay, uint32_t interval, void * user1, void * user2);
void Jtk_RemoveTimer(size_t timer_id);
uint64_t Jtk_TimeToNextTimerExpiration();
void Jtk_ServiceTimer(size_t timer_id);
size_t Jtk_GetExpiredTimer();
void * Jtk_GetTimerUserData(size_t timer_id, uint8_t index);
#endif