From ff89fc7ca7c2768dd371078dc812f60762360689 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 27 Sep 2017 20:33:18 -0400 Subject: [PATCH 01/30] Begin removing SDL Window and OpenGL context creation working. Keyboard, mouse, window events not yet working. --- src/gui/Gui-X.cc | 94 +++++++++++++++++++++++++++++++++++++++++++++++ src/gui/Gui.h | 19 ++++++++++ src/gui/Window.cc | 64 +++++++++++++------------------- src/gui/Window.h | 9 ++++- wscript | 15 +++++--- 5 files changed, 155 insertions(+), 46 deletions(-) create mode 100644 src/gui/Gui-X.cc create mode 100644 src/gui/Gui.h diff --git a/src/gui/Gui-X.cc b/src/gui/Gui-X.cc new file mode 100644 index 0000000..58a0df4 --- /dev/null +++ b/src/gui/Gui-X.cc @@ -0,0 +1,94 @@ +#ifdef GUI_X + +#include "Gui.h" +#include +#include + +static Display * g_display; +static XVisualInfo * g_vi; +static XSetWindowAttributes g_swa; +static GLXContext g_context; + +static Bool WaitForNotify(Display * display, XEvent * event, XPointer arg) +{ + return (event->type == MapNotify) && (event->xmap.window == (Window)arg); +} + +/** + * Initialize the Gui subsystem. + * + * @return true on success, false on failure + */ +bool Gui_Init() +{ + static int glx_attribute_list[] = { + GLX_RGBA, + GLX_DOUBLEBUFFER, + None, + }; + + g_display = XOpenDisplay(NULL); + if (g_display == NULL) + { + fprintf(stderr, "XOpenDisplay() failure\n"); + return false; + } + + g_vi = glXChooseVisual(g_display, DefaultScreen(g_display), + glx_attribute_list); + if (g_vi == NULL) + { + fprintf(stderr, "glXChooseVisual() failure\n"); + return false; + } + + g_context = glXCreateContext(g_display, g_vi, NULL, True); + if (g_context == NULL) + { + fprintf(stderr, "glXCreateContext() failure\n"); + return false; + } + + Colormap colormap = XCreateColormap(g_display, + RootWindow(g_display, g_vi->screen), g_vi->visual, AllocNone); + g_swa.colormap = colormap; + g_swa.border_pixel = 0; + g_swa.event_mask = StructureNotifyMask; + + return true; +} + +void * Gui_CreateWindow() +{ + XEvent event; + Window window = XCreateWindow(g_display, + RootWindow(g_display, g_vi->screen), + 0, 0, 800, 800, 0, g_vi->depth, InputOutput, g_vi->visual, + CWBorderPixel | CWColormap | CWEventMask, &g_swa); + XMapWindow(g_display, window); + XIfEvent(g_display, &event, WaitForNotify, (XPointer)window); + if (glXMakeCurrent(g_display, window, g_context) == False) + { + fprintf(stderr, "glXMakeCurrent() failure\n"); + XDestroyWindow(g_display, window); + return nullptr; + } + + return (void *)window; +} + +void Gui_SwapBuffers(void * window) +{ + glXSwapBuffers(g_display, (Window)window); +} + +void Gui_CloseWindow(void * window) +{ + XDestroyWindow(g_display, (Window)window); +} + +void Gui_WaitForEvent(Gui_Event * event) +{ +} + +#endif diff --git a/src/gui/Gui.h b/src/gui/Gui.h new file mode 100644 index 0000000..64835ac --- /dev/null +++ b/src/gui/Gui.h @@ -0,0 +1,19 @@ +#ifndef GUI_H +#define GUI_H + +#include + +#define GUI_EVENT_CLOSE_WINDOW 1u + +typedef struct +{ + uint8_t type; +} Gui_Event; + +bool Gui_Init(); +void * Gui_CreateWindow(); +void Gui_SwapBuffers(void * window); +void Gui_CloseWindow(void * window); +void Gui_WaitForEvent(Gui_Event * event); + +#endif diff --git a/src/gui/Window.cc b/src/gui/Window.cc index 95c6628..219ead0 100644 --- a/src/gui/Window.cc +++ b/src/gui/Window.cc @@ -2,13 +2,16 @@ #include "Window.h" #include "Runtime.h" #include "BufferPane.h" +#include "Gui.h" #include #include "jes_icon-32x32.h" +#include #define INITIAL_WIDTH 800 #define INITIAL_HEIGHT 800 #define FONT_SIZE 16 +#if 0 struct { SDL_TimerID timer_id; @@ -16,32 +19,7 @@ struct bool pressed; bool event_pending; } Key_Statuses[SDL_NUM_SCANCODES]; - -/** - * Initialize SDL. - * - * @retval true SDL was loaded successfully. - * @retval false Loading SDL failed. - */ -static bool Initialize_SDL() -{ - static bool initialized = false; - - if (initialized) - { - return true; - } - - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) - { - return false; - } - - atexit(SDL_Quit); - - initialized = true; - return true; -} +#endif /** * Initialize OpenGL. @@ -80,6 +58,7 @@ static bool Initialize_OpenGL() return true; } +#if 0 void Window::set_window_icon() { SDL_Surface * surface = SDL_CreateRGBSurfaceFrom((void *)jes_icon_32x32, 32, 32, 24, 32 * 3, 0xFF0000u, 0xFF00u, 0xFFu, 0u); @@ -88,6 +67,7 @@ void Window::set_window_icon() SDL_FreeSurface(surface); } +#endif /** * Create a Window. @@ -97,28 +77,22 @@ void Window::set_window_icon() */ bool Window::create(std::shared_ptr buffer) { - if (!Initialize_SDL()) + if (!Gui_Init()) { - std::cerr << "Error initializing SDL" << std::endl; + std::cerr << "Error initializing GUI" << std::endl; return false; } - m_window = SDL_CreateWindow( - APPNAME, - SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, - INITIAL_WIDTH, - INITIAL_HEIGHT, - SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); + m_window = Gui_CreateWindow(); if (m_window == NULL) { - std::cerr << "Error creating SDL window" << std::endl; + std::cerr << "Error creating window" << std::endl; return false; } +#if 0 set_window_icon(); - - (void)SDL_GL_CreateContext(m_window); +#endif if (!Initialize_OpenGL()) { @@ -169,6 +143,7 @@ bool Window::create(std::shared_ptr buffer) */ void Window::run_event_loop() { +#if 0 SDL_Event event; while ((!m_exit_requested) && SDL_WaitEvent(&event)) @@ -180,8 +155,12 @@ void Window::run_event_loop() redraw(); } } +#endif + redraw(); + sleep(5); } +#if 0 Uint32 Key_Repeat(Uint32 interval, void * param) { if (Key_Statuses[(uintptr_t)param].pressed) @@ -423,10 +402,15 @@ void Window::handle_keyval(uint32_t keyval) break; } } +#endif void Window::resize() { + m_width = 800; + m_height = 800; +#if 0 SDL_GetWindowSize(m_window, &m_width, &m_height); +#endif glViewport(0, 0, m_width, m_height); m_gl->resize(m_width, m_height); int command_buffer_height = m_command_buffer_screen_rows * m_font->get_line_height(); @@ -453,9 +437,10 @@ void Window::redraw() m_gl->draw_rect(0, m_command_buffer_screen_rows * m_font->get_line_height(), m_width, 1, 0.5, 0.5, 0.5, 1.0); m_command_buffer_pane->draw(); - SDL_GL_SwapWindow(m_window); + Gui_SwapBuffers(m_window); } +#if 0 uint32_t Window::get_keyval(SDL_Keycode keysym) { uint32_t keyval = keysym; @@ -560,6 +545,7 @@ uint32_t Window::get_shifted(uint32_t keysym) return 0u; } +#endif void Window::change_focus(std::shared_ptr buffer_pane) { diff --git a/src/gui/Window.h b/src/gui/Window.h index 759d022..8c1aa1c 100644 --- a/src/gui/Window.h +++ b/src/gui/Window.h @@ -3,7 +3,6 @@ #include #include -#include #include "Font.h" #include "Buffer.h" #include "GL.h" @@ -55,19 +54,23 @@ protected: void resize(); void redraw(); +#if 0 void handle_event(SDL_Event & event); void handle_keysym(uint32_t keysym); void handle_keyval(uint32_t keyval); uint32_t get_keyval(SDL_Keycode keysym); uint32_t get_shifted(uint32_t keysym); +#endif void change_focus(std::shared_ptr buffer_pane); +#if 0 void set_window_icon(); +#endif void handle_command(const EncodedString & command); void command_write_file(const CommandParser & cp); void command_quit(const CommandParser & cp); - SDL_Window * m_window; + void * m_window; bool m_exit_requested; bool m_redraw_requested; int m_width; @@ -84,7 +87,9 @@ protected: std::shared_ptr m_command_buffer; std::shared_ptr m_command_buffer_pane; +#if 0 Uint16 m_keymod; +#endif }; #endif diff --git a/wscript b/wscript index 4ac4744..14a418c 100644 --- a/wscript +++ b/wscript @@ -11,8 +11,11 @@ def options(opt): def configure(conf): conf.load("compiler_c compiler_cxx") conf.check(header_name = "getopt.h", global_define = False) - conf.check_cfg(package = "sdl2", args = "--cflags --libs") conf.check_cfg(package = "freetype2", uselib_store = "FreeType2", args = "--cflags --libs") + if platform.system() == "Linux": + conf.check(header_name = "X11/Xlib.h", global_define = False) + elif platform.system() == "Windows": + conf.check(header_name = "windows.h", global_define = False) def build(bld): defines = ['APPNAME="%s"' % APPNAME] @@ -22,9 +25,11 @@ def build(bld): libs = [] if platform.system() == "Linux": defines += ["PLATFORM_LINUX"] - libs += ["dl", "GL"] - elif re.search(r'MINGW', platform.system()): + defines += ["GUI_X"] + libs += ["dl", "GL", "X11"] + elif platform.system() == "Windows": defines += ["PLATFORM_WINDOWS"] + defines += ["GUI_WINDOWS"] libs += ["opengl32"] defines += ['GLCXX_GL_INCLUDE="gl3w.h"'] sources = bld.path.ant_glob(["src/**/*.cc", "src/**/*.c", "libs/glcxx/src/glcxx/*"]) @@ -35,7 +40,7 @@ def build(bld): defines = defines, cxxflags = ["-Wall", "-std=gnu++14", "-O2", "-Wno-switch"], lib = libs, - uselib = ["SDL2", "FreeType2"]) + uselib = ["FreeType2"]) test_libs = libs + [] if platform.system() == "Linux": @@ -56,4 +61,4 @@ def build(bld): lib = test_libs, cxxflags = ["-Wall", "-std=gnu++14", "--coverage", "-Wno-switch", "-include", "iostream"], linkflags = ["--coverage"], - uselib = ["SDL2", "FreeType2"]) + uselib = ["FreeType2"]) From 8154aa84cc7a62d46d388fd71877d804b51c7047 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 28 Sep 2017 20:19:04 -0400 Subject: [PATCH 02/30] begin defining GUI events --- src/gui/Gui-X.cc | 4 +++- src/gui/Gui.h | 23 ++++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/gui/Gui-X.cc b/src/gui/Gui-X.cc index 58a0df4..2a7011e 100644 --- a/src/gui/Gui-X.cc +++ b/src/gui/Gui-X.cc @@ -53,7 +53,9 @@ bool Gui_Init() RootWindow(g_display, g_vi->screen), g_vi->visual, AllocNone); g_swa.colormap = colormap; g_swa.border_pixel = 0; - g_swa.event_mask = StructureNotifyMask; + g_swa.event_mask = StructureNotifyMask | + KeyPressMask | KeyReleaseMask | + ButtonPressMask | ButtonReleaseMask; return true; } diff --git a/src/gui/Gui.h b/src/gui/Gui.h index 64835ac..e0cd38f 100644 --- a/src/gui/Gui.h +++ b/src/gui/Gui.h @@ -3,11 +3,32 @@ #include -#define GUI_EVENT_CLOSE_WINDOW 1u +#define GUI_EVENT_CLOSE_WINDOW 1u +#define GUI_EVENT_EXPOSE 2u +#define GUI_EVENT_KEY_PRESS 3u +#define GUI_EVENT_KEY_RELEASE 4u +#define GUI_EVENT_BUTTON_PRESS 5u +#define GUI_EVENT_BUTTON_RELEASE 6u + +typedef struct +{ + uint32_t key; + uint8_t mods; +} Gui_KeyEvent; + +typedef struct +{ + uint8_t button; +} Gui_ButtonEvent; typedef struct { uint8_t type; + union + { + Gui_KeyEvent key; + Gui_ButtonEvent button; + }; } Gui_Event; bool Gui_Init(); From 2348d7ede1557b023575b186ac4c8dc9f4015b6c Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sat, 30 Sep 2017 18:24:50 -0400 Subject: [PATCH 03/30] Split up Jtk sources and headers by functional area --- src/gui/Gui.h | 40 --------- src/gui/Window.cc | 8 +- src/gui/{Gui-X.cc => jtk/Jtk-X.cc} | 18 ++-- src/gui/jtk/Jtk.h | 11 +++ src/gui/jtk/Jtk_event.cc | 5 ++ src/gui/jtk/Jtk_event.h | 43 +++++++++ src/gui/jtk/Jtk_time.cc | 9 ++ src/gui/jtk/Jtk_time.h | 9 ++ src/gui/jtk/Jtk_timer.cc | 139 +++++++++++++++++++++++++++++ src/gui/jtk/Jtk_timer.h | 13 +++ src/gui/jtk/Jtk_window.h | 8 ++ wscript | 4 +- 12 files changed, 250 insertions(+), 57 deletions(-) delete mode 100644 src/gui/Gui.h rename src/gui/{Gui-X.cc => jtk/Jtk-X.cc} (90%) create mode 100644 src/gui/jtk/Jtk.h create mode 100644 src/gui/jtk/Jtk_event.cc create mode 100644 src/gui/jtk/Jtk_event.h create mode 100644 src/gui/jtk/Jtk_time.cc create mode 100644 src/gui/jtk/Jtk_time.h create mode 100644 src/gui/jtk/Jtk_timer.cc create mode 100644 src/gui/jtk/Jtk_timer.h create mode 100644 src/gui/jtk/Jtk_window.h diff --git a/src/gui/Gui.h b/src/gui/Gui.h deleted file mode 100644 index e0cd38f..0000000 --- a/src/gui/Gui.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef GUI_H -#define GUI_H - -#include - -#define GUI_EVENT_CLOSE_WINDOW 1u -#define GUI_EVENT_EXPOSE 2u -#define GUI_EVENT_KEY_PRESS 3u -#define GUI_EVENT_KEY_RELEASE 4u -#define GUI_EVENT_BUTTON_PRESS 5u -#define GUI_EVENT_BUTTON_RELEASE 6u - -typedef struct -{ - uint32_t key; - uint8_t mods; -} Gui_KeyEvent; - -typedef struct -{ - uint8_t button; -} Gui_ButtonEvent; - -typedef struct -{ - uint8_t type; - union - { - Gui_KeyEvent key; - Gui_ButtonEvent button; - }; -} Gui_Event; - -bool Gui_Init(); -void * Gui_CreateWindow(); -void Gui_SwapBuffers(void * window); -void Gui_CloseWindow(void * window); -void Gui_WaitForEvent(Gui_Event * event); - -#endif diff --git a/src/gui/Window.cc b/src/gui/Window.cc index 219ead0..a06c4e6 100644 --- a/src/gui/Window.cc +++ b/src/gui/Window.cc @@ -2,7 +2,7 @@ #include "Window.h" #include "Runtime.h" #include "BufferPane.h" -#include "Gui.h" +#include "Jtk.h" #include #include "jes_icon-32x32.h" #include @@ -77,13 +77,13 @@ void Window::set_window_icon() */ bool Window::create(std::shared_ptr buffer) { - if (!Gui_Init()) + if (!Jtk_Init()) { std::cerr << "Error initializing GUI" << std::endl; return false; } - m_window = Gui_CreateWindow(); + m_window = Jtk_CreateWindow(); if (m_window == NULL) { std::cerr << "Error creating window" << std::endl; @@ -437,7 +437,7 @@ void Window::redraw() m_gl->draw_rect(0, m_command_buffer_screen_rows * m_font->get_line_height(), m_width, 1, 0.5, 0.5, 0.5, 1.0); m_command_buffer_pane->draw(); - Gui_SwapBuffers(m_window); + Jtk_SwapBuffers(m_window); } #if 0 diff --git a/src/gui/Gui-X.cc b/src/gui/jtk/Jtk-X.cc similarity index 90% rename from src/gui/Gui-X.cc rename to src/gui/jtk/Jtk-X.cc index 2a7011e..dd9af0b 100644 --- a/src/gui/Gui-X.cc +++ b/src/gui/jtk/Jtk-X.cc @@ -1,6 +1,6 @@ -#ifdef GUI_X +#ifdef JTK_X -#include "Gui.h" +#include "Jtk.h" #include #include @@ -15,11 +15,11 @@ static Bool WaitForNotify(Display * display, XEvent * event, XPointer arg) } /** - * Initialize the Gui subsystem. + * Initialize the Jtk subsystem. * * @return true on success, false on failure */ -bool Gui_Init() +bool Jtk_Init() { static int glx_attribute_list[] = { GLX_RGBA, @@ -60,7 +60,7 @@ bool Gui_Init() return true; } -void * Gui_CreateWindow() +void * Jtk_CreateWindow() { XEvent event; Window window = XCreateWindow(g_display, @@ -79,18 +79,14 @@ void * Gui_CreateWindow() return (void *)window; } -void Gui_SwapBuffers(void * window) +void Jtk_SwapBuffers(void * window) { glXSwapBuffers(g_display, (Window)window); } -void Gui_CloseWindow(void * window) +void Jtk_CloseWindow(void * window) { XDestroyWindow(g_display, (Window)window); } -void Gui_WaitForEvent(Gui_Event * event) -{ -} - #endif diff --git a/src/gui/jtk/Jtk.h b/src/gui/jtk/Jtk.h new file mode 100644 index 0000000..f132677 --- /dev/null +++ b/src/gui/jtk/Jtk.h @@ -0,0 +1,11 @@ +#ifndef JTK_H +#define JTK_H + +#include "Jtk_event.h" +#include "Jtk_time.h" +#include "Jtk_timer.h" +#include "Jtk_window.h" + +bool Jtk_Init(); + +#endif diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc new file mode 100644 index 0000000..281c042 --- /dev/null +++ b/src/gui/jtk/Jtk_event.cc @@ -0,0 +1,5 @@ +#include "Jtk.h" + +void Jtk_WaitForEvent(Jtk_Event * event) +{ +} diff --git a/src/gui/jtk/Jtk_event.h b/src/gui/jtk/Jtk_event.h new file mode 100644 index 0000000..3fbedd0 --- /dev/null +++ b/src/gui/jtk/Jtk_event.h @@ -0,0 +1,43 @@ +#ifndef JTK_EVENT_H +#define JTK_EVENT_H + +#include +#include + +#define JTK_EVENT_CLOSE_WINDOW 1u +#define JTK_EVENT_EXPOSE 2u +#define JTK_EVENT_KEY_PRESS 3u +#define JTK_EVENT_KEY_RELEASE 4u +#define JTK_EVENT_BUTTON_PRESS 5u +#define JTK_EVENT_BUTTON_RELEASE 6u + +typedef struct +{ + uint32_t key; + uint8_t mods; +} Jtk_KeyEvent; + +typedef struct +{ + uint8_t button; +} Jtk_ButtonEvent; + +typedef struct +{ + size_t timer_id; +} Jtk_TimerEvent; + +typedef struct +{ + uint8_t type; + union + { + Jtk_KeyEvent key; + Jtk_ButtonEvent button; + Jtk_TimerEvent timer; + }; +} Jtk_Event; + +void Jtk_WaitForEvent(Jtk_Event * event); + +#endif diff --git a/src/gui/jtk/Jtk_time.cc b/src/gui/jtk/Jtk_time.cc new file mode 100644 index 0000000..bd07440 --- /dev/null +++ b/src/gui/jtk/Jtk_time.cc @@ -0,0 +1,9 @@ +#include "Jtk.h" +#include + +uint64_t Jtk_UsTime() +{ + struct timeval tv; + gettimeofday(&tv, nullptr); + return (uint64_t)tv.tv_sec * 1000000u + (uint64_t)tv.tv_usec; +} diff --git a/src/gui/jtk/Jtk_time.h b/src/gui/jtk/Jtk_time.h new file mode 100644 index 0000000..130bf75 --- /dev/null +++ b/src/gui/jtk/Jtk_time.h @@ -0,0 +1,9 @@ +#ifndef JTK_TIME_H +#define JTK_TIME_H + +#include "Jtk_timer.h" + +bool Jtk_Init(); +uint64_t Jtk_UsTime(); + +#endif diff --git a/src/gui/jtk/Jtk_timer.cc b/src/gui/jtk/Jtk_timer.cc new file mode 100644 index 0000000..557bf7e --- /dev/null +++ b/src/gui/jtk/Jtk_timer.cc @@ -0,0 +1,139 @@ +#include "Jtk.h" +#include +#include +#include + +typedef struct +{ + uint64_t next; /**< Time the timer next expires (us). */ + uint64_t interval; /**< Timer interval (us). */ + size_t id; /**< Timer ID. */ +} Timer; + +/** Vector used to allocate timer IDs. */ +static std::vector> g_timers; + +/** Linked list used to traverse all active timers. */ +static std::list> g_active_timers; + +static size_t AllocateTimerID() +{ + for (size_t i = 0; i < g_timers.size(); i++) + { + if (!g_timers[i]) + { + return i; + } + } + g_timers.push_back(nullptr); + return g_timers.size() - 1u; +} + +/** + * Add a timer. + * + * @param delay + * Delay time in milliseconds. + * @param interval + * Interval time in milliseconds. A value of 0 indicates that the timer + * is not periodic. + * + * @return + * Timer ID. + */ +size_t Jtk_AddTimer(uint32_t delay, uint32_t interval) +{ + uint64_t current_system_time = Jtk_UsTime(); + size_t timer_id = AllocateTimerID(); + auto timer = std::make_shared(); + timer->next = current_system_time + (delay * 1000u); + timer->interval = interval * 1000u; + timer->id = timer_id; + g_timers[timer_id] = timer; + g_active_timers.push_back(timer); + return timer_id; +} + +/** + * Remove a timer. + * + * @param timer_id + * The ID of the timer to remove. + */ +void Jtk_RemoveTimer(size_t timer_id) +{ + if (timer_id < g_timers.size()) + { + g_timers[timer_id] = nullptr; + auto timer = g_timers[timer_id]; + g_active_timers.remove(timer); + } +} + +/** + * Determine the amount of time until the next timer expires (in us). + * + * @return + * Time (in us) until the next timer expires. This will be 0 if an active + * timer has already expired, and will be (uint64_t)-1 if there are no + * active timers. + */ +uint64_t Jtk_TimeToNextTimerExpiration() +{ + uint64_t time = (uint64_t)-1; + uint64_t current_system_time = Jtk_UsTime(); + for (auto & timer : g_active_timers) + { + if (timer->next <= current_system_time) + { + return 0; + } + uint64_t time_until_this_timer = timer->next - current_system_time; + if (time_until_this_timer < time) + { + time = time_until_this_timer; + } + } + return time; +} + +/** + * Service a timer. + * + * This will increment the timer's next activation time by its interval, or + * for a timer with an interval of 0, will remove the timer. + * + * @param timer_id + * The ID of the timer to service. + */ +void Jtk_ServiceTimer(size_t timer_id) +{ + auto timer = g_timers[timer_id]; + if (timer->interval == 0u) + { + Jtk_RemoveTimer(timer_id); + } + else + { + timer->next += timer->interval; + } +} + +/** + * Return the ID of an expired timer. + * + * @return + * The ID of an expired timer, or (size_t)-1 if no timer is expired. + */ +size_t Jtk_GetExpiredTimer() +{ + uint64_t current_system_time = Jtk_UsTime(); + for (auto & timer : g_active_timers) + { + if (timer->next <= current_system_time) + { + return timer->id; + } + } + return (size_t)-1; +} diff --git a/src/gui/jtk/Jtk_timer.h b/src/gui/jtk/Jtk_timer.h new file mode 100644 index 0000000..ae6c93d --- /dev/null +++ b/src/gui/jtk/Jtk_timer.h @@ -0,0 +1,13 @@ +#ifndef JTK_TIMER_H +#define JTK_TIMER_H + +#include +#include + +size_t Jtk_AddTimer(uint32_t delay, uint32_t interval); +void Jtk_RemoveTimer(size_t timer_id); +uint64_t Jtk_TimeToNextTimerExpiration(); +void Jtk_ServiceTimer(size_t timer_id); +size_t Jtk_GetExpiredTimer(); + +#endif diff --git a/src/gui/jtk/Jtk_window.h b/src/gui/jtk/Jtk_window.h new file mode 100644 index 0000000..1046c93 --- /dev/null +++ b/src/gui/jtk/Jtk_window.h @@ -0,0 +1,8 @@ +#ifndef JTK_WINDOW_H +#define JTK_WINDOW_H + +void * Jtk_CreateWindow(); +void Jtk_SwapBuffers(void * window); +void Jtk_CloseWindow(void * window); + +#endif diff --git a/wscript b/wscript index 14a418c..c67b05a 100644 --- a/wscript +++ b/wscript @@ -25,11 +25,11 @@ def build(bld): libs = [] if platform.system() == "Linux": defines += ["PLATFORM_LINUX"] - defines += ["GUI_X"] + defines += ["JTK_X"] libs += ["dl", "GL", "X11"] elif platform.system() == "Windows": defines += ["PLATFORM_WINDOWS"] - defines += ["GUI_WINDOWS"] + defines += ["JTK_WINDOWS"] libs += ["opengl32"] defines += ['GLCXX_GL_INCLUDE="gl3w.h"'] sources = bld.path.ant_glob(["src/**/*.cc", "src/**/*.c", "libs/glcxx/src/glcxx/*"]) From 095d8d440ec7762bfb82306321ba1c11a48a1d7f Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sat, 30 Sep 2017 20:17:22 -0400 Subject: [PATCH 04/30] Begin processing X events --- src/gui/jtk/{Jtk-X.cc => Jtk.cc} | 45 +++------------- src/gui/jtk/Jtk_event.cc | 89 ++++++++++++++++++++++++++++++++ src/gui/jtk/Jtk_event.h | 3 +- src/gui/jtk/Jtk_internal.h | 9 ++++ src/gui/jtk/Jtk_window.cc | 44 ++++++++++++++++ 5 files changed, 150 insertions(+), 40 deletions(-) rename src/gui/jtk/{Jtk-X.cc => Jtk.cc} (52%) create mode 100644 src/gui/jtk/Jtk_internal.h create mode 100644 src/gui/jtk/Jtk_window.cc diff --git a/src/gui/jtk/Jtk-X.cc b/src/gui/jtk/Jtk.cc similarity index 52% rename from src/gui/jtk/Jtk-X.cc rename to src/gui/jtk/Jtk.cc index dd9af0b..f150c72 100644 --- a/src/gui/jtk/Jtk-X.cc +++ b/src/gui/jtk/Jtk.cc @@ -1,18 +1,14 @@ +#include "Jtk.h" + #ifdef JTK_X -#include "Jtk.h" #include #include -static Display * g_display; -static XVisualInfo * g_vi; -static XSetWindowAttributes g_swa; -static GLXContext g_context; - -static Bool WaitForNotify(Display * display, XEvent * event, XPointer arg) -{ - return (event->type == MapNotify) && (event->xmap.window == (Window)arg); -} +Display * g_display; +XVisualInfo * g_vi; +XSetWindowAttributes g_swa; +GLXContext g_context; /** * Initialize the Jtk subsystem. @@ -60,33 +56,4 @@ bool Jtk_Init() return true; } -void * Jtk_CreateWindow() -{ - XEvent event; - Window window = XCreateWindow(g_display, - RootWindow(g_display, g_vi->screen), - 0, 0, 800, 800, 0, g_vi->depth, InputOutput, g_vi->visual, - CWBorderPixel | CWColormap | CWEventMask, &g_swa); - XMapWindow(g_display, window); - XIfEvent(g_display, &event, WaitForNotify, (XPointer)window); - if (glXMakeCurrent(g_display, window, g_context) == False) - { - fprintf(stderr, "glXMakeCurrent() failure\n"); - XDestroyWindow(g_display, window); - return nullptr; - } - - return (void *)window; -} - -void Jtk_SwapBuffers(void * window) -{ - glXSwapBuffers(g_display, (Window)window); -} - -void Jtk_CloseWindow(void * window) -{ - XDestroyWindow(g_display, (Window)window); -} - #endif diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc index 281c042..e75ab79 100644 --- a/src/gui/jtk/Jtk_event.cc +++ b/src/gui/jtk/Jtk_event.cc @@ -1,5 +1,94 @@ #include "Jtk.h" +#ifdef JTK_X + +#include +#include +#include +#include +#include "Jtk_internal.h" + +/** Do not wait longer than 100ms */ +#define MAX_WAIT_TIME 100000u + +/** + * Process an X event. + * + * @param x_event + * Pointer to the X event. + * @param event + * Pointer to the Jtk event. + * + * @retval true + * The event should be passed to the user and event has been filled in. + * @retval false + * The event should not be passed to the user. + */ +static bool ProcessXEvent(XEvent * x_event, Jtk_Event * event) +{ + switch (x_event->type) + { + case KeyPress: + break; + + case KeyRelease: + break; + + case ButtonPress: + break; + + case ButtonRelease: + break; + + case Expose: + break; + + case MappingNotify: + XRefreshKeyboardMapping(&x_event->xmapping); + return false; + } + + return false; +} + void Jtk_WaitForEvent(Jtk_Event * event) { + for (;;) + { + /* First check if any timer has expired. */ + size_t timer_id = Jtk_GetExpiredTimer(); + if (timer_id != (size_t)-1) + { + event->type = JTK_EVENT_TIMER; + event->timer.timer_id = timer_id; + return; + } + + /* Next check for an X event. */ + if (XPending(g_display) > 0) + { + XEvent x_event; + XNextEvent(g_display, &x_event); + if (ProcessXEvent(&x_event, event)) + return; + } + + /* Finally, wait for something to happen. */ + uint64_t time_to_wait = Jtk_TimeToNextTimerExpiration(); + if (time_to_wait > MAX_WAIT_TIME) + { + time_to_wait = MAX_WAIT_TIME; + } + + int x_fd = ConnectionNumber(g_display); + fd_set fds; + FD_ZERO(&fds); + FD_SET(x_fd, &fds); + struct timeval tv; + tv.tv_sec = time_to_wait / 1000000u; + tv.tv_usec = time_to_wait % 1000000u; + select(x_fd + 1, &fds, nullptr, nullptr, &tv); + } } + +#endif diff --git a/src/gui/jtk/Jtk_event.h b/src/gui/jtk/Jtk_event.h index 3fbedd0..88da58b 100644 --- a/src/gui/jtk/Jtk_event.h +++ b/src/gui/jtk/Jtk_event.h @@ -5,11 +5,12 @@ #include #define JTK_EVENT_CLOSE_WINDOW 1u -#define JTK_EVENT_EXPOSE 2u +#define JTK_EVENT_WINDOW_EXPOSE 2u #define JTK_EVENT_KEY_PRESS 3u #define JTK_EVENT_KEY_RELEASE 4u #define JTK_EVENT_BUTTON_PRESS 5u #define JTK_EVENT_BUTTON_RELEASE 6u +#define JTK_EVENT_TIMER 7u typedef struct { diff --git a/src/gui/jtk/Jtk_internal.h b/src/gui/jtk/Jtk_internal.h new file mode 100644 index 0000000..5d5c518 --- /dev/null +++ b/src/gui/jtk/Jtk_internal.h @@ -0,0 +1,9 @@ +#ifndef JTK_INTERNAL_H +#define JTK_INTERNAL_H + +extern Display * g_display; +extern XVisualInfo * g_vi; +extern XSetWindowAttributes g_swa; +extern GLXContext g_context; + +#endif diff --git a/src/gui/jtk/Jtk_window.cc b/src/gui/jtk/Jtk_window.cc new file mode 100644 index 0000000..b6b3dda --- /dev/null +++ b/src/gui/jtk/Jtk_window.cc @@ -0,0 +1,44 @@ + +#include "Jtk.h" + +#ifdef JTK_X + +#include +#include "Jtk_internal.h" +#include + +static Bool WaitForNotify(Display * display, XEvent * event, XPointer arg) +{ + return (event->type == MapNotify) && (event->xmap.window == (Window)arg); +} + +void * Jtk_CreateWindow() +{ + XEvent event; + Window window = XCreateWindow(g_display, + RootWindow(g_display, g_vi->screen), + 0, 0, 800, 800, 0, g_vi->depth, InputOutput, g_vi->visual, + CWBorderPixel | CWColormap | CWEventMask, &g_swa); + XMapWindow(g_display, window); + XIfEvent(g_display, &event, WaitForNotify, (XPointer)window); + if (glXMakeCurrent(g_display, window, g_context) == False) + { + fprintf(stderr, "glXMakeCurrent() failure\n"); + XDestroyWindow(g_display, window); + return nullptr; + } + + return (void *)window; +} + +void Jtk_SwapBuffers(void * window) +{ + glXSwapBuffers(g_display, (Window)window); +} + +void Jtk_CloseWindow(void * window) +{ + XDestroyWindow(g_display, (Window)window); +} + +#endif From 52b3c9faa94bdc727456827a0b4a9e5e1dbc95c1 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sat, 30 Sep 2017 20:21:49 -0400 Subject: [PATCH 05/30] if an X event is not sent to the user, make sure to check for more X events ready to process --- src/gui/jtk/Jtk_event.cc | 4 ++-- src/gui/jtk/Jtk_event.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc index e75ab79..d710543 100644 --- a/src/gui/jtk/Jtk_event.cc +++ b/src/gui/jtk/Jtk_event.cc @@ -51,7 +51,7 @@ static bool ProcessXEvent(XEvent * x_event, Jtk_Event * event) return false; } -void Jtk_WaitForEvent(Jtk_Event * event) +void Jtk_WaitEvent(Jtk_Event * event) { for (;;) { @@ -65,7 +65,7 @@ void Jtk_WaitForEvent(Jtk_Event * event) } /* Next check for an X event. */ - if (XPending(g_display) > 0) + while (XPending(g_display) > 0) { XEvent x_event; XNextEvent(g_display, &x_event); diff --git a/src/gui/jtk/Jtk_event.h b/src/gui/jtk/Jtk_event.h index 88da58b..e889b43 100644 --- a/src/gui/jtk/Jtk_event.h +++ b/src/gui/jtk/Jtk_event.h @@ -39,6 +39,6 @@ typedef struct }; } Jtk_Event; -void Jtk_WaitForEvent(Jtk_Event * event); +void Jtk_WaitEvent(Jtk_Event * event); #endif From 30a38a1487f9042a6eef8b760d0bc7a0dfd4cd36 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sat, 30 Sep 2017 21:23:22 -0400 Subject: [PATCH 06/30] Begin handling X keyboard events --- src/gui/jtk/Jtk.h | 1 + src/gui/jtk/Jtk_event.cc | 48 ++++++++++++++++++++++++++++++++++++++-- src/gui/jtk/Jtk_keys.h | 10 +++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 src/gui/jtk/Jtk_keys.h diff --git a/src/gui/jtk/Jtk.h b/src/gui/jtk/Jtk.h index f132677..7eccbf1 100644 --- a/src/gui/jtk/Jtk.h +++ b/src/gui/jtk/Jtk.h @@ -2,6 +2,7 @@ #define JTK_H #include "Jtk_event.h" +#include "Jtk_keys.h" #include "Jtk_time.h" #include "Jtk_timer.h" #include "Jtk_window.h" diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc index d710543..4efff2a 100644 --- a/src/gui/jtk/Jtk_event.cc +++ b/src/gui/jtk/Jtk_event.cc @@ -11,6 +11,48 @@ /** Do not wait longer than 100ms */ #define MAX_WAIT_TIME 100000u +/** + * Process an X keyboard event. + * + * @param x_event + * Pointer to the X event. + * @param event + * Pointer to the Jtk event. + */ +static bool ProcessXKeyEvent(XEvent * x_event, Jtk_Event * event) +{ + char buffer; + KeySym keysym; + if (XLookupString(&x_event->xkey, &buffer, 1, &keysym, nullptr) > 0) + { + uint8_t mods = 0u; + if (x_event->xkey.state & ShiftMask) + { + mods |= JTK_KEY_MODS_SHIFT; + } + if (x_event->xkey.state & LockMask) + { + mods |= JTK_KEY_MODS_LOCK; + } + if (x_event->xkey.state & ControlMask) + { + mods |= JTK_KEY_MODS_CTRL; + } + event->key.key = buffer; + event->key.mods = mods; + } + else + { + switch (keysym) + { + case XK_F1: event->key.key = JTK_KEY_F1; break; + default: + return false; + } + } + return true; +} + /** * Process an X event. * @@ -29,10 +71,12 @@ static bool ProcessXEvent(XEvent * x_event, Jtk_Event * event) switch (x_event->type) { case KeyPress: - break; + event->type = JTK_EVENT_KEY_PRESS; + return ProcessXKeyEvent(x_event, event); case KeyRelease: - break; + event->type = JTK_EVENT_KEY_RELEASE; + return ProcessXKeyEvent(x_event, event); case ButtonPress: break; diff --git a/src/gui/jtk/Jtk_keys.h b/src/gui/jtk/Jtk_keys.h new file mode 100644 index 0000000..f4dc28c --- /dev/null +++ b/src/gui/jtk/Jtk_keys.h @@ -0,0 +1,10 @@ +#ifndef JTK_KEYS_H +#define JTK_KEYS_H + +#define JTK_KEY_MODS_SHIFT 0x1u +#define JTK_KEY_MODS_LOCK 0x2u +#define JTK_KEY_MODS_CTRL 0x4u + +#define JTK_KEY_F1 0xFF000001u + +#endif From 035f5805ad5150a25b644513eff2bd63b2a0b833 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sat, 30 Sep 2017 22:09:25 -0400 Subject: [PATCH 07/30] Define many more keys --- src/gui/jtk/Jtk_event.cc | 107 ++++++++++++++++++++++++++++++++++++- src/gui/jtk/Jtk_keys.h | 112 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 214 insertions(+), 5 deletions(-) diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc index 4efff2a..8010053 100644 --- a/src/gui/jtk/Jtk_event.cc +++ b/src/gui/jtk/Jtk_event.cc @@ -45,7 +45,112 @@ static bool ProcessXKeyEvent(XEvent * x_event, Jtk_Event * event) { switch (keysym) { - case XK_F1: event->key.key = JTK_KEY_F1; break; + case XK_F1: event->key.key = JTK_KEY_F1; break; + case XK_F2: event->key.key = JTK_KEY_F2; break; + case XK_F3: event->key.key = JTK_KEY_F3; break; + case XK_F4: event->key.key = JTK_KEY_F4; break; + case XK_F5: event->key.key = JTK_KEY_F5; break; + case XK_F6: event->key.key = JTK_KEY_F6; break; + case XK_F7: event->key.key = JTK_KEY_F7; break; + case XK_F8: event->key.key = JTK_KEY_F8; break; + case XK_F9: event->key.key = JTK_KEY_F9; break; + case XK_F10: event->key.key = JTK_KEY_F10; break; + case XK_F11: event->key.key = JTK_KEY_F11; break; + case XK_F12: event->key.key = JTK_KEY_F12; break; + case XK_F13: event->key.key = JTK_KEY_F13; break; + case XK_F14: event->key.key = JTK_KEY_F14; break; + case XK_F15: event->key.key = JTK_KEY_F15; break; + case XK_F16: event->key.key = JTK_KEY_F16; break; + case XK_F17: event->key.key = JTK_KEY_F17; break; + case XK_F18: event->key.key = JTK_KEY_F18; break; + case XK_F19: event->key.key = JTK_KEY_F19; break; + case XK_F20: event->key.key = JTK_KEY_F20; break; + case XK_F21: event->key.key = JTK_KEY_F21; break; + case XK_F22: event->key.key = JTK_KEY_F22; break; + case XK_F23: event->key.key = JTK_KEY_F23; break; + case XK_F24: event->key.key = JTK_KEY_F24; break; + case XK_F25: event->key.key = JTK_KEY_F25; break; + case XK_F26: event->key.key = JTK_KEY_F26; break; + case XK_F27: event->key.key = JTK_KEY_F27; break; + case XK_F28: event->key.key = JTK_KEY_F28; break; + case XK_F29: event->key.key = JTK_KEY_F29; break; + case XK_F30: event->key.key = JTK_KEY_F30; break; + case XK_F31: event->key.key = JTK_KEY_F31; break; + + case XK_Shift_L: event->key.key = JTK_KEY_SHIFT_L; break; + case XK_Shift_R: event->key.key = JTK_KEY_SHIFT_R; break; + case XK_Control_L: event->key.key = JTK_KEY_CTRL_L; break; + case XK_Control_R: event->key.key = JTK_KEY_CTRL_R; break; + case XK_Caps_Lock: event->key.key = JTK_KEY_CAPS_LOCK; break; + case XK_Shift_Lock: event->key.key = JTK_KEY_SHIFT_LOCK;break; + + case XK_Meta_L: event->key.key = JTK_KEY_META_L; break; + case XK_Meta_R: event->key.key = JTK_KEY_META_R; break; + case XK_Alt_L: event->key.key = JTK_KEY_ALT_L; break; + case XK_Alt_R: event->key.key = JTK_KEY_ALT_R; break; + case XK_Super_L: event->key.key = JTK_KEY_SUPER_L; break; + case XK_Super_R: event->key.key = JTK_KEY_SUPER_R; break; + + case XK_Home: event->key.key = JTK_KEY_HOME; break; + case XK_Left: event->key.key = JTK_KEY_LEFT; break; + case XK_Up: event->key.key = JTK_KEY_UP; break; + case XK_Right: event->key.key = JTK_KEY_RIGHT; break; + case XK_Down: event->key.key = JTK_KEY_DOWN; break; + case XK_Page_Up: event->key.key = JTK_KEY_PAGE_UP; break; + case XK_Page_Down: event->key.key = JTK_KEY_PAGE_DOWN; break; + case XK_End: event->key.key = JTK_KEY_END; break; + case XK_Begin: event->key.key = JTK_KEY_BEGIN; break; + + case XK_Select: event->key.key = JTK_KEY_SELECT; break; + case XK_Print: event->key.key = JTK_KEY_PRINT; break; + case XK_Execute: event->key.key = JTK_KEY_EXECUTE; break; + case XK_Insert: event->key.key = JTK_KEY_INSERT; break; + case XK_Undo: event->key.key = JTK_KEY_UNDO; break; + case XK_Redo: event->key.key = JTK_KEY_REDO; break; + case XK_Menu: event->key.key = JTK_KEY_MENU; break; + case XK_Find: event->key.key = JTK_KEY_FIND; break; + case XK_Cancel: event->key.key = JTK_KEY_CANCEL; break; + case XK_Help: event->key.key = JTK_KEY_HELP; break; + case XK_Break: event->key.key = JTK_KEY_BREAK; break; + case XK_Num_Lock: event->key.key = JTK_KEY_NUM_LOCK; break; + + case XK_KP_Space: event->key.key = JTK_KEY_KP_SPACE; break; + case XK_KP_Tab: event->key.key = JTK_KEY_KP_TAB; break; + case XK_KP_Enter: event->key.key = JTK_KEY_KP_ENTER; break; + case XK_KP_F1: event->key.key = JTK_KEY_KP_F1; break; + case XK_KP_F2: event->key.key = JTK_KEY_KP_F2; break; + case XK_KP_F3: event->key.key = JTK_KEY_KP_F3; break; + case XK_KP_F4: event->key.key = JTK_KEY_KP_F4; break; + case XK_KP_Home: event->key.key = JTK_KEY_KP_HOME; break; + case XK_KP_Left: event->key.key = JTK_KEY_KP_LEFT; break; + case XK_KP_Up: event->key.key = JTK_KEY_KP_UP; break; + case XK_KP_Right: event->key.key = JTK_KEY_KP_RIGHT; break; + case XK_KP_Down: event->key.key = JTK_KEY_KP_DOWN; break; + case XK_KP_Page_Up: event->key.key = JTK_KEY_KP_PAGE_UP; break; + case XK_KP_Page_Down: event->key.key = JTK_KEY_KP_PAGE_DOWN; break; + case XK_KP_End: event->key.key = JTK_KEY_KP_END; break; + case XK_KP_Begin: event->key.key = JTK_KEY_KP_BEGIN; break; + case XK_KP_Insert: event->key.key = JTK_KEY_KP_INSERT; break; + case XK_KP_Delete: event->key.key = JTK_KEY_KP_DELETE; break; + case XK_KP_Equal: event->key.key = JTK_KEY_KP_EQUAL; break; + case XK_KP_Multiply: event->key.key = JTK_KEY_KP_MULTIPLY; break; + case XK_KP_Add: event->key.key = JTK_KEY_KP_ADD; break; + case XK_KP_Separator: event->key.key = JTK_KEY_KP_SEPARATOR; break; + case XK_KP_Subtract: event->key.key = JTK_KEY_KP_SUBTRACT; break; + case XK_KP_Decimal: event->key.key = JTK_KEY_KP_DECIMAL; break; + case XK_KP_Divide: event->key.key = JTK_KEY_KP_DIVIDE; break; + + case XK_KP_0: event->key.key = JTK_KEY_KP_0; break; + case XK_KP_1: event->key.key = JTK_KEY_KP_1; break; + case XK_KP_2: event->key.key = JTK_KEY_KP_2; break; + case XK_KP_3: event->key.key = JTK_KEY_KP_3; break; + case XK_KP_4: event->key.key = JTK_KEY_KP_4; break; + case XK_KP_5: event->key.key = JTK_KEY_KP_5; break; + case XK_KP_6: event->key.key = JTK_KEY_KP_6; break; + case XK_KP_7: event->key.key = JTK_KEY_KP_7; break; + case XK_KP_8: event->key.key = JTK_KEY_KP_8; break; + case XK_KP_9: event->key.key = JTK_KEY_KP_9; break; + default: return false; } diff --git a/src/gui/jtk/Jtk_keys.h b/src/gui/jtk/Jtk_keys.h index f4dc28c..3141d18 100644 --- a/src/gui/jtk/Jtk_keys.h +++ b/src/gui/jtk/Jtk_keys.h @@ -1,10 +1,114 @@ #ifndef JTK_KEYS_H #define JTK_KEYS_H -#define JTK_KEY_MODS_SHIFT 0x1u -#define JTK_KEY_MODS_LOCK 0x2u -#define JTK_KEY_MODS_CTRL 0x4u +#define JTK_KEY_MODS_SHIFT 0x1u +#define JTK_KEY_MODS_LOCK 0x2u +#define JTK_KEY_MODS_CTRL 0x4u -#define JTK_KEY_F1 0xFF000001u +#define JTK_KEY_F1 0xFF000001u +#define JTK_KEY_F2 0xFF000002u +#define JTK_KEY_F3 0xFF000003u +#define JTK_KEY_F4 0xFF000004u +#define JTK_KEY_F5 0xFF000005u +#define JTK_KEY_F6 0xFF000006u +#define JTK_KEY_F7 0xFF000007u +#define JTK_KEY_F8 0xFF000008u +#define JTK_KEY_F9 0xFF000009u +#define JTK_KEY_F10 0xFF00000Au +#define JTK_KEY_F11 0xFF00000Bu +#define JTK_KEY_F12 0xFF00000Cu +#define JTK_KEY_F13 0xFF00000Du +#define JTK_KEY_F14 0xFF00000Eu +#define JTK_KEY_F15 0xFF00000Fu +#define JTK_KEY_F16 0xFF000010u +#define JTK_KEY_F17 0xFF000011u +#define JTK_KEY_F18 0xFF000012u +#define JTK_KEY_F19 0xFF000013u +#define JTK_KEY_F20 0xFF000014u +#define JTK_KEY_F21 0xFF000015u +#define JTK_KEY_F22 0xFF000016u +#define JTK_KEY_F23 0xFF000017u +#define JTK_KEY_F24 0xFF000018u +#define JTK_KEY_F25 0xFF000019u +#define JTK_KEY_F26 0xFF00001Au +#define JTK_KEY_F27 0xFF00001Bu +#define JTK_KEY_F28 0xFF00001Cu +#define JTK_KEY_F29 0xFF00001Du +#define JTK_KEY_F30 0xFF00001Eu +#define JTK_KEY_F31 0xFF00001Fu + +#define JTK_KEY_SHIFT_L 0xFF000030u +#define JTK_KEY_SHIFT_R 0xFF000031u +#define JTK_KEY_CTRL_L 0xFF000032u +#define JTK_KEY_CTRL_R 0xFF000033u +#define JTK_KEY_CAPS_LOCK 0xFF000034u +#define JTK_KEY_SHIFT_LOCK 0xFF000035u + +#define JTK_KEY_META_L 0xFF000036u +#define JTK_KEY_META_R 0xFF000037u +#define JTK_KEY_ALT_L 0xFF000038u +#define JTK_KEY_ALT_R 0xFF000039u +#define JTK_KEY_SUPER_L 0xFF00003Au +#define JTK_KEY_SUPER_R 0xFF00003Bu + +#define JTK_KEY_HOME 0xFF00003Cu +#define JTK_KEY_LEFT 0xFF00003Du +#define JTK_KEY_UP 0xFF00003Eu +#define JTK_KEY_RIGHT 0xFF00003Fu +#define JTK_KEY_DOWN 0xFF000040u +#define JTK_KEY_PAGE_UP 0xFF000042u +#define JTK_KEY_PAGE_DOWN 0xFF000044u +#define JTK_KEY_END 0xFF000045u +#define JTK_KEY_BEGIN 0xFF000046u + +#define JTK_KEY_SELECT 0xFF000047u +#define JTK_KEY_PRINT 0xFF000048u +#define JTK_KEY_EXECUTE 0xFF000049u +#define JTK_KEY_INSERT 0xFF00004Au +#define JTK_KEY_UNDO 0xFF00004Bu +#define JTK_KEY_REDO 0xFF00004Cu +#define JTK_KEY_MENU 0xFF00004Du +#define JTK_KEY_FIND 0xFF00004Eu +#define JTK_KEY_CANCEL 0xFF00004Fu +#define JTK_KEY_HELP 0xFF000050u +#define JTK_KEY_BREAK 0xFF000051u +#define JTK_KEY_NUM_LOCK 0xFF000054u + +#define JTK_KEY_KP_SPACE 0xFF000055u +#define JTK_KEY_KP_TAB 0xFF000056u +#define JTK_KEY_KP_ENTER 0xFF000057u +#define JTK_KEY_KP_F1 0xFF000058u +#define JTK_KEY_KP_F2 0xFF000059u +#define JTK_KEY_KP_F3 0xFF00005Au +#define JTK_KEY_KP_F4 0xFF00005Bu +#define JTK_KEY_KP_HOME 0xFF00005Cu +#define JTK_KEY_KP_LEFT 0xFF00005Du +#define JTK_KEY_KP_UP 0xFF00005Eu +#define JTK_KEY_KP_RIGHT 0xFF00005Fu +#define JTK_KEY_KP_DOWN 0xFF000060u +#define JTK_KEY_KP_PAGE_UP 0xFF000062u +#define JTK_KEY_KP_PAGE_DOWN 0xFF000064u +#define JTK_KEY_KP_END 0xFF000065u +#define JTK_KEY_KP_BEGIN 0xFF000066u +#define JTK_KEY_KP_INSERT 0xFF000067u +#define JTK_KEY_KP_DELETE 0xFF000068u +#define JTK_KEY_KP_EQUAL 0xFF000069u +#define JTK_KEY_KP_MULTIPLY 0xFF00006Au +#define JTK_KEY_KP_ADD 0xFF00006Bu +#define JTK_KEY_KP_SEPARATOR 0xFF00006Cu +#define JTK_KEY_KP_SUBTRACT 0xFF00006Du +#define JTK_KEY_KP_DECIMAL 0xFF00006Eu +#define JTK_KEY_KP_DIVIDE 0xFF00006Fu + +#define JTK_KEY_KP_0 0xFF000070u +#define JTK_KEY_KP_1 0xFF000071u +#define JTK_KEY_KP_2 0xFF000072u +#define JTK_KEY_KP_3 0xFF000073u +#define JTK_KEY_KP_4 0xFF000074u +#define JTK_KEY_KP_5 0xFF000075u +#define JTK_KEY_KP_6 0xFF000076u +#define JTK_KEY_KP_7 0xFF000077u +#define JTK_KEY_KP_8 0xFF000078u +#define JTK_KEY_KP_9 0xFF000079u #endif From f424fd573daa7177dc6bb879cf564ec11e8c96c5 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sat, 30 Sep 2017 22:46:46 -0400 Subject: [PATCH 08/30] Filter out repeated key presses --- src/gui/jtk/Jtk_event.cc | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc index 8010053..6643311 100644 --- a/src/gui/jtk/Jtk_event.cc +++ b/src/gui/jtk/Jtk_event.cc @@ -158,6 +158,34 @@ static bool ProcessXKeyEvent(XEvent * x_event, Jtk_Event * event) return true; } +static Bool KeyRepeatCheckIfEvent(Display * display, XEvent * chkev, + XPointer arg) +{ + XEvent * release_event = (XEvent *)arg; + if (chkev->type == KeyPress && + chkev->xkey.keycode == release_event->xkey.keycode && + chkev->xkey.time - release_event->xkey.time < 2) + return True; + return False; +} + +/** + * Check to see if this is a repeated key. + */ +static bool IsRepeatKey(Display * display, XEvent * event) +{ + XEvent dummyev; + if (XPending(display)) + { + if (XCheckIfEvent(display, &dummyev, KeyRepeatCheckIfEvent, + (XPointer)event) == True) + { + return true; + } + } + return false; +} + /** * Process an X event. * @@ -180,6 +208,9 @@ static bool ProcessXEvent(XEvent * x_event, Jtk_Event * event) return ProcessXKeyEvent(x_event, event); case KeyRelease: + if (IsRepeatKey(g_display, x_event)) { + return false; + } event->type = JTK_EVENT_KEY_RELEASE; return ProcessXKeyEvent(x_event, event); From b9d650d9ef8ffa7ea0bb032e728c0c7b8bc7b723 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sun, 1 Oct 2017 08:02:26 -0400 Subject: [PATCH 09/30] fix Jtk_RemoveTimer() --- src/gui/jtk/Jtk_timer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/jtk/Jtk_timer.cc b/src/gui/jtk/Jtk_timer.cc index 557bf7e..4f4f2ce 100644 --- a/src/gui/jtk/Jtk_timer.cc +++ b/src/gui/jtk/Jtk_timer.cc @@ -64,9 +64,9 @@ void Jtk_RemoveTimer(size_t timer_id) { if (timer_id < g_timers.size()) { - g_timers[timer_id] = nullptr; auto timer = g_timers[timer_id]; g_active_timers.remove(timer); + g_timers[timer_id] = nullptr; } } From afd4b83814ff3bfa946fc83b3178be0c22e9d01f Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sun, 1 Oct 2017 08:03:44 -0400 Subject: [PATCH 10/30] service timers so they do not infinitely re-trigger --- src/gui/jtk/Jtk_event.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc index 6643311..9a21ec0 100644 --- a/src/gui/jtk/Jtk_event.cc +++ b/src/gui/jtk/Jtk_event.cc @@ -241,6 +241,7 @@ void Jtk_WaitEvent(Jtk_Event * event) { event->type = JTK_EVENT_TIMER; event->timer.timer_id = timer_id; + Jtk_ServiceTimer(timer_id); return; } From 6546508cc64f95d7a0eff58ff52e92b79c85a993 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sun, 1 Oct 2017 13:48:03 -0400 Subject: [PATCH 11/30] Begin replacing SDL keyboard handling with Jtk --- src/gui/Window.cc | 162 ++++++++-------------------------------------- src/gui/Window.h | 10 +-- 2 files changed, 31 insertions(+), 141 deletions(-) diff --git a/src/gui/Window.cc b/src/gui/Window.cc index a06c4e6..31a89a1 100644 --- a/src/gui/Window.cc +++ b/src/gui/Window.cc @@ -2,7 +2,6 @@ #include "Window.h" #include "Runtime.h" #include "BufferPane.h" -#include "Jtk.h" #include #include "jes_icon-32x32.h" #include @@ -143,11 +142,11 @@ bool Window::create(std::shared_ptr buffer) */ void Window::run_event_loop() { -#if 0 - SDL_Event event; + Jtk_Event event; - while ((!m_exit_requested) && SDL_WaitEvent(&event)) + while (!m_exit_requested) { + Jtk_WaitEvent(&event); handle_event(event); if (m_redraw_requested) { @@ -155,9 +154,6 @@ void Window::run_event_loop() redraw(); } } -#endif - redraw(); - sleep(5); } #if 0 @@ -185,20 +181,23 @@ Uint32 Key_Repeat(Uint32 interval, void * param) return 0u; } } +#endif /** - * Handle a SDL event. + * Handle a Jtk event. */ -void Window::handle_event(SDL_Event & event) +void Window::handle_event(Jtk_Event & event) { switch (event.type) { +#if 0 case SDL_QUIT: m_exit_requested = true; break; +#endif - case SDL_KEYDOWN: - m_keymod = event.key.keysym.mod; + case JTK_EVENT_KEY_PRESS: +#if 0 if (event.key.repeat == 0) { Key_Statuses[event.key.keysym.scancode].pressed = true; @@ -206,18 +205,25 @@ void Window::handle_event(SDL_Event & event) Key_Statuses[event.key.keysym.scancode].timer_id = SDL_AddTimer(300, Key_Repeat, (void *)event.key.keysym.scancode); handle_keysym(event.key.keysym.sym); } +#endif + handle_keyval(event.key.key); break; - case SDL_KEYUP: - m_keymod = event.key.keysym.mod; + 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; } +#endif break; + case JTK_EVENT_WINDOW_EXPOSE: + m_redraw_requested = true; + break; +#if 0 case SDL_WINDOWEVENT: switch (event.window.event) { @@ -246,40 +252,36 @@ void Window::handle_event(SDL_Event & event) m_focused_buffer_pane->scroll_window_down(ScrollMode::WHEEL); } break; +#endif } } -void Window::handle_keysym(uint32_t keysym) -{ - handle_keyval(get_keyval(keysym)); -} - void Window::handle_keyval(uint32_t keyval) { switch (keyval) { - case SDLK_HOME: + case JTK_KEY_HOME: m_focused_buffer_pane->cursor_move(BufferPane::CursorMovement::SOL); break; - case SDLK_END: + case JTK_KEY_END: m_focused_buffer_pane->cursor_move(BufferPane::CursorMovement::EOL); break; - case SDLK_RIGHT: + case JTK_KEY_RIGHT: m_focused_buffer_pane->cursor_move(BufferPane::CursorMovement::RIGHT); break; - case SDLK_LEFT: + case JTK_KEY_LEFT: m_focused_buffer_pane->cursor_move(BufferPane::CursorMovement::LEFT); break; - case SDLK_DOWN: + case JTK_KEY_DOWN: m_focused_buffer_pane->cursor_move(BufferPane::CursorMovement::DOWN); break; - case SDLK_UP: + case JTK_KEY_UP: m_focused_buffer_pane->cursor_move(BufferPane::CursorMovement::UP); break; - case SDLK_PAGEUP: + case JTK_KEY_PAGE_UP: m_focused_buffer_pane->scroll_window_up(ScrollMode::WHOLE_SCREEN); break; - case SDLK_PAGEDOWN: + case JTK_KEY_PAGE_DOWN: m_focused_buffer_pane->scroll_window_down(ScrollMode::WHOLE_SCREEN); break; default: @@ -402,7 +404,6 @@ void Window::handle_keyval(uint32_t keyval) break; } } -#endif void Window::resize() { @@ -440,113 +441,6 @@ void Window::redraw() Jtk_SwapBuffers(m_window); } -#if 0 -uint32_t Window::get_keyval(SDL_Keycode keysym) -{ - uint32_t keyval = keysym; - if ((m_keymod & (KMOD_SHIFT | KMOD_CAPS)) != 0u) - { - uint32_t shifted = get_shifted(keyval); - if (shifted != 0u) - { - keyval = shifted; - } - else - { - keyval |= Keymod::SHIFT; - } - } - switch (keyval) - { - case SDLK_RETURN: keyval = '\n'; break; - case SDLK_KP_DIVIDE: keyval = '/'; break; - case SDLK_KP_MULTIPLY: keyval = '*'; break; - case SDLK_KP_MINUS: keyval = '-'; break; - case SDLK_KP_PLUS: keyval = '+'; break; - case SDLK_KP_ENTER: keyval = '\n'; break; - case SDLK_KP_1: keyval = '1'; break; - case SDLK_KP_2: keyval = '2'; break; - case SDLK_KP_3: keyval = '3'; break; - case SDLK_KP_4: keyval = '4'; break; - case SDLK_KP_5: keyval = '5'; break; - case SDLK_KP_6: keyval = '6'; break; - case SDLK_KP_7: keyval = '7'; break; - case SDLK_KP_8: keyval = '8'; break; - case SDLK_KP_9: keyval = '9'; break; - case SDLK_KP_0: keyval = '0'; break; - case SDLK_KP_PERIOD: keyval = '.'; break; - case SDLK_KP_EQUALS: keyval = '='; break; - case SDLK_KP_COMMA: keyval = ','; break; - case SDLK_KP_LEFTPAREN: keyval = '('; break; - case SDLK_KP_RIGHTPAREN: keyval = ')'; break; - case SDLK_KP_LEFTBRACE: keyval = '{'; break; - case SDLK_KP_RIGHTBRACE: keyval = '}'; break; - case SDLK_KP_TAB: keyval = '\t'; break; - case SDLK_KP_BACKSPACE: keyval = '\b'; break; - case SDLK_KP_PERCENT: keyval = '%'; break; - case SDLK_KP_LESS: keyval = '<'; break; - case SDLK_KP_GREATER: keyval = '>'; break; - case SDLK_KP_AMPERSAND: keyval = '&'; break; - case SDLK_KP_VERTICALBAR: keyval = '|'; break; - case SDLK_KP_COLON: keyval = ':'; break; - case SDLK_KP_HASH: keyval = '#'; break; - case SDLK_KP_SPACE: keyval = ' '; break; - case SDLK_KP_AT: keyval = '@'; break; - case SDLK_KP_EXCLAM: keyval = '!'; break; - } - if ((m_keymod & KMOD_CTRL) != 0u) - { - keyval |= Keymod::CTRL; - } - if ((m_keymod & KMOD_ALT) != 0u) - { - keyval |= Keymod::ALT; - } - if ((m_keymod & KMOD_GUI) != 0u) - { - keyval |= Keymod::GUI; - } - return keyval; -} - -uint32_t Window::get_shifted(uint32_t keysym) -{ - if ((keysym >= 'a') && (keysym <= 'z')) - { - return keysym - ('a' - 'A'); - } - - switch (keysym) - { - case SDLK_QUOTE: return '"'; - case SDLK_COMMA: return '<'; - case SDLK_MINUS: return '_'; - case SDLK_PERIOD: return '>'; - case SDLK_SLASH: return '?'; - case SDLK_0: return ')'; - case SDLK_1: return '!'; - case SDLK_2: return '@'; - case SDLK_3: return '#'; - case SDLK_4: return '$'; - case SDLK_5: return '%'; - case SDLK_6: return '^'; - case SDLK_7: return '&'; - case SDLK_8: return '*'; - case SDLK_9: return '('; - case SDLK_SEMICOLON: return ':'; - case SDLK_EQUALS: return '+'; - case SDLK_LEFTBRACKET: return '{'; - case SDLK_BACKSLASH: return '|'; - case SDLK_RIGHTBRACKET: return '}'; - case SDLK_BACKQUOTE: return '~'; - case SDLK_SPACE: return ' '; - case SDLK_BACKSPACE: return '\b'; - } - - return 0u; -} -#endif - void Window::change_focus(std::shared_ptr buffer_pane) { m_focused_buffer_pane->set_focused(false); diff --git a/src/gui/Window.h b/src/gui/Window.h index 8c1aa1c..2da7bb3 100644 --- a/src/gui/Window.h +++ b/src/gui/Window.h @@ -8,6 +8,7 @@ #include "GL.h" #include "EncodedString.h" #include "CommandParser.h" +#include "Jtk.h" class BufferPane; @@ -54,10 +55,9 @@ protected: void resize(); void redraw(); -#if 0 - void handle_event(SDL_Event & event); - void handle_keysym(uint32_t keysym); + void handle_event(Jtk_Event & event); void handle_keyval(uint32_t keyval); +#if 0 uint32_t get_keyval(SDL_Keycode keysym); uint32_t get_shifted(uint32_t keysym); #endif @@ -86,10 +86,6 @@ protected: std::shared_ptr m_focused_buffer_pane; std::shared_ptr m_command_buffer; std::shared_ptr m_command_buffer_pane; - -#if 0 - Uint16 m_keymod; -#endif }; #endif From 15fcaa80fa8659542f075f6eb7d84fb13e11c314 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sun, 1 Oct 2017 13:56:01 -0400 Subject: [PATCH 12/30] Do not let X translate control key combinations to key codes for us. --- src/gui/jtk/Jtk_event.cc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc index 9a21ec0..131fc3e 100644 --- a/src/gui/jtk/Jtk_event.cc +++ b/src/gui/jtk/Jtk_event.cc @@ -23,7 +23,11 @@ static bool ProcessXKeyEvent(XEvent * x_event, Jtk_Event * event) { char buffer; KeySym keysym; - if (XLookupString(&x_event->xkey, &buffer, 1, &keysym, nullptr) > 0) + /* Make a copy of x_event and turn off the ControlMask bit for lookup + * up keycodes. We'll handle control keys ourselves. */ + XEvent x_event_for_key_lookup = *x_event; + x_event_for_key_lookup.xkey.state &= ~ControlMask; + if (XLookupString(&x_event_for_key_lookup.xkey, &buffer, 1, &keysym, nullptr) > 0) { uint8_t mods = 0u; if (x_event->xkey.state & ShiftMask) @@ -38,7 +42,14 @@ static bool ProcessXKeyEvent(XEvent * x_event, Jtk_Event * event) { mods |= JTK_KEY_MODS_CTRL; } - event->key.key = buffer; + if (buffer == '\r') + { + event->key.key = '\n'; + } + else + { + event->key.key = buffer; + } event->key.mods = mods; } else From 486253d0b64122b48c8f24f8ee47ce38ce830a62 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sun, 1 Oct 2017 17:00:06 -0400 Subject: [PATCH 13/30] Jtk: encode key modifiers in key value field for keyboard events --- src/gui/Window.cc | 29 +++--- src/gui/Window.h | 14 +-- src/gui/jtk/Jtk_event.cc | 29 +++--- src/gui/jtk/Jtk_event.h | 1 - src/gui/jtk/Jtk_keys.h | 208 ++++++++++++++++++++------------------- 5 files changed, 137 insertions(+), 144 deletions(-) diff --git a/src/gui/Window.cc b/src/gui/Window.cc index 31a89a1..6b0300e 100644 --- a/src/gui/Window.cc +++ b/src/gui/Window.cc @@ -206,7 +206,7 @@ void Window::handle_event(Jtk_Event & event) handle_keysym(event.key.keysym.sym); } #endif - handle_keyval(event.key.key); + handle_keypress(event.key.key); break; case JTK_EVENT_KEY_RELEASE: @@ -256,9 +256,10 @@ void Window::handle_event(Jtk_Event & event) } } -void Window::handle_keyval(uint32_t keyval) +void Window::handle_keypress(uint32_t keyval) { - switch (keyval) + uint32_t keycode = keyval & JTK_KEY_KEYCODE_MASK; + switch (keyval & (JTK_KEY_KEYCODE_MASK | JTK_KEY_MODS_CTRL)) { case JTK_KEY_HOME: m_focused_buffer_pane->cursor_move(BufferPane::CursorMovement::SOL); @@ -287,7 +288,7 @@ void Window::handle_keyval(uint32_t keyval) default: if (m_focused_buffer_pane->insert_mode()) { - if (keyval == '\033') + if (keycode == '\033') { if (m_focused_buffer_pane == m_command_buffer_pane) { @@ -300,9 +301,9 @@ void Window::handle_keyval(uint32_t keyval) m_focused_buffer_pane->exit_insert_mode(); } } - else if (keyval < 0xFFu) + else if (keycode < 0xFFu) { - if ((keyval == '\n') && (m_focused_buffer_pane == m_command_buffer_pane)) + if ((keycode == '\n') && (m_focused_buffer_pane == m_command_buffer_pane)) { EncodedString command = m_command_buffer->get_string(); m_command_buffer_pane->clear(); @@ -312,13 +313,13 @@ void Window::handle_keyval(uint32_t keyval) } else { - m_focused_buffer_pane->insert_code_point(keyval); + m_focused_buffer_pane->insert_code_point(keycode); } } } else { - switch (keyval) + switch (keyval & (JTK_KEY_KEYCODE_MASK | JTK_KEY_MODS_CTRL)) { case '0': m_focused_buffer_pane->cursor_move(BufferPane::CursorMovement::SOL); @@ -381,22 +382,22 @@ void Window::handle_keyval(uint32_t keyval) case 'x': m_focused_buffer_pane->kill_character_at_cursor(); break; - case Keymod::CTRL + 'b': + case JTK_KEY_MODS_CTRL + 'b': m_focused_buffer_pane->scroll_window_up(ScrollMode::WHOLE_SCREEN); break; - case Keymod::CTRL + 'd': + case JTK_KEY_MODS_CTRL + 'd': m_focused_buffer_pane->scroll_window_down(ScrollMode::HALF_SCREEN); break; - case Keymod::CTRL + 'e': + case JTK_KEY_MODS_CTRL + 'e': m_focused_buffer_pane->scroll_window_down(ScrollMode::ONE_LINE); break; - case Keymod::CTRL + 'f': + case JTK_KEY_MODS_CTRL + 'f': m_focused_buffer_pane->scroll_window_down(ScrollMode::WHOLE_SCREEN); break; - case Keymod::CTRL + 'u': + case JTK_KEY_MODS_CTRL + 'u': m_focused_buffer_pane->scroll_window_up(ScrollMode::HALF_SCREEN); break; - case Keymod::CTRL + 'y': + case JTK_KEY_MODS_CTRL + 'y': m_focused_buffer_pane->scroll_window_up(ScrollMode::ONE_LINE); break; } diff --git a/src/gui/Window.h b/src/gui/Window.h index 2da7bb3..ba7c0f1 100644 --- a/src/gui/Window.h +++ b/src/gui/Window.h @@ -15,18 +15,6 @@ class BufferPane; class Window { public: - class Keymod - { - public: - enum : uint32_t - { - CTRL = 0x10000, - ALT = 0x20000, - SHIFT = 0x40000, - GUI = 0x80000, - }; - }; - enum class ScrollMode : uint8_t { ONE_LINE, @@ -56,7 +44,7 @@ protected: void resize(); void redraw(); void handle_event(Jtk_Event & event); - void handle_keyval(uint32_t keyval); + void handle_keypress(uint32_t keyval); #if 0 uint32_t get_keyval(SDL_Keycode keysym); uint32_t get_shifted(uint32_t keysym); diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc index 131fc3e..8bab1bd 100644 --- a/src/gui/jtk/Jtk_event.cc +++ b/src/gui/jtk/Jtk_event.cc @@ -29,19 +29,6 @@ static bool ProcessXKeyEvent(XEvent * x_event, Jtk_Event * event) x_event_for_key_lookup.xkey.state &= ~ControlMask; if (XLookupString(&x_event_for_key_lookup.xkey, &buffer, 1, &keysym, nullptr) > 0) { - uint8_t mods = 0u; - if (x_event->xkey.state & ShiftMask) - { - mods |= JTK_KEY_MODS_SHIFT; - } - if (x_event->xkey.state & LockMask) - { - mods |= JTK_KEY_MODS_LOCK; - } - if (x_event->xkey.state & ControlMask) - { - mods |= JTK_KEY_MODS_CTRL; - } if (buffer == '\r') { event->key.key = '\n'; @@ -50,7 +37,6 @@ static bool ProcessXKeyEvent(XEvent * x_event, Jtk_Event * event) { event->key.key = buffer; } - event->key.mods = mods; } else { @@ -166,6 +152,21 @@ static bool ProcessXKeyEvent(XEvent * x_event, Jtk_Event * event) return false; } } + + /* OR in the modifier states */ + if (x_event->xkey.state & ShiftMask) + { + event->key.key |= JTK_KEY_MODS_SHIFT; + } + if (x_event->xkey.state & LockMask) + { + event->key.key |= JTK_KEY_MODS_LOCK; + } + if (x_event->xkey.state & ControlMask) + { + event->key.key |= JTK_KEY_MODS_CTRL; + } + return true; } diff --git a/src/gui/jtk/Jtk_event.h b/src/gui/jtk/Jtk_event.h index e889b43..d093226 100644 --- a/src/gui/jtk/Jtk_event.h +++ b/src/gui/jtk/Jtk_event.h @@ -15,7 +15,6 @@ typedef struct { uint32_t key; - uint8_t mods; } Jtk_KeyEvent; typedef struct diff --git a/src/gui/jtk/Jtk_keys.h b/src/gui/jtk/Jtk_keys.h index 3141d18..4902ce0 100644 --- a/src/gui/jtk/Jtk_keys.h +++ b/src/gui/jtk/Jtk_keys.h @@ -1,114 +1,118 @@ #ifndef JTK_KEYS_H #define JTK_KEYS_H -#define JTK_KEY_MODS_SHIFT 0x1u -#define JTK_KEY_MODS_LOCK 0x2u -#define JTK_KEY_MODS_CTRL 0x4u +#define JTK_KEY_MODS_MASK 0xFF000000u -#define JTK_KEY_F1 0xFF000001u -#define JTK_KEY_F2 0xFF000002u -#define JTK_KEY_F3 0xFF000003u -#define JTK_KEY_F4 0xFF000004u -#define JTK_KEY_F5 0xFF000005u -#define JTK_KEY_F6 0xFF000006u -#define JTK_KEY_F7 0xFF000007u -#define JTK_KEY_F8 0xFF000008u -#define JTK_KEY_F9 0xFF000009u -#define JTK_KEY_F10 0xFF00000Au -#define JTK_KEY_F11 0xFF00000Bu -#define JTK_KEY_F12 0xFF00000Cu -#define JTK_KEY_F13 0xFF00000Du -#define JTK_KEY_F14 0xFF00000Eu -#define JTK_KEY_F15 0xFF00000Fu -#define JTK_KEY_F16 0xFF000010u -#define JTK_KEY_F17 0xFF000011u -#define JTK_KEY_F18 0xFF000012u -#define JTK_KEY_F19 0xFF000013u -#define JTK_KEY_F20 0xFF000014u -#define JTK_KEY_F21 0xFF000015u -#define JTK_KEY_F22 0xFF000016u -#define JTK_KEY_F23 0xFF000017u -#define JTK_KEY_F24 0xFF000018u -#define JTK_KEY_F25 0xFF000019u -#define JTK_KEY_F26 0xFF00001Au -#define JTK_KEY_F27 0xFF00001Bu -#define JTK_KEY_F28 0xFF00001Cu -#define JTK_KEY_F29 0xFF00001Du -#define JTK_KEY_F30 0xFF00001Eu -#define JTK_KEY_F31 0xFF00001Fu +#define JTK_KEY_MODS_SHIFT 0x01000000u +#define JTK_KEY_MODS_LOCK 0x02000000u +#define JTK_KEY_MODS_CTRL 0x04000000u -#define JTK_KEY_SHIFT_L 0xFF000030u -#define JTK_KEY_SHIFT_R 0xFF000031u -#define JTK_KEY_CTRL_L 0xFF000032u -#define JTK_KEY_CTRL_R 0xFF000033u -#define JTK_KEY_CAPS_LOCK 0xFF000034u -#define JTK_KEY_SHIFT_LOCK 0xFF000035u +#define JTK_KEY_KEYCODE_MASK 0x00FFFFFFu -#define JTK_KEY_META_L 0xFF000036u -#define JTK_KEY_META_R 0xFF000037u -#define JTK_KEY_ALT_L 0xFF000038u -#define JTK_KEY_ALT_R 0xFF000039u -#define JTK_KEY_SUPER_L 0xFF00003Au -#define JTK_KEY_SUPER_R 0xFF00003Bu +#define JTK_KEY_F1 0x00FF0001u +#define JTK_KEY_F2 0x00FF0002u +#define JTK_KEY_F3 0x00FF0003u +#define JTK_KEY_F4 0x00FF0004u +#define JTK_KEY_F5 0x00FF0005u +#define JTK_KEY_F6 0x00FF0006u +#define JTK_KEY_F7 0x00FF0007u +#define JTK_KEY_F8 0x00FF0008u +#define JTK_KEY_F9 0x00FF0009u +#define JTK_KEY_F10 0x00FF000Au +#define JTK_KEY_F11 0x00FF000Bu +#define JTK_KEY_F12 0x00FF000Cu +#define JTK_KEY_F13 0x00FF000Du +#define JTK_KEY_F14 0x00FF000Eu +#define JTK_KEY_F15 0x00FF000Fu +#define JTK_KEY_F16 0x00FF0010u +#define JTK_KEY_F17 0x00FF0011u +#define JTK_KEY_F18 0x00FF0012u +#define JTK_KEY_F19 0x00FF0013u +#define JTK_KEY_F20 0x00FF0014u +#define JTK_KEY_F21 0x00FF0015u +#define JTK_KEY_F22 0x00FF0016u +#define JTK_KEY_F23 0x00FF0017u +#define JTK_KEY_F24 0x00FF0018u +#define JTK_KEY_F25 0x00FF0019u +#define JTK_KEY_F26 0x00FF001Au +#define JTK_KEY_F27 0x00FF001Bu +#define JTK_KEY_F28 0x00FF001Cu +#define JTK_KEY_F29 0x00FF001Du +#define JTK_KEY_F30 0x00FF001Eu +#define JTK_KEY_F31 0x00FF001Fu -#define JTK_KEY_HOME 0xFF00003Cu -#define JTK_KEY_LEFT 0xFF00003Du -#define JTK_KEY_UP 0xFF00003Eu -#define JTK_KEY_RIGHT 0xFF00003Fu -#define JTK_KEY_DOWN 0xFF000040u -#define JTK_KEY_PAGE_UP 0xFF000042u -#define JTK_KEY_PAGE_DOWN 0xFF000044u -#define JTK_KEY_END 0xFF000045u -#define JTK_KEY_BEGIN 0xFF000046u +#define JTK_KEY_SHIFT_L 0x00FF0030u +#define JTK_KEY_SHIFT_R 0x00FF0031u +#define JTK_KEY_CTRL_L 0x00FF0032u +#define JTK_KEY_CTRL_R 0x00FF0033u +#define JTK_KEY_CAPS_LOCK 0x00FF0034u +#define JTK_KEY_SHIFT_LOCK 0x00FF0035u -#define JTK_KEY_SELECT 0xFF000047u -#define JTK_KEY_PRINT 0xFF000048u -#define JTK_KEY_EXECUTE 0xFF000049u -#define JTK_KEY_INSERT 0xFF00004Au -#define JTK_KEY_UNDO 0xFF00004Bu -#define JTK_KEY_REDO 0xFF00004Cu -#define JTK_KEY_MENU 0xFF00004Du -#define JTK_KEY_FIND 0xFF00004Eu -#define JTK_KEY_CANCEL 0xFF00004Fu -#define JTK_KEY_HELP 0xFF000050u -#define JTK_KEY_BREAK 0xFF000051u -#define JTK_KEY_NUM_LOCK 0xFF000054u +#define JTK_KEY_META_L 0x00FF0036u +#define JTK_KEY_META_R 0x00FF0037u +#define JTK_KEY_ALT_L 0x00FF0038u +#define JTK_KEY_ALT_R 0x00FF0039u +#define JTK_KEY_SUPER_L 0x00FF003Au +#define JTK_KEY_SUPER_R 0x00FF003Bu -#define JTK_KEY_KP_SPACE 0xFF000055u -#define JTK_KEY_KP_TAB 0xFF000056u -#define JTK_KEY_KP_ENTER 0xFF000057u -#define JTK_KEY_KP_F1 0xFF000058u -#define JTK_KEY_KP_F2 0xFF000059u -#define JTK_KEY_KP_F3 0xFF00005Au -#define JTK_KEY_KP_F4 0xFF00005Bu -#define JTK_KEY_KP_HOME 0xFF00005Cu -#define JTK_KEY_KP_LEFT 0xFF00005Du -#define JTK_KEY_KP_UP 0xFF00005Eu -#define JTK_KEY_KP_RIGHT 0xFF00005Fu -#define JTK_KEY_KP_DOWN 0xFF000060u -#define JTK_KEY_KP_PAGE_UP 0xFF000062u -#define JTK_KEY_KP_PAGE_DOWN 0xFF000064u -#define JTK_KEY_KP_END 0xFF000065u -#define JTK_KEY_KP_BEGIN 0xFF000066u -#define JTK_KEY_KP_INSERT 0xFF000067u -#define JTK_KEY_KP_DELETE 0xFF000068u -#define JTK_KEY_KP_EQUAL 0xFF000069u -#define JTK_KEY_KP_MULTIPLY 0xFF00006Au -#define JTK_KEY_KP_ADD 0xFF00006Bu -#define JTK_KEY_KP_SEPARATOR 0xFF00006Cu -#define JTK_KEY_KP_SUBTRACT 0xFF00006Du -#define JTK_KEY_KP_DECIMAL 0xFF00006Eu -#define JTK_KEY_KP_DIVIDE 0xFF00006Fu +#define JTK_KEY_HOME 0x00FF003Cu +#define JTK_KEY_LEFT 0x00FF003Du +#define JTK_KEY_UP 0x00FF003Eu +#define JTK_KEY_RIGHT 0x00FF003Fu +#define JTK_KEY_DOWN 0x00FF0040u +#define JTK_KEY_PAGE_UP 0x00FF0042u +#define JTK_KEY_PAGE_DOWN 0x00FF0044u +#define JTK_KEY_END 0x00FF0045u +#define JTK_KEY_BEGIN 0x00FF0046u -#define JTK_KEY_KP_0 0xFF000070u -#define JTK_KEY_KP_1 0xFF000071u -#define JTK_KEY_KP_2 0xFF000072u -#define JTK_KEY_KP_3 0xFF000073u -#define JTK_KEY_KP_4 0xFF000074u -#define JTK_KEY_KP_5 0xFF000075u -#define JTK_KEY_KP_6 0xFF000076u -#define JTK_KEY_KP_7 0xFF000077u -#define JTK_KEY_KP_8 0xFF000078u -#define JTK_KEY_KP_9 0xFF000079u +#define JTK_KEY_SELECT 0x00FF0047u +#define JTK_KEY_PRINT 0x00FF0048u +#define JTK_KEY_EXECUTE 0x00FF0049u +#define JTK_KEY_INSERT 0x00FF004Au +#define JTK_KEY_UNDO 0x00FF004Bu +#define JTK_KEY_REDO 0x00FF004Cu +#define JTK_KEY_MENU 0x00FF004Du +#define JTK_KEY_FIND 0x00FF004Eu +#define JTK_KEY_CANCEL 0x00FF004Fu +#define JTK_KEY_HELP 0x00FF0050u +#define JTK_KEY_BREAK 0x00FF0051u +#define JTK_KEY_NUM_LOCK 0x00FF0054u + +#define JTK_KEY_KP_SPACE 0x00FF0055u +#define JTK_KEY_KP_TAB 0x00FF0056u +#define JTK_KEY_KP_ENTER 0x00FF0057u +#define JTK_KEY_KP_F1 0x00FF0058u +#define JTK_KEY_KP_F2 0x00FF0059u +#define JTK_KEY_KP_F3 0x00FF005Au +#define JTK_KEY_KP_F4 0x00FF005Bu +#define JTK_KEY_KP_HOME 0x00FF005Cu +#define JTK_KEY_KP_LEFT 0x00FF005Du +#define JTK_KEY_KP_UP 0x00FF005Eu +#define JTK_KEY_KP_RIGHT 0x00FF005Fu +#define JTK_KEY_KP_DOWN 0x00FF0060u +#define JTK_KEY_KP_PAGE_UP 0x00FF0062u +#define JTK_KEY_KP_PAGE_DOWN 0x00FF0064u +#define JTK_KEY_KP_END 0x00FF0065u +#define JTK_KEY_KP_BEGIN 0x00FF0066u +#define JTK_KEY_KP_INSERT 0x00FF0067u +#define JTK_KEY_KP_DELETE 0x00FF0068u +#define JTK_KEY_KP_EQUAL 0x00FF0069u +#define JTK_KEY_KP_MULTIPLY 0x00FF006Au +#define JTK_KEY_KP_ADD 0x00FF006Bu +#define JTK_KEY_KP_SEPARATOR 0x00FF006Cu +#define JTK_KEY_KP_SUBTRACT 0x00FF006Du +#define JTK_KEY_KP_DECIMAL 0x00FF006Eu +#define JTK_KEY_KP_DIVIDE 0x00FF006Fu + +#define JTK_KEY_KP_0 0x00FF0070u +#define JTK_KEY_KP_1 0x00FF0071u +#define JTK_KEY_KP_2 0x00FF0072u +#define JTK_KEY_KP_3 0x00FF0073u +#define JTK_KEY_KP_4 0x00FF0074u +#define JTK_KEY_KP_5 0x00FF0075u +#define JTK_KEY_KP_6 0x00FF0076u +#define JTK_KEY_KP_7 0x00FF0077u +#define JTK_KEY_KP_8 0x00FF0078u +#define JTK_KEY_KP_9 0x00FF0079u #endif From 6ff2faf4af8881a54b4e1f69e655d9f6d63b2835 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sun, 1 Oct 2017 17:46:30 -0400 Subject: [PATCH 14/30] 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. --- src/gui/Window.cc | 93 ++++++++++++++++++---------------------- src/gui/jtk/Jtk_event.cc | 2 + src/gui/jtk/Jtk_event.h | 2 + src/gui/jtk/Jtk_timer.cc | 20 ++++++++- src/gui/jtk/Jtk_timer.h | 3 +- 5 files changed, 66 insertions(+), 54 deletions(-) diff --git a/src/gui/Window.cc b/src/gui/Window.cc index 6b0300e..4463824 100644 --- a/src/gui/Window.cc +++ b/src/gui/Window.cc @@ -5,20 +5,27 @@ #include #include "jes_icon-32x32.h" #include +#include #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 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) { diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc index 8bab1bd..899d0c0 100644 --- a/src/gui/jtk/Jtk_event.cc +++ b/src/gui/jtk/Jtk_event.cc @@ -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; } diff --git a/src/gui/jtk/Jtk_event.h b/src/gui/jtk/Jtk_event.h index d093226..89d6f05 100644 --- a/src/gui/jtk/Jtk_event.h +++ b/src/gui/jtk/Jtk_event.h @@ -25,6 +25,8 @@ typedef struct typedef struct { size_t timer_id; + void * user1; + void * user2; } Jtk_TimerEvent; typedef struct diff --git a/src/gui/jtk/Jtk_timer.cc b/src/gui/jtk/Jtk_timer.cc index 4f4f2ce..4be3a85 100644 --- a/src/gui/jtk/Jtk_timer.cc +++ b/src/gui/jtk/Jtk_timer.cc @@ -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; +} diff --git a/src/gui/jtk/Jtk_timer.h b/src/gui/jtk/Jtk_timer.h index ae6c93d..d3a4e6a 100644 --- a/src/gui/jtk/Jtk_timer.h +++ b/src/gui/jtk/Jtk_timer.h @@ -4,10 +4,11 @@ #include #include -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 From 4e3050dbecd8cc2adcdaec1d9a4b4b1b4c1474df Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 5 Oct 2017 20:10:59 -0400 Subject: [PATCH 15/30] Handle key repeats in Jtk itself --- src/gui/Window.cc | 58 +------ src/gui/jtk/Jtk_event.cc | 336 +++++++++++++++++++++++---------------- src/gui/jtk/Jtk_event.h | 5 + src/gui/jtk/Jtk_keys.h | 2 + 4 files changed, 215 insertions(+), 186 deletions(-) diff --git a/src/gui/Window.cc b/src/gui/Window.cc index 4463824..d301f0b 100644 --- a/src/gui/Window.cc +++ b/src/gui/Window.cc @@ -11,22 +11,6 @@ #define INITIAL_HEIGHT 800 #define FONT_SIZE 16 -#define TIMER_TYPE_KEY_REPEAT 1u - -struct KeyStatus -{ - size_t timer_id; - uint32_t keyval; - bool pressed; - bool event_pending; - - KeyStatus() - { - pressed = false; - } -}; -std::unordered_map g_key_statuses; - /** * Initialize OpenGL. * @@ -139,6 +123,8 @@ bool Window::create(std::shared_ptr buffer) resize(); + m_redraw_requested = true; + return true; } @@ -153,13 +139,13 @@ void Window::run_event_loop() while (!m_exit_requested) { - Jtk_WaitEvent(&event); - handle_event(event); if (m_redraw_requested) { m_redraw_requested = false; redraw(); } + Jtk_WaitEvent(&event); + handle_event(event); } } @@ -177,46 +163,18 @@ void Window::handle_event(Jtk_Event & event) #endif case JTK_EVENT_KEY_PRESS: + if (!event.key.repeat) { - 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); - } - break; - - case JTK_EVENT_KEY_RELEASE: - { - KeyStatus & key_status = g_key_statuses[event.key.key]; - if (key_status.pressed) - { - Jtk_RemoveTimer(key_status.timer_id); - key_status.pressed = false; - } + Jtk_BeginKeyRepeat(&event.key, 300u, 25u); } + handle_keypress(event.key.key); + m_redraw_requested = true; 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) diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc index 899d0c0..cb1231e 100644 --- a/src/gui/jtk/Jtk_event.cc +++ b/src/gui/jtk/Jtk_event.cc @@ -7,167 +7,179 @@ #include #include #include "Jtk_internal.h" +#include /** Do not wait longer than 100ms */ #define MAX_WAIT_TIME 100000u -/** - * Process an X keyboard event. - * - * @param x_event - * Pointer to the X event. - * @param event - * Pointer to the Jtk event. - */ -static bool ProcessXKeyEvent(XEvent * x_event, Jtk_Event * event) +/** Hold a copy of the last-seen keyboard modifier state. */ +static unsigned int g_x_state; +static std::unordered_map g_repeating_keys; +static std::unordered_map g_key_repeat_timers; + +static void StopKeyRepeat(unsigned int x_keycode) { + auto it = g_repeating_keys.find(x_keycode); + if (it != g_repeating_keys.end()) + { + size_t timer_id = it->second; + Jtk_RemoveTimer(timer_id); + g_repeating_keys.erase(x_keycode); + g_key_repeat_timers.erase(timer_id); + } +} + +static uint32_t XKeyToJtkKey(unsigned int x_keycode) +{ + XKeyEvent x_key_event; + x_key_event.type = KeyPress; + x_key_event.display = g_display; + /* Turn off the ControlMask bit for looking up keys. We'll handle control + * keys ourselves. */ + x_key_event.state = g_x_state & ~ControlMask; + x_key_event.keycode = x_keycode; char buffer; KeySym keysym; - /* Make a copy of x_event and turn off the ControlMask bit for lookup - * up keycodes. We'll handle control keys ourselves. */ - XEvent x_event_for_key_lookup = *x_event; - x_event_for_key_lookup.xkey.state &= ~ControlMask; - if (XLookupString(&x_event_for_key_lookup.xkey, &buffer, 1, &keysym, nullptr) > 0) + uint32_t key = JTK_KEY_UNKNOWN; + + if (XLookupString(&x_key_event, &buffer, 1, &keysym, nullptr) > 0) { if (buffer == '\r') { - event->key.key = '\n'; + key = '\n'; } else { - event->key.key = buffer; + key = buffer; } } else { switch (keysym) { - case XK_F1: event->key.key = JTK_KEY_F1; break; - case XK_F2: event->key.key = JTK_KEY_F2; break; - case XK_F3: event->key.key = JTK_KEY_F3; break; - case XK_F4: event->key.key = JTK_KEY_F4; break; - case XK_F5: event->key.key = JTK_KEY_F5; break; - case XK_F6: event->key.key = JTK_KEY_F6; break; - case XK_F7: event->key.key = JTK_KEY_F7; break; - case XK_F8: event->key.key = JTK_KEY_F8; break; - case XK_F9: event->key.key = JTK_KEY_F9; break; - case XK_F10: event->key.key = JTK_KEY_F10; break; - case XK_F11: event->key.key = JTK_KEY_F11; break; - case XK_F12: event->key.key = JTK_KEY_F12; break; - case XK_F13: event->key.key = JTK_KEY_F13; break; - case XK_F14: event->key.key = JTK_KEY_F14; break; - case XK_F15: event->key.key = JTK_KEY_F15; break; - case XK_F16: event->key.key = JTK_KEY_F16; break; - case XK_F17: event->key.key = JTK_KEY_F17; break; - case XK_F18: event->key.key = JTK_KEY_F18; break; - case XK_F19: event->key.key = JTK_KEY_F19; break; - case XK_F20: event->key.key = JTK_KEY_F20; break; - case XK_F21: event->key.key = JTK_KEY_F21; break; - case XK_F22: event->key.key = JTK_KEY_F22; break; - case XK_F23: event->key.key = JTK_KEY_F23; break; - case XK_F24: event->key.key = JTK_KEY_F24; break; - case XK_F25: event->key.key = JTK_KEY_F25; break; - case XK_F26: event->key.key = JTK_KEY_F26; break; - case XK_F27: event->key.key = JTK_KEY_F27; break; - case XK_F28: event->key.key = JTK_KEY_F28; break; - case XK_F29: event->key.key = JTK_KEY_F29; break; - case XK_F30: event->key.key = JTK_KEY_F30; break; - case XK_F31: event->key.key = JTK_KEY_F31; break; + case XK_F1: key = JTK_KEY_F1; break; + case XK_F2: key = JTK_KEY_F2; break; + case XK_F3: key = JTK_KEY_F3; break; + case XK_F4: key = JTK_KEY_F4; break; + case XK_F5: key = JTK_KEY_F5; break; + case XK_F6: key = JTK_KEY_F6; break; + case XK_F7: key = JTK_KEY_F7; break; + case XK_F8: key = JTK_KEY_F8; break; + case XK_F9: key = JTK_KEY_F9; break; + case XK_F10: key = JTK_KEY_F10; break; + case XK_F11: key = JTK_KEY_F11; break; + case XK_F12: key = JTK_KEY_F12; break; + case XK_F13: key = JTK_KEY_F13; break; + case XK_F14: key = JTK_KEY_F14; break; + case XK_F15: key = JTK_KEY_F15; break; + case XK_F16: key = JTK_KEY_F16; break; + case XK_F17: key = JTK_KEY_F17; break; + case XK_F18: key = JTK_KEY_F18; break; + case XK_F19: key = JTK_KEY_F19; break; + case XK_F20: key = JTK_KEY_F20; break; + case XK_F21: key = JTK_KEY_F21; break; + case XK_F22: key = JTK_KEY_F22; break; + case XK_F23: key = JTK_KEY_F23; break; + case XK_F24: key = JTK_KEY_F24; break; + case XK_F25: key = JTK_KEY_F25; break; + case XK_F26: key = JTK_KEY_F26; break; + case XK_F27: key = JTK_KEY_F27; break; + case XK_F28: key = JTK_KEY_F28; break; + case XK_F29: key = JTK_KEY_F29; break; + case XK_F30: key = JTK_KEY_F30; break; + case XK_F31: key = JTK_KEY_F31; break; - case XK_Shift_L: event->key.key = JTK_KEY_SHIFT_L; break; - case XK_Shift_R: event->key.key = JTK_KEY_SHIFT_R; break; - case XK_Control_L: event->key.key = JTK_KEY_CTRL_L; break; - case XK_Control_R: event->key.key = JTK_KEY_CTRL_R; break; - case XK_Caps_Lock: event->key.key = JTK_KEY_CAPS_LOCK; break; - case XK_Shift_Lock: event->key.key = JTK_KEY_SHIFT_LOCK;break; + case XK_Shift_L: key = JTK_KEY_SHIFT_L; break; + case XK_Shift_R: key = JTK_KEY_SHIFT_R; break; + case XK_Control_L: key = JTK_KEY_CTRL_L; break; + case XK_Control_R: key = JTK_KEY_CTRL_R; break; + case XK_Caps_Lock: key = JTK_KEY_CAPS_LOCK; break; + case XK_Shift_Lock: key = JTK_KEY_SHIFT_LOCK;break; - case XK_Meta_L: event->key.key = JTK_KEY_META_L; break; - case XK_Meta_R: event->key.key = JTK_KEY_META_R; break; - case XK_Alt_L: event->key.key = JTK_KEY_ALT_L; break; - case XK_Alt_R: event->key.key = JTK_KEY_ALT_R; break; - case XK_Super_L: event->key.key = JTK_KEY_SUPER_L; break; - case XK_Super_R: event->key.key = JTK_KEY_SUPER_R; break; + case XK_Meta_L: key = JTK_KEY_META_L; break; + case XK_Meta_R: key = JTK_KEY_META_R; break; + case XK_Alt_L: key = JTK_KEY_ALT_L; break; + case XK_Alt_R: key = JTK_KEY_ALT_R; break; + case XK_Super_L: key = JTK_KEY_SUPER_L; break; + case XK_Super_R: key = JTK_KEY_SUPER_R; break; - case XK_Home: event->key.key = JTK_KEY_HOME; break; - case XK_Left: event->key.key = JTK_KEY_LEFT; break; - case XK_Up: event->key.key = JTK_KEY_UP; break; - case XK_Right: event->key.key = JTK_KEY_RIGHT; break; - case XK_Down: event->key.key = JTK_KEY_DOWN; break; - case XK_Page_Up: event->key.key = JTK_KEY_PAGE_UP; break; - case XK_Page_Down: event->key.key = JTK_KEY_PAGE_DOWN; break; - case XK_End: event->key.key = JTK_KEY_END; break; - case XK_Begin: event->key.key = JTK_KEY_BEGIN; break; + case XK_Home: key = JTK_KEY_HOME; break; + case XK_Left: key = JTK_KEY_LEFT; break; + case XK_Up: key = JTK_KEY_UP; break; + case XK_Right: key = JTK_KEY_RIGHT; break; + case XK_Down: key = JTK_KEY_DOWN; break; + case XK_Page_Up: key = JTK_KEY_PAGE_UP; break; + case XK_Page_Down: key = JTK_KEY_PAGE_DOWN; break; + case XK_End: key = JTK_KEY_END; break; + case XK_Begin: key = JTK_KEY_BEGIN; break; - case XK_Select: event->key.key = JTK_KEY_SELECT; break; - case XK_Print: event->key.key = JTK_KEY_PRINT; break; - case XK_Execute: event->key.key = JTK_KEY_EXECUTE; break; - case XK_Insert: event->key.key = JTK_KEY_INSERT; break; - case XK_Undo: event->key.key = JTK_KEY_UNDO; break; - case XK_Redo: event->key.key = JTK_KEY_REDO; break; - case XK_Menu: event->key.key = JTK_KEY_MENU; break; - case XK_Find: event->key.key = JTK_KEY_FIND; break; - case XK_Cancel: event->key.key = JTK_KEY_CANCEL; break; - case XK_Help: event->key.key = JTK_KEY_HELP; break; - case XK_Break: event->key.key = JTK_KEY_BREAK; break; - case XK_Num_Lock: event->key.key = JTK_KEY_NUM_LOCK; break; + case XK_Select: key = JTK_KEY_SELECT; break; + case XK_Print: key = JTK_KEY_PRINT; break; + case XK_Execute: key = JTK_KEY_EXECUTE; break; + case XK_Insert: key = JTK_KEY_INSERT; break; + case XK_Undo: key = JTK_KEY_UNDO; break; + case XK_Redo: key = JTK_KEY_REDO; break; + case XK_Menu: key = JTK_KEY_MENU; break; + case XK_Find: key = JTK_KEY_FIND; break; + case XK_Cancel: key = JTK_KEY_CANCEL; break; + case XK_Help: key = JTK_KEY_HELP; break; + case XK_Break: key = JTK_KEY_BREAK; break; + case XK_Num_Lock: key = JTK_KEY_NUM_LOCK; break; - case XK_KP_Space: event->key.key = JTK_KEY_KP_SPACE; break; - case XK_KP_Tab: event->key.key = JTK_KEY_KP_TAB; break; - case XK_KP_Enter: event->key.key = JTK_KEY_KP_ENTER; break; - case XK_KP_F1: event->key.key = JTK_KEY_KP_F1; break; - case XK_KP_F2: event->key.key = JTK_KEY_KP_F2; break; - case XK_KP_F3: event->key.key = JTK_KEY_KP_F3; break; - case XK_KP_F4: event->key.key = JTK_KEY_KP_F4; break; - case XK_KP_Home: event->key.key = JTK_KEY_KP_HOME; break; - case XK_KP_Left: event->key.key = JTK_KEY_KP_LEFT; break; - case XK_KP_Up: event->key.key = JTK_KEY_KP_UP; break; - case XK_KP_Right: event->key.key = JTK_KEY_KP_RIGHT; break; - case XK_KP_Down: event->key.key = JTK_KEY_KP_DOWN; break; - case XK_KP_Page_Up: event->key.key = JTK_KEY_KP_PAGE_UP; break; - case XK_KP_Page_Down: event->key.key = JTK_KEY_KP_PAGE_DOWN; break; - case XK_KP_End: event->key.key = JTK_KEY_KP_END; break; - case XK_KP_Begin: event->key.key = JTK_KEY_KP_BEGIN; break; - case XK_KP_Insert: event->key.key = JTK_KEY_KP_INSERT; break; - case XK_KP_Delete: event->key.key = JTK_KEY_KP_DELETE; break; - case XK_KP_Equal: event->key.key = JTK_KEY_KP_EQUAL; break; - case XK_KP_Multiply: event->key.key = JTK_KEY_KP_MULTIPLY; break; - case XK_KP_Add: event->key.key = JTK_KEY_KP_ADD; break; - case XK_KP_Separator: event->key.key = JTK_KEY_KP_SEPARATOR; break; - case XK_KP_Subtract: event->key.key = JTK_KEY_KP_SUBTRACT; break; - case XK_KP_Decimal: event->key.key = JTK_KEY_KP_DECIMAL; break; - case XK_KP_Divide: event->key.key = JTK_KEY_KP_DIVIDE; break; + case XK_KP_Space: key = JTK_KEY_KP_SPACE; break; + case XK_KP_Tab: key = JTK_KEY_KP_TAB; break; + case XK_KP_Enter: key = JTK_KEY_KP_ENTER; break; + case XK_KP_F1: key = JTK_KEY_KP_F1; break; + case XK_KP_F2: key = JTK_KEY_KP_F2; break; + case XK_KP_F3: key = JTK_KEY_KP_F3; break; + case XK_KP_F4: key = JTK_KEY_KP_F4; break; + case XK_KP_Home: key = JTK_KEY_KP_HOME; break; + case XK_KP_Left: key = JTK_KEY_KP_LEFT; break; + case XK_KP_Up: key = JTK_KEY_KP_UP; break; + case XK_KP_Right: key = JTK_KEY_KP_RIGHT; break; + case XK_KP_Down: key = JTK_KEY_KP_DOWN; break; + case XK_KP_Page_Up: key = JTK_KEY_KP_PAGE_UP; break; + case XK_KP_Page_Down: key = JTK_KEY_KP_PAGE_DOWN; break; + case XK_KP_End: key = JTK_KEY_KP_END; break; + case XK_KP_Begin: key = JTK_KEY_KP_BEGIN; break; + case XK_KP_Insert: key = JTK_KEY_KP_INSERT; break; + case XK_KP_Delete: key = JTK_KEY_KP_DELETE; break; + case XK_KP_Equal: key = JTK_KEY_KP_EQUAL; break; + case XK_KP_Multiply: key = JTK_KEY_KP_MULTIPLY; break; + case XK_KP_Add: key = JTK_KEY_KP_ADD; break; + case XK_KP_Separator: key = JTK_KEY_KP_SEPARATOR; break; + case XK_KP_Subtract: key = JTK_KEY_KP_SUBTRACT; break; + case XK_KP_Decimal: key = JTK_KEY_KP_DECIMAL; break; + case XK_KP_Divide: key = JTK_KEY_KP_DIVIDE; break; - case XK_KP_0: event->key.key = JTK_KEY_KP_0; break; - case XK_KP_1: event->key.key = JTK_KEY_KP_1; break; - case XK_KP_2: event->key.key = JTK_KEY_KP_2; break; - case XK_KP_3: event->key.key = JTK_KEY_KP_3; break; - case XK_KP_4: event->key.key = JTK_KEY_KP_4; break; - case XK_KP_5: event->key.key = JTK_KEY_KP_5; break; - case XK_KP_6: event->key.key = JTK_KEY_KP_6; break; - case XK_KP_7: event->key.key = JTK_KEY_KP_7; break; - case XK_KP_8: event->key.key = JTK_KEY_KP_8; break; - case XK_KP_9: event->key.key = JTK_KEY_KP_9; break; - - default: - return false; + case XK_KP_0: key = JTK_KEY_KP_0; break; + case XK_KP_1: key = JTK_KEY_KP_1; break; + case XK_KP_2: key = JTK_KEY_KP_2; break; + case XK_KP_3: key = JTK_KEY_KP_3; break; + case XK_KP_4: key = JTK_KEY_KP_4; break; + case XK_KP_5: key = JTK_KEY_KP_5; break; + case XK_KP_6: key = JTK_KEY_KP_6; break; + case XK_KP_7: key = JTK_KEY_KP_7; break; + case XK_KP_8: key = JTK_KEY_KP_8; break; + case XK_KP_9: key = JTK_KEY_KP_9; break; } } /* OR in the modifier states */ - if (x_event->xkey.state & ShiftMask) + if (g_x_state & ShiftMask) { - event->key.key |= JTK_KEY_MODS_SHIFT; + key |= JTK_KEY_MODS_SHIFT; } - if (x_event->xkey.state & LockMask) + if (g_x_state & LockMask) { - event->key.key |= JTK_KEY_MODS_LOCK; + key |= JTK_KEY_MODS_LOCK; } - if (x_event->xkey.state & ControlMask) + if (g_x_state & ControlMask) { - event->key.key |= JTK_KEY_MODS_CTRL; + key |= JTK_KEY_MODS_CTRL; } - return true; + return key; } static Bool KeyRepeatCheckIfEvent(Display * display, XEvent * chkev, @@ -198,6 +210,44 @@ static bool IsRepeatKey(Display * display, XEvent * event) return false; } +/** + * Process an X key press event. + * + * @param x_event + * Pointer to the X event. + * @param event + * Pointer to the Jtk event. + */ +static bool ProcessXKeyPressEvent(XEvent * x_event, Jtk_Event * event) +{ + unsigned int x_keycode = x_event->xkey.keycode; + g_x_state = x_event->xkey.state; + event->type = JTK_EVENT_KEY_PRESS; + event->key.repeat = false; + event->key.key = XKeyToJtkKey(x_keycode); + event->key.x_keycode = x_keycode; + return true; +} + +/** + * Process an X key release event. + * + * @param x_event + * Pointer to the X event. + * @param event + * Pointer to the Jtk event. + */ +static bool ProcessXKeyReleaseEvent(XEvent * x_event, Jtk_Event * event) +{ + if (IsRepeatKey(g_display, x_event)) + { + return false; + } + g_x_state = x_event->xkey.state; + StopKeyRepeat(x_event->xkey.keycode); + return false; +} + /** * Process an X event. * @@ -216,15 +266,10 @@ static bool ProcessXEvent(XEvent * x_event, Jtk_Event * event) switch (x_event->type) { case KeyPress: - event->type = JTK_EVENT_KEY_PRESS; - return ProcessXKeyEvent(x_event, event); + return ProcessXKeyPressEvent(x_event, event); case KeyRelease: - if (IsRepeatKey(g_display, x_event)) { - return false; - } - event->type = JTK_EVENT_KEY_RELEASE; - return ProcessXKeyEvent(x_event, event); + return ProcessXKeyReleaseEvent(x_event, event); case ButtonPress: break; @@ -251,10 +296,21 @@ void Jtk_WaitEvent(Jtk_Event * event) size_t timer_id = Jtk_GetExpiredTimer(); if (timer_id != (size_t)-1) { - 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); + auto it = g_key_repeat_timers.find(timer_id); + if (it != g_key_repeat_timers.end()) + { + event->type = JTK_EVENT_KEY_PRESS; + event->key.repeat = true; + event->key.key = XKeyToJtkKey(it->second); + event->key.x_keycode = it->second; + } + else + { + 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; } @@ -286,4 +342,12 @@ void Jtk_WaitEvent(Jtk_Event * event) } } +void Jtk_BeginKeyRepeat(Jtk_KeyEvent * key_event, uint32_t delay, uint32_t interval) +{ + StopKeyRepeat(key_event->x_keycode); + size_t timer_id = Jtk_AddTimer(delay, interval, nullptr, nullptr); + g_repeating_keys[key_event->x_keycode] = timer_id; + g_key_repeat_timers[timer_id] = key_event->x_keycode; +} + #endif diff --git a/src/gui/jtk/Jtk_event.h b/src/gui/jtk/Jtk_event.h index 89d6f05..06aac1d 100644 --- a/src/gui/jtk/Jtk_event.h +++ b/src/gui/jtk/Jtk_event.h @@ -14,7 +14,11 @@ typedef struct { + bool repeat; uint32_t key; +#ifdef JTK_X + unsigned int x_keycode; +#endif } Jtk_KeyEvent; typedef struct @@ -41,5 +45,6 @@ typedef struct } Jtk_Event; void Jtk_WaitEvent(Jtk_Event * event); +void Jtk_BeginKeyRepeat(Jtk_KeyEvent * key_event, uint32_t delay, uint32_t interval); #endif diff --git a/src/gui/jtk/Jtk_keys.h b/src/gui/jtk/Jtk_keys.h index 4902ce0..4f1eaeb 100644 --- a/src/gui/jtk/Jtk_keys.h +++ b/src/gui/jtk/Jtk_keys.h @@ -115,4 +115,6 @@ #define JTK_KEY_KP_8 0x00FF0078u #define JTK_KEY_KP_9 0x00FF0079u +#define JTK_KEY_UNKNOWN 0x00FFFFFFu + #endif From 07cdc5f8d08aca9f1e5d4ad01d60d9e3703d3f76 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 5 Oct 2017 20:16:46 -0400 Subject: [PATCH 16/30] Query for X modifier state when needed --- src/gui/jtk/Jtk_event.cc | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc index cb1231e..bf8ac3d 100644 --- a/src/gui/jtk/Jtk_event.cc +++ b/src/gui/jtk/Jtk_event.cc @@ -12,8 +12,6 @@ /** Do not wait longer than 100ms */ #define MAX_WAIT_TIME 100000u -/** Hold a copy of the last-seen keyboard modifier state. */ -static unsigned int g_x_state; static std::unordered_map g_repeating_keys; static std::unordered_map g_key_repeat_timers; @@ -29,6 +27,15 @@ static void StopKeyRepeat(unsigned int x_keycode) } } +static unsigned int GetXState() +{ + Window win; + int i; + unsigned int state; + XQueryPointer(g_display, RootWindow(g_display, DefaultScreen(g_display)), &win, &win, &i, &i, &i, &i, &state); + return state; +} + static uint32_t XKeyToJtkKey(unsigned int x_keycode) { XKeyEvent x_key_event; @@ -36,7 +43,8 @@ static uint32_t XKeyToJtkKey(unsigned int x_keycode) x_key_event.display = g_display; /* Turn off the ControlMask bit for looking up keys. We'll handle control * keys ourselves. */ - x_key_event.state = g_x_state & ~ControlMask; + unsigned int x_state = GetXState(); + x_key_event.state = x_state & ~ControlMask; x_key_event.keycode = x_keycode; char buffer; KeySym keysym; @@ -166,15 +174,15 @@ static uint32_t XKeyToJtkKey(unsigned int x_keycode) } /* OR in the modifier states */ - if (g_x_state & ShiftMask) + if (x_state & ShiftMask) { key |= JTK_KEY_MODS_SHIFT; } - if (g_x_state & LockMask) + if (x_state & LockMask) { key |= JTK_KEY_MODS_LOCK; } - if (g_x_state & ControlMask) + if (x_state & ControlMask) { key |= JTK_KEY_MODS_CTRL; } @@ -221,7 +229,6 @@ static bool IsRepeatKey(Display * display, XEvent * event) static bool ProcessXKeyPressEvent(XEvent * x_event, Jtk_Event * event) { unsigned int x_keycode = x_event->xkey.keycode; - g_x_state = x_event->xkey.state; event->type = JTK_EVENT_KEY_PRESS; event->key.repeat = false; event->key.key = XKeyToJtkKey(x_keycode); @@ -243,7 +250,6 @@ static bool ProcessXKeyReleaseEvent(XEvent * x_event, Jtk_Event * event) { return false; } - g_x_state = x_event->xkey.state; StopKeyRepeat(x_event->xkey.keycode); return false; } From 6eeb0d5b9aa5cf2d979017425c6724731a0846e5 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 12 Oct 2017 19:59:46 -0400 Subject: [PATCH 17/30] Process X events before timers --- src/gui/jtk/Jtk_event.cc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc index bf8ac3d..db8d9a5 100644 --- a/src/gui/jtk/Jtk_event.cc +++ b/src/gui/jtk/Jtk_event.cc @@ -298,7 +298,16 @@ void Jtk_WaitEvent(Jtk_Event * event) { for (;;) { - /* First check if any timer has expired. */ + /* First check for an X event. */ + while (XPending(g_display) > 0) + { + XEvent x_event; + XNextEvent(g_display, &x_event); + if (ProcessXEvent(&x_event, event)) + return; + } + + /* Next check if any timer has expired. */ size_t timer_id = Jtk_GetExpiredTimer(); if (timer_id != (size_t)-1) { @@ -321,15 +330,6 @@ void Jtk_WaitEvent(Jtk_Event * event) return; } - /* Next check for an X event. */ - while (XPending(g_display) > 0) - { - XEvent x_event; - XNextEvent(g_display, &x_event); - if (ProcessXEvent(&x_event, event)) - return; - } - /* Finally, wait for something to happen. */ uint64_t time_to_wait = Jtk_TimeToNextTimerExpiration(); if (time_to_wait > MAX_WAIT_TIME) From de31e975565efa62421209fd96f2c49df01cb019 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 12 Oct 2017 20:44:16 -0400 Subject: [PATCH 18/30] turn off custom key repeats and just use X key repeats --- src/gui/Window.cc | 2 ++ src/gui/jtk/Jtk_event.cc | 8 ++++++++ src/gui/jtk/Jtk_event.h | 2 ++ 3 files changed, 12 insertions(+) diff --git a/src/gui/Window.cc b/src/gui/Window.cc index d301f0b..3778fc0 100644 --- a/src/gui/Window.cc +++ b/src/gui/Window.cc @@ -163,10 +163,12 @@ void Window::handle_event(Jtk_Event & event) #endif case JTK_EVENT_KEY_PRESS: +#if 0 if (!event.key.repeat) { Jtk_BeginKeyRepeat(&event.key, 300u, 25u); } +#endif handle_keypress(event.key.key); m_redraw_requested = true; break; diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc index db8d9a5..1cc9394 100644 --- a/src/gui/jtk/Jtk_event.cc +++ b/src/gui/jtk/Jtk_event.cc @@ -15,6 +15,7 @@ static std::unordered_map g_repeating_keys; static std::unordered_map g_key_repeat_timers; +#if 0 static void StopKeyRepeat(unsigned int x_keycode) { auto it = g_repeating_keys.find(x_keycode); @@ -26,6 +27,7 @@ static void StopKeyRepeat(unsigned int x_keycode) g_key_repeat_timers.erase(timer_id); } } +#endif static unsigned int GetXState() { @@ -190,6 +192,7 @@ static uint32_t XKeyToJtkKey(unsigned int x_keycode) return key; } +#if 0 static Bool KeyRepeatCheckIfEvent(Display * display, XEvent * chkev, XPointer arg) { @@ -217,6 +220,7 @@ static bool IsRepeatKey(Display * display, XEvent * event) } return false; } +#endif /** * Process an X key press event. @@ -246,11 +250,13 @@ static bool ProcessXKeyPressEvent(XEvent * x_event, Jtk_Event * event) */ static bool ProcessXKeyReleaseEvent(XEvent * x_event, Jtk_Event * event) { +#if 0 if (IsRepeatKey(g_display, x_event)) { return false; } StopKeyRepeat(x_event->xkey.keycode); +#endif return false; } @@ -348,6 +354,7 @@ void Jtk_WaitEvent(Jtk_Event * event) } } +#if 0 void Jtk_BeginKeyRepeat(Jtk_KeyEvent * key_event, uint32_t delay, uint32_t interval) { StopKeyRepeat(key_event->x_keycode); @@ -355,5 +362,6 @@ void Jtk_BeginKeyRepeat(Jtk_KeyEvent * key_event, uint32_t delay, uint32_t inter g_repeating_keys[key_event->x_keycode] = timer_id; g_key_repeat_timers[timer_id] = key_event->x_keycode; } +#endif #endif diff --git a/src/gui/jtk/Jtk_event.h b/src/gui/jtk/Jtk_event.h index 06aac1d..27391b4 100644 --- a/src/gui/jtk/Jtk_event.h +++ b/src/gui/jtk/Jtk_event.h @@ -45,6 +45,8 @@ typedef struct } Jtk_Event; void Jtk_WaitEvent(Jtk_Event * event); +#if 0 void Jtk_BeginKeyRepeat(Jtk_KeyEvent * key_event, uint32_t delay, uint32_t interval); +#endif #endif From 5999d62660c051a9cbe46b0d206f60d0bc808114 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 12 Oct 2017 21:05:39 -0400 Subject: [PATCH 19/30] handle window resizes --- src/gui/Window.cc | 18 ++++++++++-------- src/gui/Window.h | 2 +- src/gui/jtk/Jtk_event.cc | 19 +++++++++++++++++++ src/gui/jtk/Jtk_event.h | 8 ++++++++ 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/gui/Window.cc b/src/gui/Window.cc index 3778fc0..9f59172 100644 --- a/src/gui/Window.cc +++ b/src/gui/Window.cc @@ -121,7 +121,7 @@ bool Window::create(std::shared_ptr buffer) m_command_buffer_pane->set_command_mode(); m_command_buffer_screen_rows = 1; - resize(); + resize(INITIAL_WIDTH, INITIAL_HEIGHT); m_redraw_requested = true; @@ -177,6 +177,11 @@ void Window::handle_event(Jtk_Event & event) m_redraw_requested = true; break; + case JTK_EVENT_WINDOW_RESIZE: + resize(event.resize.width, event.resize.height); + m_redraw_requested = true; + break; + #if 0 case SDL_WINDOWEVENT: switch (event.window.event) @@ -355,13 +360,10 @@ void Window::handle_keypress(uint32_t keyval) } } -void Window::resize() +void Window::resize(size_t width, size_t height) { - m_width = 800; - m_height = 800; -#if 0 - SDL_GetWindowSize(m_window, &m_width, &m_height); -#endif + m_width = width; + m_height = height; glViewport(0, 0, m_width, m_height); m_gl->resize(m_width, m_height); int command_buffer_height = m_command_buffer_screen_rows * m_font->get_line_height(); @@ -378,7 +380,7 @@ void Window::redraw() m_command_buffer_screen_rows = 1; if (m_command_buffer_screen_rows != last_command_buffer_screen_rows) { - resize(); + resize(m_width, m_height); } last_command_buffer_screen_rows = m_command_buffer_screen_rows; diff --git a/src/gui/Window.h b/src/gui/Window.h index ba7c0f1..5ae05bf 100644 --- a/src/gui/Window.h +++ b/src/gui/Window.h @@ -41,7 +41,7 @@ public: protected: - void resize(); + void resize(size_t width, size_t height); void redraw(); void handle_event(Jtk_Event & event); void handle_keypress(uint32_t keyval); diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc index 1cc9394..ccd4530 100644 --- a/src/gui/jtk/Jtk_event.cc +++ b/src/gui/jtk/Jtk_event.cc @@ -260,6 +260,22 @@ static bool ProcessXKeyReleaseEvent(XEvent * x_event, Jtk_Event * event) return false; } +/** + * Process an X configure event. + * + * @param x_event + * Pointer to the X event. + * @param event + * Pointer to the Jtk event. + */ +static bool ProcessConfigureEvent(XEvent * x_event, Jtk_Event * event) +{ + event->type = JTK_EVENT_WINDOW_RESIZE; + event->resize.width = x_event->xconfigure.width; + event->resize.height = x_event->xconfigure.height; + return true; +} + /** * Process an X event. * @@ -292,6 +308,9 @@ static bool ProcessXEvent(XEvent * x_event, Jtk_Event * event) case Expose: break; + case ConfigureNotify: + return ProcessConfigureEvent(x_event, event); + case MappingNotify: XRefreshKeyboardMapping(&x_event->xmapping); return false; diff --git a/src/gui/jtk/Jtk_event.h b/src/gui/jtk/Jtk_event.h index 27391b4..9091306 100644 --- a/src/gui/jtk/Jtk_event.h +++ b/src/gui/jtk/Jtk_event.h @@ -11,6 +11,7 @@ #define JTK_EVENT_BUTTON_PRESS 5u #define JTK_EVENT_BUTTON_RELEASE 6u #define JTK_EVENT_TIMER 7u +#define JTK_EVENT_WINDOW_RESIZE 8u typedef struct { @@ -33,6 +34,12 @@ typedef struct void * user2; } Jtk_TimerEvent; +typedef struct +{ + size_t width; + size_t height; +} Jtk_WindowResizeEvent; + typedef struct { uint8_t type; @@ -41,6 +48,7 @@ typedef struct Jtk_KeyEvent key; Jtk_ButtonEvent button; Jtk_TimerEvent timer; + Jtk_WindowResizeEvent resize; }; } Jtk_Event; From 34dc95627244d80b9ac3e6ac55cbb5134d0001a4 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 12 Oct 2017 21:11:27 -0400 Subject: [PATCH 20/30] Use modifier state from X keypress event, not current state at time of event process --- src/gui/jtk/Jtk_event.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc index ccd4530..8d9fcdb 100644 --- a/src/gui/jtk/Jtk_event.cc +++ b/src/gui/jtk/Jtk_event.cc @@ -29,6 +29,7 @@ static void StopKeyRepeat(unsigned int x_keycode) } #endif +#if 0 static unsigned int GetXState() { Window win; @@ -37,15 +38,15 @@ static unsigned int GetXState() XQueryPointer(g_display, RootWindow(g_display, DefaultScreen(g_display)), &win, &win, &i, &i, &i, &i, &state); return state; } +#endif -static uint32_t XKeyToJtkKey(unsigned int x_keycode) +static uint32_t XKeyToJtkKey(unsigned int x_keycode, unsigned int x_state) { XKeyEvent x_key_event; x_key_event.type = KeyPress; x_key_event.display = g_display; /* Turn off the ControlMask bit for looking up keys. We'll handle control * keys ourselves. */ - unsigned int x_state = GetXState(); x_key_event.state = x_state & ~ControlMask; x_key_event.keycode = x_keycode; char buffer; @@ -235,7 +236,7 @@ static bool ProcessXKeyPressEvent(XEvent * x_event, Jtk_Event * event) unsigned int x_keycode = x_event->xkey.keycode; event->type = JTK_EVENT_KEY_PRESS; event->key.repeat = false; - event->key.key = XKeyToJtkKey(x_keycode); + event->key.key = XKeyToJtkKey(x_keycode, x_event->xkey.state); event->key.x_keycode = x_keycode; return true; } @@ -336,6 +337,7 @@ void Jtk_WaitEvent(Jtk_Event * event) size_t timer_id = Jtk_GetExpiredTimer(); if (timer_id != (size_t)-1) { +#if 0 auto it = g_key_repeat_timers.find(timer_id); if (it != g_key_repeat_timers.end()) { @@ -346,11 +348,14 @@ void Jtk_WaitEvent(Jtk_Event * event) } else { +#endif 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); +#if 0 } +#endif Jtk_ServiceTimer(timer_id); return; } From 3a594b5355ff916bc2aeaba595052e891f90efad Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sat, 14 Oct 2017 11:31:29 -0400 Subject: [PATCH 21/30] Avoid backlogging duplicate keypress events. --- src/gui/jtk/Jtk_event.cc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc index 8d9fcdb..7f0f85b 100644 --- a/src/gui/jtk/Jtk_event.cc +++ b/src/gui/jtk/Jtk_event.cc @@ -223,6 +223,15 @@ static bool IsRepeatKey(Display * display, XEvent * event) } #endif +static Bool MatchKeyPress(Display * display, XEvent * event, XPointer arg) +{ + XEvent * match_event = (XEvent *)arg; + return (event->type == match_event->type) && + (event->xkey.window == match_event->xkey.window) && + (event->xkey.state == match_event->xkey.state) && + (event->xkey.keycode == match_event->xkey.keycode); +} + /** * Process an X key press event. * @@ -238,6 +247,12 @@ static bool ProcessXKeyPressEvent(XEvent * x_event, Jtk_Event * event) event->key.repeat = false; event->key.key = XKeyToJtkKey(x_keycode, x_event->xkey.state); event->key.x_keycode = x_keycode; + /* Remove any following keypress events for the same keycode from the X + * queue. */ + XEvent remove_event; + while (XCheckIfEvent(g_display, &remove_event, MatchKeyPress, (XPointer)x_event) == True) + { + } return true; } From 49c34907f5cd5928680eb0f7af251ada800f7d1f Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sat, 14 Oct 2017 11:36:07 -0400 Subject: [PATCH 22/30] add Jtk_CheckEvent() --- src/gui/jtk/Jtk_event.cc | 78 ++++++++++++++++++++++------------------ src/gui/jtk/Jtk_event.h | 1 + 2 files changed, 44 insertions(+), 35 deletions(-) diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc index 7f0f85b..966069f 100644 --- a/src/gui/jtk/Jtk_event.cc +++ b/src/gui/jtk/Jtk_event.cc @@ -335,47 +335,55 @@ static bool ProcessXEvent(XEvent * x_event, Jtk_Event * event) return false; } +bool Jtk_CheckEvent(Jtk_Event * event) +{ + /* First check for an X event. */ + while (XPending(g_display) > 0) + { + XEvent x_event; + XNextEvent(g_display, &x_event); + if (ProcessXEvent(&x_event, event)) + return true; + } + + /* Next check if any timer has expired. */ + size_t timer_id = Jtk_GetExpiredTimer(); + if (timer_id != (size_t)-1) + { +#if 0 + auto it = g_key_repeat_timers.find(timer_id); + if (it != g_key_repeat_timers.end()) + { + event->type = JTK_EVENT_KEY_PRESS; + event->key.repeat = true; + event->key.key = XKeyToJtkKey(it->second); + event->key.x_keycode = it->second; + } + else + { +#endif + 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); +#if 0 + } +#endif + Jtk_ServiceTimer(timer_id); + return true; + } + + return false; +} + void Jtk_WaitEvent(Jtk_Event * event) { for (;;) { - /* First check for an X event. */ - while (XPending(g_display) > 0) - { - XEvent x_event; - XNextEvent(g_display, &x_event); - if (ProcessXEvent(&x_event, event)) - return; - } - - /* Next check if any timer has expired. */ - size_t timer_id = Jtk_GetExpiredTimer(); - if (timer_id != (size_t)-1) - { -#if 0 - auto it = g_key_repeat_timers.find(timer_id); - if (it != g_key_repeat_timers.end()) - { - event->type = JTK_EVENT_KEY_PRESS; - event->key.repeat = true; - event->key.key = XKeyToJtkKey(it->second); - event->key.x_keycode = it->second; - } - else - { -#endif - 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); -#if 0 - } -#endif - Jtk_ServiceTimer(timer_id); + if (Jtk_CheckEvent(event)) return; - } - /* Finally, wait for something to happen. */ + /* Wait for something to happen. */ uint64_t time_to_wait = Jtk_TimeToNextTimerExpiration(); if (time_to_wait > MAX_WAIT_TIME) { diff --git a/src/gui/jtk/Jtk_event.h b/src/gui/jtk/Jtk_event.h index 9091306..edd5f9c 100644 --- a/src/gui/jtk/Jtk_event.h +++ b/src/gui/jtk/Jtk_event.h @@ -52,6 +52,7 @@ typedef struct }; } Jtk_Event; +bool Jtk_CheckEvent(Jtk_Event * event); void Jtk_WaitEvent(Jtk_Event * event); #if 0 void Jtk_BeginKeyRepeat(Jtk_KeyEvent * key_event, uint32_t delay, uint32_t interval); From b100262a155138d194f5b35b58e89951238e38cc Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sat, 14 Oct 2017 11:42:03 -0400 Subject: [PATCH 23/30] process multiple queued events up to a maximum time before redrawing screen --- src/gui/Window.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/gui/Window.cc b/src/gui/Window.cc index 9f59172..003a664 100644 --- a/src/gui/Window.cc +++ b/src/gui/Window.cc @@ -11,6 +11,10 @@ #define INITIAL_HEIGHT 800 #define FONT_SIZE 16 +/* Process multiple queued events for up to this long before stopping to + * redraw the screen. */ +#define MAX_EVENT_PROCESS_TIME 50000 + /** * Initialize OpenGL. * @@ -145,7 +149,13 @@ void Window::run_event_loop() redraw(); } Jtk_WaitEvent(&event); + uint64_t event_time = Jtk_UsTime(); handle_event(event); + while (Jtk_CheckEvent(&event) && + ((Jtk_UsTime() - event_time) < MAX_EVENT_PROCESS_TIME)) + { + handle_event(event); + } } } From 5e40c33eda1fedb3ac53078041308c5548745ae7 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sat, 14 Oct 2017 11:48:25 -0400 Subject: [PATCH 24/30] handle X button press events --- src/gui/Window.cc | 8 ++++---- src/gui/jtk/Jtk_event.cc | 12 +++++++++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/gui/Window.cc b/src/gui/Window.cc index 003a664..f0aa2ac 100644 --- a/src/gui/Window.cc +++ b/src/gui/Window.cc @@ -205,18 +205,18 @@ void Window::handle_event(Jtk_Event & event) break; } break; +#endif - case SDL_MOUSEWHEEL: - if (event.wheel.y > 0) + case JTK_EVENT_BUTTON_PRESS: + if (event.button.button == 4) { m_focused_buffer_pane->scroll_window_up(ScrollMode::WHEEL); } - else + else if (event.button.button == 5) { m_focused_buffer_pane->scroll_window_down(ScrollMode::WHEEL); } break; -#endif } } diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc index 966069f..efd39e2 100644 --- a/src/gui/jtk/Jtk_event.cc +++ b/src/gui/jtk/Jtk_event.cc @@ -276,6 +276,16 @@ static bool ProcessXKeyReleaseEvent(XEvent * x_event, Jtk_Event * event) return false; } +/** + * Process an X button press event. + */ +static bool ProcessXButtonPressEvent(XEvent * x_event, Jtk_Event * event) +{ + event->type = JTK_EVENT_BUTTON_PRESS; + event->button.button = x_event->xbutton.button; + return true; +} + /** * Process an X configure event. * @@ -316,7 +326,7 @@ static bool ProcessXEvent(XEvent * x_event, Jtk_Event * event) return ProcessXKeyReleaseEvent(x_event, event); case ButtonPress: - break; + return ProcessXButtonPressEvent(x_event, event); case ButtonRelease: break; From c2323f4397630349feb0b6afc3b09bd38d196fcc Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sat, 14 Oct 2017 11:52:27 -0400 Subject: [PATCH 25/30] Do not queue up mouse wheel scroll events while others are still processing --- src/gui/jtk/Jtk_event.cc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc index efd39e2..5d390ea 100644 --- a/src/gui/jtk/Jtk_event.cc +++ b/src/gui/jtk/Jtk_event.cc @@ -276,6 +276,15 @@ static bool ProcessXKeyReleaseEvent(XEvent * x_event, Jtk_Event * event) return false; } +static Bool MatchButtonPress(Display * display, XEvent * event, XPointer arg) +{ + XEvent * match_event = (XEvent *)arg; + return (event->type == match_event->type) && + (event->xbutton.window == match_event->xbutton.window) && + (event->xbutton.state == match_event->xbutton.state) && + (event->xbutton.button == match_event->xbutton.button); +} + /** * Process an X button press event. */ @@ -283,6 +292,15 @@ static bool ProcessXButtonPressEvent(XEvent * x_event, Jtk_Event * event) { event->type = JTK_EVENT_BUTTON_PRESS; event->button.button = x_event->xbutton.button; + /* If this is a mouse wheel scroll event, remove any following scroll + * events. */ + if ((event->button.button == 4) || (event->button.button == 5)) + { + XEvent remove_event; + while (XCheckIfEvent(g_display, &remove_event, MatchButtonPress, (XPointer)x_event) == True) + { + } + } return true; } From 2d944e4a870726edf2c40b8fc74625bcf1256599 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sat, 14 Oct 2017 11:59:48 -0400 Subject: [PATCH 26/30] handle X Expose, GraphicsExpose, and MapNotify events --- src/gui/jtk/Jtk_event.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc index 5d390ea..ebc1ab8 100644 --- a/src/gui/jtk/Jtk_event.cc +++ b/src/gui/jtk/Jtk_event.cc @@ -350,7 +350,16 @@ static bool ProcessXEvent(XEvent * x_event, Jtk_Event * event) break; case Expose: - break; + event->type = JTK_EVENT_WINDOW_EXPOSE; + return true; + + case GraphicsExpose: + event->type = JTK_EVENT_WINDOW_EXPOSE; + return true; + + case MapNotify: + event->type = JTK_EVENT_WINDOW_EXPOSE; + return true; case ConfigureNotify: return ProcessConfigureEvent(x_event, event); From 314c840105de43decb25d11e236438ca1d082df8 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sat, 14 Oct 2017 12:16:16 -0400 Subject: [PATCH 27/30] add Jtk_SetWindowTitle() --- src/gui/Window.cc | 1 + src/gui/jtk/Jtk_window.cc | 11 +++++++++++ src/gui/jtk/Jtk_window.h | 1 + 3 files changed, 13 insertions(+) diff --git a/src/gui/Window.cc b/src/gui/Window.cc index f0aa2ac..b115607 100644 --- a/src/gui/Window.cc +++ b/src/gui/Window.cc @@ -83,6 +83,7 @@ bool Window::create(std::shared_ptr buffer) std::cerr << "Error creating window" << std::endl; return false; } + Jtk_SetWindowTitle(m_window, "jes"); #if 0 set_window_icon(); diff --git a/src/gui/jtk/Jtk_window.cc b/src/gui/jtk/Jtk_window.cc index b6b3dda..cf01a0a 100644 --- a/src/gui/jtk/Jtk_window.cc +++ b/src/gui/jtk/Jtk_window.cc @@ -6,6 +6,7 @@ #include #include "Jtk_internal.h" #include +#include static Bool WaitForNotify(Display * display, XEvent * event, XPointer arg) { @@ -41,4 +42,14 @@ void Jtk_CloseWindow(void * window) XDestroyWindow(g_display, (Window)window); } +void Jtk_SetWindowTitle(void * window, const char * title) +{ + XTextProperty title_property; + if (XStringListToTextProperty((char **)&title, 1, &title_property) != 0) + { + XSetTextProperty(g_display, (Window)window, &title_property, XA_WM_NAME); + XFree(title_property.value); + } +} + #endif diff --git a/src/gui/jtk/Jtk_window.h b/src/gui/jtk/Jtk_window.h index 1046c93..720c036 100644 --- a/src/gui/jtk/Jtk_window.h +++ b/src/gui/jtk/Jtk_window.h @@ -4,5 +4,6 @@ void * Jtk_CreateWindow(); void Jtk_SwapBuffers(void * window); void Jtk_CloseWindow(void * window); +void Jtk_SetWindowTitle(void * window, const char * title); #endif From 7199bb56e331e9a19bb9c72a9e96657c57e4230d Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sat, 14 Oct 2017 12:22:38 -0400 Subject: [PATCH 28/30] adjust cursor screen row when moving cursor up/down by screen rows --- src/core/BufferView.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/BufferView.cc b/src/core/BufferView.cc index e7cceae..ee341c0 100644 --- a/src/core/BufferView.cc +++ b/src/core/BufferView.cc @@ -170,6 +170,8 @@ bool BufferView::cursor_move(CursorMovement which, bool allow_eol) { case CursorMovement::LEFT: case CursorMovement::RIGHT: + case CursorMovement::SCREEN_ROW_UP: + case CursorMovement::SCREEN_ROW_DOWN: determine_new_cursor_screen_row(); break; case CursorMovement::UP: From 7648bee12e4dd610ebebbab798a297d2e12b8bdb Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sat, 14 Oct 2017 12:30:28 -0400 Subject: [PATCH 29/30] draw control characters in different color font --- src/gui/BufferPane.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/BufferPane.cc b/src/gui/BufferPane.cc index e83f655..8dd0d76 100644 --- a/src/gui/BufferPane.cc +++ b/src/gui/BufferPane.cc @@ -201,8 +201,8 @@ void BufferPane::draw_buffer_character(uint32_t character, int screen_row, int s m_window->gl()->draw_rect(win_x(x + 2), win_y(y), m_window->font()->get_advance() * 2 - 4, 1, 0, 0.7, 1.0, 1.0); - m_window->gl()->draw_character(win_x(x), win_y(y), '^', *m_window->font(), 1.0, 1.0, 1.0, 1.0); - m_window->gl()->draw_character(win_x(col_x(screen_column + 1)), win_y(y), character | 0x40u, *m_window->font(), 1.0, 1.0, 1.0, 1.0); + m_window->gl()->draw_character(win_x(x), win_y(y), '^', *m_window->font(), 0.0, 0.7, 1.0, 1.0); + m_window->gl()->draw_character(win_x(col_x(screen_column + 1)), win_y(y), character | 0x40u, *m_window->font(), 0.0, 0.7, 1.0, 1.0); } else { From 5239f128ccc519b3622bf98f14d046cd6c85b59c Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sat, 14 Oct 2017 12:38:39 -0400 Subject: [PATCH 30/30] pass keyboard modifier key states in button press event --- src/gui/jtk/Jtk_event.cc | 33 +++++++++++++++++++++------------ src/gui/jtk/Jtk_event.h | 1 + 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/gui/jtk/Jtk_event.cc b/src/gui/jtk/Jtk_event.cc index ebc1ab8..4cb2276 100644 --- a/src/gui/jtk/Jtk_event.cc +++ b/src/gui/jtk/Jtk_event.cc @@ -40,6 +40,25 @@ static unsigned int GetXState() } #endif +static uint32_t XStateToJtkKeyMods(unsigned int x_state) +{ + uint32_t mods = 0u; + /* OR in the modifier states */ + if (x_state & ShiftMask) + { + mods |= JTK_KEY_MODS_SHIFT; + } + if (x_state & LockMask) + { + mods |= JTK_KEY_MODS_LOCK; + } + if (x_state & ControlMask) + { + mods |= JTK_KEY_MODS_CTRL; + } + return mods; +} + static uint32_t XKeyToJtkKey(unsigned int x_keycode, unsigned int x_state) { XKeyEvent x_key_event; @@ -177,18 +196,7 @@ static uint32_t XKeyToJtkKey(unsigned int x_keycode, unsigned int x_state) } /* OR in the modifier states */ - if (x_state & ShiftMask) - { - key |= JTK_KEY_MODS_SHIFT; - } - if (x_state & LockMask) - { - key |= JTK_KEY_MODS_LOCK; - } - if (x_state & ControlMask) - { - key |= JTK_KEY_MODS_CTRL; - } + key |= XStateToJtkKeyMods(x_state); return key; } @@ -291,6 +299,7 @@ static Bool MatchButtonPress(Display * display, XEvent * event, XPointer arg) static bool ProcessXButtonPressEvent(XEvent * x_event, Jtk_Event * event) { event->type = JTK_EVENT_BUTTON_PRESS; + event->button.mods = XStateToJtkKeyMods(x_event->xbutton.state); event->button.button = x_event->xbutton.button; /* If this is a mouse wheel scroll event, remove any following scroll * events. */ diff --git a/src/gui/jtk/Jtk_event.h b/src/gui/jtk/Jtk_event.h index edd5f9c..c8e910d 100644 --- a/src/gui/jtk/Jtk_event.h +++ b/src/gui/jtk/Jtk_event.h @@ -24,6 +24,7 @@ typedef struct typedef struct { + uint32_t mods; uint8_t button; } Jtk_ButtonEvent;