From d678be717c628bf679daf55cef5bd4dc2d7b00d8 Mon Sep 17 00:00:00 2001 From: Matthew Kilgore Date: Thu, 24 Nov 2022 04:50:48 -0500 Subject: [PATCH] Move GLUT initialization logic into separate .cpp file --- Makefile | 5 + internal/c/libqb.cpp | 534 +----------------- internal/c/libqb/build.mk | 7 + internal/c/libqb/include/glut-thread.h | 31 + internal/c/libqb/include/keyhandler.h | 299 ++++++++++ .../c/libqb/src/console-only-main-thread.cpp | 33 ++ internal/c/libqb/src/glut-main-thread.cpp | 173 ++++++ internal/c/libqb/src/mac-key-monitor.h | 10 + internal/c/libqb/src/mac-key-monitor.mm | 85 +++ internal/c/parts/core/build.mk | 2 + 10 files changed, 655 insertions(+), 524 deletions(-) create mode 100644 internal/c/libqb/include/glut-thread.h create mode 100644 internal/c/libqb/include/keyhandler.h create mode 100644 internal/c/libqb/src/console-only-main-thread.cpp create mode 100644 internal/c/libqb/src/glut-main-thread.cpp create mode 100644 internal/c/libqb/src/mac-key-monitor.h create mode 100644 internal/c/libqb/src/mac-key-monitor.mm diff --git a/Makefile b/Makefile index 9e6f7f7cc..c9b02292b 100644 --- a/Makefile +++ b/Makefile @@ -421,6 +421,11 @@ EXE_OBJS := $(QBLIB) $(EXE_OBJS) %.o: %.cpp $(CXX) $(CXXFLAGS) $< -c -o $@ +ifeq ($(OS),osx) +%.o: %.mm + $(CXX) $(CXXFLAGS) $< -c -o $@ +endif + $(PATH_INTERNAL_TEMP)/data.o: $(PATH_INTERNAL_TEMP)/data.bin $(OBJCOPY) -Ibinary $(OBJCOPY_FLAGS) $< $@ diff --git a/internal/c/libqb.cpp b/internal/c/libqb.cpp index 09a62a662..3c4ed2b22 100644 --- a/internal/c/libqb.cpp +++ b/internal/c/libqb.cpp @@ -29,6 +29,8 @@ #include "image.h" #include "gui.h" #include "http.h" +#include "keyhandler.h" +#include "glut-thread.h" int32 disableEvents = 0; @@ -243,26 +245,10 @@ extern "C" void QB64_Window_Handle(void *handle) { //... } -static bool is_glut_up(); -static void start_glut_thread(); - -#define NEEDS_GLUT(error_result) do { \ - if (!is_glut_up()) { \ - error(5); \ - return error_result; \ - } \ - } while (0) - -#define OPTIONAL_GLUT(result) do { \ - if (!is_glut_up()) \ - return result; \ - } while (0) - // forward references void set_view(int32 new_mode); void set_render_source(int32 new_handle); void set_render_dest(int32 new_handle); -void reinit_glut_callbacks(); int32 framebufferobjects_supported = 0; @@ -1243,294 +1229,6 @@ int64 GetTicks() { return orwl_gettime(); } int64 GetTicks() { return ((((int64)clock()) * ((int64)1000)) / ((int64)CLOCKS_PER_SEC)); } #endif -#define QBK 200000 -#define VK 100000 -#define UC 1073741824 -/* QBK codes: - 200000-200010: Numpad keys with Num-Lock off - NO_NUMLOCK_KP0=INSERT - NO_NUMLOCK_KP1=END - NO_NUMLOCK_KP2=DOWN - NO_NUMLOCK_KP3=PGDOWN - NO_NUMLOCK_KP4... - NO_NUMLOCK_KP5 - NO_NUMLOCK_KP6 - NO_NUMLOCK_KP7 - NO_NUMLOCK_KP8 - NO_NUMLOCK_KP9 - NO_NUMLOCK_KP_PERIOD=DEL - 200011: SCROLL_LOCK_ON - 200012: INSERT_MODE_ON -*/ -#define QBK_SCROLL_LOCK_MODE 11 -#define QBK_INSERT_MODE 12 -#define QBK_CHR0 13 -typedef enum { - QBVK_UNKNOWN = 0, - QBVK_FIRST = 0, - QBVK_BACKSPACE = 8, - QBVK_TAB = 9, - QBVK_CLEAR = 12, - QBVK_RETURN = 13, - QBVK_PAUSE = 19, - QBVK_ESCAPE = 27, - QBVK_SPACE = 32, - QBVK_EXCLAIM = 33, - QBVK_QUOTEDBL = 34, - QBVK_HASH = 35, - QBVK_DOLLAR = 36, - QBVK_AMPERSAND = 38, - QBVK_QUOTE = 39, - QBVK_LEFTPAREN = 40, - QBVK_RIGHTPAREN = 41, - QBVK_ASTERISK = 42, - QBVK_PLUS = 43, - QBVK_COMMA = 44, - QBVK_MINUS = 45, - QBVK_PERIOD = 46, - QBVK_SLASH = 47, - QBVK_0 = 48, - QBVK_1 = 49, - QBVK_2 = 50, - QBVK_3 = 51, - QBVK_4 = 52, - QBVK_5 = 53, - QBVK_6 = 54, - QBVK_7 = 55, - QBVK_8 = 56, - QBVK_9 = 57, - QBVK_COLON = 58, - QBVK_SEMICOLON = 59, - QBVK_LESS = 60, - QBVK_EQUALS = 61, - QBVK_GREATER = 62, - QBVK_QUESTION = 63, - QBVK_AT = 64, - // Skip uppercase letters - QBVK_LEFTBRACKET = 91, - QBVK_BACKSLASH = 92, - QBVK_RIGHTBRACKET = 93, - QBVK_CARET = 94, - QBVK_UNDERSCORE = 95, - QBVK_BACKQUOTE = 96, - QBVK_a = 97, - QBVK_b = 98, - QBVK_c = 99, - QBVK_d = 100, - QBVK_e = 101, - QBVK_f = 102, - QBVK_g = 103, - QBVK_h = 104, - QBVK_i = 105, - QBVK_j = 106, - QBVK_k = 107, - QBVK_l = 108, - QBVK_m = 109, - QBVK_n = 110, - QBVK_o = 111, - QBVK_p = 112, - QBVK_q = 113, - QBVK_r = 114, - QBVK_s = 115, - QBVK_t = 116, - QBVK_u = 117, - QBVK_v = 118, - QBVK_w = 119, - QBVK_x = 120, - QBVK_y = 121, - QBVK_z = 122, - QBVK_DELETE = 127, - // End of ASCII mapped QBVKs - // International QBVKs - QBVK_WORLD_0 = 160, /* 0xA0 */ - QBVK_WORLD_1 = 161, - QBVK_WORLD_2 = 162, - QBVK_WORLD_3 = 163, - QBVK_WORLD_4 = 164, - QBVK_WORLD_5 = 165, - QBVK_WORLD_6 = 166, - QBVK_WORLD_7 = 167, - QBVK_WORLD_8 = 168, - QBVK_WORLD_9 = 169, - QBVK_WORLD_10 = 170, - QBVK_WORLD_11 = 171, - QBVK_WORLD_12 = 172, - QBVK_WORLD_13 = 173, - QBVK_WORLD_14 = 174, - QBVK_WORLD_15 = 175, - QBVK_WORLD_16 = 176, - QBVK_WORLD_17 = 177, - QBVK_WORLD_18 = 178, - QBVK_WORLD_19 = 179, - QBVK_WORLD_20 = 180, - QBVK_WORLD_21 = 181, - QBVK_WORLD_22 = 182, - QBVK_WORLD_23 = 183, - QBVK_WORLD_24 = 184, - QBVK_WORLD_25 = 185, - QBVK_WORLD_26 = 186, - QBVK_WORLD_27 = 187, - QBVK_WORLD_28 = 188, - QBVK_WORLD_29 = 189, - QBVK_WORLD_30 = 190, - QBVK_WORLD_31 = 191, - QBVK_WORLD_32 = 192, - QBVK_WORLD_33 = 193, - QBVK_WORLD_34 = 194, - QBVK_WORLD_35 = 195, - QBVK_WORLD_36 = 196, - QBVK_WORLD_37 = 197, - QBVK_WORLD_38 = 198, - QBVK_WORLD_39 = 199, - QBVK_WORLD_40 = 200, - QBVK_WORLD_41 = 201, - QBVK_WORLD_42 = 202, - QBVK_WORLD_43 = 203, - QBVK_WORLD_44 = 204, - QBVK_WORLD_45 = 205, - QBVK_WORLD_46 = 206, - QBVK_WORLD_47 = 207, - QBVK_WORLD_48 = 208, - QBVK_WORLD_49 = 209, - QBVK_WORLD_50 = 210, - QBVK_WORLD_51 = 211, - QBVK_WORLD_52 = 212, - QBVK_WORLD_53 = 213, - QBVK_WORLD_54 = 214, - QBVK_WORLD_55 = 215, - QBVK_WORLD_56 = 216, - QBVK_WORLD_57 = 217, - QBVK_WORLD_58 = 218, - QBVK_WORLD_59 = 219, - QBVK_WORLD_60 = 220, - QBVK_WORLD_61 = 221, - QBVK_WORLD_62 = 222, - QBVK_WORLD_63 = 223, - QBVK_WORLD_64 = 224, - QBVK_WORLD_65 = 225, - QBVK_WORLD_66 = 226, - QBVK_WORLD_67 = 227, - QBVK_WORLD_68 = 228, - QBVK_WORLD_69 = 229, - QBVK_WORLD_70 = 230, - QBVK_WORLD_71 = 231, - QBVK_WORLD_72 = 232, - QBVK_WORLD_73 = 233, - QBVK_WORLD_74 = 234, - QBVK_WORLD_75 = 235, - QBVK_WORLD_76 = 236, - QBVK_WORLD_77 = 237, - QBVK_WORLD_78 = 238, - QBVK_WORLD_79 = 239, - QBVK_WORLD_80 = 240, - QBVK_WORLD_81 = 241, - QBVK_WORLD_82 = 242, - QBVK_WORLD_83 = 243, - QBVK_WORLD_84 = 244, - QBVK_WORLD_85 = 245, - QBVK_WORLD_86 = 246, - QBVK_WORLD_87 = 247, - QBVK_WORLD_88 = 248, - QBVK_WORLD_89 = 249, - QBVK_WORLD_90 = 250, - QBVK_WORLD_91 = 251, - QBVK_WORLD_92 = 252, - QBVK_WORLD_93 = 253, - QBVK_WORLD_94 = 254, - QBVK_WORLD_95 = 255, /* 0xFF */ - // Numeric keypad - QBVK_KP0 = 256, - QBVK_KP1 = 257, - QBVK_KP2 = 258, - QBVK_KP3 = 259, - QBVK_KP4 = 260, - QBVK_KP5 = 261, - QBVK_KP6 = 262, - QBVK_KP7 = 263, - QBVK_KP8 = 264, - QBVK_KP9 = 265, - QBVK_KP_PERIOD = 266, - QBVK_KP_DIVIDE = 267, - QBVK_KP_MULTIPLY = 268, - QBVK_KP_MINUS = 269, - QBVK_KP_PLUS = 270, - QBVK_KP_ENTER = 271, - QBVK_KP_EQUALS = 272, - // Arrows + Home/End pad - QBVK_UP = 273, - QBVK_DOWN = 274, - QBVK_RIGHT = 275, - QBVK_LEFT = 276, - QBVK_INSERT = 277, - QBVK_HOME = 278, - QBVK_END = 279, - QBVK_PAGEUP = 280, - QBVK_PAGEDOWN = 281, - // Function keys - QBVK_F1 = 282, - QBVK_F2 = 283, - QBVK_F3 = 284, - QBVK_F4 = 285, - QBVK_F5 = 286, - QBVK_F6 = 287, - QBVK_F7 = 288, - QBVK_F8 = 289, - QBVK_F9 = 290, - QBVK_F10 = 291, - QBVK_F11 = 292, - QBVK_F12 = 293, - QBVK_F13 = 294, - QBVK_F14 = 295, - QBVK_F15 = 296, - // Key state modifier keys - QBVK_NUMLOCK = 300, - QBVK_CAPSLOCK = 301, - QBVK_SCROLLOCK = 302, - // If more modifiers are added, the window defocus code in qb64_os_event_linux must be altered - QBVK_RSHIFT = 303, - QBVK_LSHIFT = 304, - QBVK_RCTRL = 305, - QBVK_LCTRL = 306, - QBVK_RALT = 307, - QBVK_LALT = 308, - QBVK_RMETA = 309, - QBVK_LMETA = 310, - QBVK_LSUPER = 311, /* Left "Windows" key */ - QBVK_RSUPER = 312, /* Right "Windows" key */ - QBVK_MODE = 313, /* "Alt Gr" key */ - QBVK_COMPOSE = 314, /* Multi-key compose key */ - // Miscellaneous function keys - QBVK_HELP = 315, - QBVK_PRINT = 316, - QBVK_SYSREQ = 317, - QBVK_BREAK = 318, - QBVK_MENU = 319, - QBVK_POWER = 320, /* Power Macintosh power key */ - QBVK_EURO = 321, /* Some european keyboards */ - QBVK_UNDO = 322, /* Atari keyboard has Undo */ - QBVK_LAST -} QBVKs; -// Enumeration of valid key mods (possibly OR'd together) -typedef enum { - KMOD_NONE = 0x0000, - KMOD_LSHIFT = 0x0001, - KMOD_RSHIFT = 0x0002, - KMOD_LCTRL = 0x0040, - KMOD_RCTRL = 0x0080, - KMOD_LALT = 0x0100, - KMOD_RALT = 0x0200, - KMOD_LMETA = 0x0400, - KMOD_RMETA = 0x0800, - KMOD_NUM = 0x1000, - KMOD_CAPS = 0x2000, - KMOD_MODE = 0x4000, - KMOD_RESERVED = 0x8000 -} KMODs; -#define KMOD_CTRL (KMOD_LCTRL | KMOD_RCTRL) -#define KMOD_SHIFT (KMOD_LSHIFT | KMOD_RSHIFT) -#define KMOD_ALT (KMOD_LALT | KMOD_RALT) -#define KMOD_META (KMOD_LMETA | KMOD_RMETA) - /* Restricted Functionality: (Security focused approach, does not include restricting sound etc) Block while compiling: (ONLY things that cannot be caught at runtime) @@ -27547,7 +27245,7 @@ void sub_screenicon() { int32 func_windowexists() { #ifdef QB64_GLUT - return is_glut_up(); + return libqb_is_glut_up(); #else return -1; #endif @@ -34286,7 +33984,7 @@ void sub__screenshow() { #ifdef QB64_GLUT screen_hide = 0; // $SCREENHIDE programs will not have the window running - start_glut_thread(); + libqb_start_glut_thread(); glutShowWindow(); #endif } @@ -34296,7 +33994,9 @@ void sub__screenhide() { return; #ifdef QB64_GLUT - // start_glut_thread(); + // This is probably unnecessary, no conditions allow for screen_hide==0 + // without GLUT running, but it doesn't hurt anything. + libqb_start_glut_thread(); glutHideWindow(); #endif @@ -37367,165 +37067,6 @@ qbs *func__dir(qbs *context_in) { #endif } -static void glutWarning(const char *fmt, va_list lst) { - // Do something -} - -// Performs all of the FreeGLUT initialization except for calling glutMainLoop() -static void initialize_glut(int argc, char **argv) { -#ifdef QB64_GLUT -# ifdef CORE_FREEGLUT - // This keeps FreeGlut from dumping warnings to console - glutInitWarningFunc(glutWarning); - glutInitErrorFunc(glutWarning); -# endif - - glutInit(&argc, argv); - -# ifdef QB64_MACOSX - [NSEvent addLocalMonitorForEventsMatchingMask:NSFlagsChangedMask - handler:^NSEvent *(NSEvent *event) { - // notes on bitfields: - // if ([event modifierFlags] == 131330) keydown_vk(VK+QBVK_LSHIFT);// 100000000100000010 - // if ([event modifierFlags] == 131332) keydown_vk(VK+QBVK_RSHIFT);// 100000000100000100 - // if ([event modifierFlags] == 262401) keydown_vk(VK+QBVK_LCTRL); //1000000000100000001 - // if ([event modifierFlags] == 270592) keydown_vk(VK+QBVK_RCTRL); //1000010000100000000 - // if ([event modifierFlags] == 524576) keydown_vk(VK+QBVK_LALT); //10000000000100100000 - // if ([event modifierFlags] == 524608) keydown_vk(VK+QBVK_RALT); //10000000000101000000 - // caps lock // 10000000100000000 - - int x = [event modifierFlags]; - - if (x & (1 << 0)) { - if (!keyheld(VK + QBVK_LCTRL)) - keydown_vk(VK + QBVK_LCTRL); - } else { - if (keyheld(VK + QBVK_LCTRL)) - keyup_vk(VK + QBVK_LCTRL); - } - if (x & (1 << 13)) { - if (!keyheld(VK + QBVK_RCTRL)) - keydown_vk(VK + QBVK_RCTRL); - } else { - if (keyheld(VK + QBVK_RCTRL)) - keyup_vk(VK + QBVK_RCTRL); - } - - if (x & (1 << 1)) { - if (!keyheld(VK + QBVK_LSHIFT)) - keydown_vk(VK + QBVK_LSHIFT); - } else { - if (keyheld(VK + QBVK_LSHIFT)) - keyup_vk(VK + QBVK_LSHIFT); - } - if (x & (1 << 2)) { - if (!keyheld(VK + QBVK_RSHIFT)) - keydown_vk(VK + QBVK_RSHIFT); - } else { - if (keyheld(VK + QBVK_RSHIFT)) - keyup_vk(VK + QBVK_RSHIFT); - } - - if (x & (1 << 5)) { - if (!keyheld(VK + QBVK_LALT)) - keydown_vk(VK + QBVK_LALT); - } else { - if (keyheld(VK + QBVK_LALT)) - keyup_vk(VK + QBVK_LALT); - } - if (x & (1 << 6)) { - if (!keyheld(VK + QBVK_RALT)) - keydown_vk(VK + QBVK_RALT); - } else { - if (keyheld(VK + QBVK_RALT)) - keyup_vk(VK + QBVK_RALT); - } - - if (x & (1 << 16)) { - if (!keyheld(VK + QBVK_CAPSLOCK)) - keydown_vk(VK + QBVK_CAPSLOCK); - } else { - if (keyheld(VK + QBVK_CAPSLOCK)) - keyup_vk(VK + QBVK_CAPSLOCK); - } - - return event; - }]; -# endif - -# ifdef QB64_WINDOWS - glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE); -# else - glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); -# endif - - glutInitWindowSize(640, 400); // cannot be changed unless display_x(etc) are modified - - if (!glutGet(GLUT_DISPLAY_MODE_POSSIBLE)) // must be called on Linux or GLUT crashes - { - exit(1); - } - - if (!window_title) { - glutCreateWindow("Untitled"); - } else { - glutCreateWindow((char *)window_title); - } - - GLenum err = glewInit(); - if (GLEW_OK != err) { - gui_alert((char *)glewGetErrorString(err)); - } - if (glewIsSupported("GL_EXT_framebuffer_object")) - framebufferobjects_supported = 1; - - glutDisplayFunc(GLUT_DISPLAY_REQUEST); - -# ifdef QB64_WINDOWS - glutTimerFunc(8, GLUT_TIMER_EVENT, 0); -# else - glutIdleFunc(GLUT_IDLEFUNC); -# endif - - glutKeyboardFunc(GLUT_KEYBOARD_FUNC); - glutKeyboardUpFunc(GLUT_KEYBOARDUP_FUNC); - glutSpecialFunc(GLUT_SPECIAL_FUNC); - glutSpecialUpFunc(GLUT_SPECIALUP_FUNC); - glutMouseFunc(GLUT_MOUSE_FUNC); - glutMotionFunc(GLUT_MOTION_FUNC); - glutPassiveMotionFunc(GLUT_PASSIVEMOTION_FUNC); - glutReshapeFunc(GLUT_RESHAPE_FUNC); - -# ifdef CORE_FREEGLUT - glutMouseWheelFunc(GLUT_MOUSEWHEEL_FUNC); -# endif -#endif // QB64_GLUT -} - -static bool glut_is_started; -static struct completion glut_thread_starter; -static struct completion *glut_thread_initialized; - -static void start_glut_thread() { - if (glut_is_started) - return; - - struct completion init; - completion_init(&init); - - glut_thread_initialized = &init; - - completion_finish(&glut_thread_starter); - - completion_wait(&init); - completion_clear(&init); -} - -// Checks whether the GLUT thread is running -static bool is_glut_up() { - return glut_is_started; -} - extern void set_dynamic_info(); int main(int argc, char *argv[]) { @@ -37967,14 +37508,7 @@ int main(int argc, char *argv[]) { libqb_http_init(); -#ifdef QB64_GUI - if (!screen_hide) { - initialize_glut(argc, argv); // Initialize GLUT if the screen isn't hidden - glut_is_started = true; - } else { - completion_init(&glut_thread_starter); - } -#endif + libqb_glut_presetup(argc, argv); struct libqb_thread *qbmain = libqb_thread_new(); libqb_thread_start(qbmain, QBMAIN, NULL); @@ -37984,32 +37518,9 @@ int main(int argc, char *argv[]) { lock_display_required = 1; -#ifdef QB64_GUI + libqb_start_main_thread(argc, argv); - struct libqb_thread *main_loop = libqb_thread_new(); - libqb_thread_start(main_loop, MAIN_LOOP, NULL); - - // This happens for $SCREENHIDE programs. This thread waits on the - // `glut_thread_starter` completion, which will get completed if a - // _ScreenShow is used. - if (!glut_is_started) { - completion_wait(&glut_thread_starter); - - initialize_glut(argc, argv); - glut_is_started = true; - - if (glut_thread_initialized) - completion_finish(glut_thread_initialized); - } - - glutMainLoop(); - -#else - // normally MAIN_LOOP() is launched in a separate thread to reserve the primary thread for GLUT - // that is not required, so run MAIN_LOOP() in our primary thread - MAIN_LOOP(NULL); - return 0; -#endif + return 0; // Should never get here } //###################### Main Loop #################### @@ -40238,31 +39749,6 @@ extern "C" int qb64_custom_event(int event, int v1, int v2, int v3, int v4, int return -1; // Unknown command (use for debugging purposes only) } // qb64_custom_event -void reinit_glut_callbacks() { - -#ifdef QB64_GLUT - - glutDisplayFunc(GLUT_DISPLAY_REQUEST); -# ifdef QB64_WINDOWS - glutTimerFunc(8, GLUT_TIMER_EVENT, 0); -# else - glutIdleFunc(GLUT_IDLEFUNC); -# endif - glutKeyboardFunc(GLUT_KEYBOARD_FUNC); - glutKeyboardUpFunc(GLUT_KEYBOARDUP_FUNC); - glutSpecialFunc(GLUT_SPECIAL_FUNC); - glutSpecialUpFunc(GLUT_SPECIALUP_FUNC); - glutMouseFunc(GLUT_MOUSE_FUNC); - glutMotionFunc(GLUT_MOTION_FUNC); - glutPassiveMotionFunc(GLUT_PASSIVEMOTION_FUNC); - glutReshapeFunc(GLUT_RESHAPE_FUNC); -# ifdef CORE_FREEGLUT - glutMouseWheelFunc(GLUT_MOUSEWHEEL_FUNC); -# endif - -#endif -} - int32 func__capslock() { #ifdef QB64_WINDOWS return -GetKeyState(VK_CAPITAL); diff --git a/internal/c/libqb/build.mk b/internal/c/libqb/build.mk index 3350de34c..bde5b3834 100644 --- a/internal/c/libqb/build.mk +++ b/internal/c/libqb/build.mk @@ -8,4 +8,11 @@ libqb-objs-y$(DEP_HTTP) += $(PATH_LIBQB)/src/http-stub.o libqb-objs-y += $(PATH_LIBQB)/src/threading-$(PLATFORM).o +libqb-objs-y$(DEP_CONSOLE_ONLY) += $(PATH_LIBQB)/src/glut-main-thread.o +libqb-objs-$(DEP_CONSOLE_ONLY) += $(PATH_LIBQB)/src/console-only-main-thread.o + +ifeq ($(OS),osx) +libqb-objs-y$(DEP_CONSOLE_ONLY) += $(PATH_LIBQB)/src/mac-key-monitor.o +endif + CLEAN_LIST += $(libqb-objs-y) $(libqb-objs-yy) $(libqb-objs-) diff --git a/internal/c/libqb/include/glut-thread.h b/internal/c/libqb/include/glut-thread.h new file mode 100644 index 000000000..d87397e9e --- /dev/null +++ b/internal/c/libqb/include/glut-thread.h @@ -0,0 +1,31 @@ +#ifndef INCLUDE_LIBQB_GLUT_THREAD_H +#define INCLUDE_LIBQB_GLUT_THREAD_H + +// Called to potentially setup GLUT before starting the program. +void libqb_glut_presetup(int argc, char **argv); + +// Starts the "main thread", including handling all the GLUT setup. +void libqb_start_main_thread(int argc, char **argv); + +// Used to support _ScreenShow, which can start the GLUT thread after the +// program is started +void libqb_start_glut_thread(); + +// Indicates whether GLUT is currently running (and thus whether we're able to +// do any GLUT-related stuff +bool libqb_is_glut_up(); + +// Convinence macros, exists a function depending on the state of GLUT +#define NEEDS_GLUT(error_result) do { \ + if (!libqb_is_glut_up()) { \ + error(5); \ + return error_result; \ + } \ + } while (0) + +#define OPTIONAL_GLUT(result) do { \ + if (!libqb_is_glut_up()) \ + return result; \ + } while (0) + +#endif diff --git a/internal/c/libqb/include/keyhandler.h b/internal/c/libqb/include/keyhandler.h new file mode 100644 index 000000000..4909c5ae8 --- /dev/null +++ b/internal/c/libqb/include/keyhandler.h @@ -0,0 +1,299 @@ +#ifndef INCLUDE_LIBQB_KEYHANDLER_h +#define INCLUDE_LIBQB_KEYHANDLER_h + +#include + +int32_t keyheld(uint32_t x); + +void keydown_vk(uint32_t key); +void keyup_vk(uint32_t key); + +#define QBK 200000 +#define VK 100000 +#define UC 1073741824 +/* QBK codes: + 200000-200010: Numpad keys with Num-Lock off + NO_NUMLOCK_KP0=INSERT + NO_NUMLOCK_KP1=END + NO_NUMLOCK_KP2=DOWN + NO_NUMLOCK_KP3=PGDOWN + NO_NUMLOCK_KP4... + NO_NUMLOCK_KP5 + NO_NUMLOCK_KP6 + NO_NUMLOCK_KP7 + NO_NUMLOCK_KP8 + NO_NUMLOCK_KP9 + NO_NUMLOCK_KP_PERIOD=DEL + 200011: SCROLL_LOCK_ON + 200012: INSERT_MODE_ON +*/ +#define QBK_SCROLL_LOCK_MODE 11 +#define QBK_INSERT_MODE 12 +#define QBK_CHR0 13 +typedef enum { + QBVK_UNKNOWN = 0, + QBVK_FIRST = 0, + QBVK_BACKSPACE = 8, + QBVK_TAB = 9, + QBVK_CLEAR = 12, + QBVK_RETURN = 13, + QBVK_PAUSE = 19, + QBVK_ESCAPE = 27, + QBVK_SPACE = 32, + QBVK_EXCLAIM = 33, + QBVK_QUOTEDBL = 34, + QBVK_HASH = 35, + QBVK_DOLLAR = 36, + QBVK_AMPERSAND = 38, + QBVK_QUOTE = 39, + QBVK_LEFTPAREN = 40, + QBVK_RIGHTPAREN = 41, + QBVK_ASTERISK = 42, + QBVK_PLUS = 43, + QBVK_COMMA = 44, + QBVK_MINUS = 45, + QBVK_PERIOD = 46, + QBVK_SLASH = 47, + QBVK_0 = 48, + QBVK_1 = 49, + QBVK_2 = 50, + QBVK_3 = 51, + QBVK_4 = 52, + QBVK_5 = 53, + QBVK_6 = 54, + QBVK_7 = 55, + QBVK_8 = 56, + QBVK_9 = 57, + QBVK_COLON = 58, + QBVK_SEMICOLON = 59, + QBVK_LESS = 60, + QBVK_EQUALS = 61, + QBVK_GREATER = 62, + QBVK_QUESTION = 63, + QBVK_AT = 64, + // Skip uppercase letters + QBVK_LEFTBRACKET = 91, + QBVK_BACKSLASH = 92, + QBVK_RIGHTBRACKET = 93, + QBVK_CARET = 94, + QBVK_UNDERSCORE = 95, + QBVK_BACKQUOTE = 96, + QBVK_a = 97, + QBVK_b = 98, + QBVK_c = 99, + QBVK_d = 100, + QBVK_e = 101, + QBVK_f = 102, + QBVK_g = 103, + QBVK_h = 104, + QBVK_i = 105, + QBVK_j = 106, + QBVK_k = 107, + QBVK_l = 108, + QBVK_m = 109, + QBVK_n = 110, + QBVK_o = 111, + QBVK_p = 112, + QBVK_q = 113, + QBVK_r = 114, + QBVK_s = 115, + QBVK_t = 116, + QBVK_u = 117, + QBVK_v = 118, + QBVK_w = 119, + QBVK_x = 120, + QBVK_y = 121, + QBVK_z = 122, + QBVK_DELETE = 127, + // End of ASCII mapped QBVKs + // International QBVKs + QBVK_WORLD_0 = 160, /* 0xA0 */ + QBVK_WORLD_1 = 161, + QBVK_WORLD_2 = 162, + QBVK_WORLD_3 = 163, + QBVK_WORLD_4 = 164, + QBVK_WORLD_5 = 165, + QBVK_WORLD_6 = 166, + QBVK_WORLD_7 = 167, + QBVK_WORLD_8 = 168, + QBVK_WORLD_9 = 169, + QBVK_WORLD_10 = 170, + QBVK_WORLD_11 = 171, + QBVK_WORLD_12 = 172, + QBVK_WORLD_13 = 173, + QBVK_WORLD_14 = 174, + QBVK_WORLD_15 = 175, + QBVK_WORLD_16 = 176, + QBVK_WORLD_17 = 177, + QBVK_WORLD_18 = 178, + QBVK_WORLD_19 = 179, + QBVK_WORLD_20 = 180, + QBVK_WORLD_21 = 181, + QBVK_WORLD_22 = 182, + QBVK_WORLD_23 = 183, + QBVK_WORLD_24 = 184, + QBVK_WORLD_25 = 185, + QBVK_WORLD_26 = 186, + QBVK_WORLD_27 = 187, + QBVK_WORLD_28 = 188, + QBVK_WORLD_29 = 189, + QBVK_WORLD_30 = 190, + QBVK_WORLD_31 = 191, + QBVK_WORLD_32 = 192, + QBVK_WORLD_33 = 193, + QBVK_WORLD_34 = 194, + QBVK_WORLD_35 = 195, + QBVK_WORLD_36 = 196, + QBVK_WORLD_37 = 197, + QBVK_WORLD_38 = 198, + QBVK_WORLD_39 = 199, + QBVK_WORLD_40 = 200, + QBVK_WORLD_41 = 201, + QBVK_WORLD_42 = 202, + QBVK_WORLD_43 = 203, + QBVK_WORLD_44 = 204, + QBVK_WORLD_45 = 205, + QBVK_WORLD_46 = 206, + QBVK_WORLD_47 = 207, + QBVK_WORLD_48 = 208, + QBVK_WORLD_49 = 209, + QBVK_WORLD_50 = 210, + QBVK_WORLD_51 = 211, + QBVK_WORLD_52 = 212, + QBVK_WORLD_53 = 213, + QBVK_WORLD_54 = 214, + QBVK_WORLD_55 = 215, + QBVK_WORLD_56 = 216, + QBVK_WORLD_57 = 217, + QBVK_WORLD_58 = 218, + QBVK_WORLD_59 = 219, + QBVK_WORLD_60 = 220, + QBVK_WORLD_61 = 221, + QBVK_WORLD_62 = 222, + QBVK_WORLD_63 = 223, + QBVK_WORLD_64 = 224, + QBVK_WORLD_65 = 225, + QBVK_WORLD_66 = 226, + QBVK_WORLD_67 = 227, + QBVK_WORLD_68 = 228, + QBVK_WORLD_69 = 229, + QBVK_WORLD_70 = 230, + QBVK_WORLD_71 = 231, + QBVK_WORLD_72 = 232, + QBVK_WORLD_73 = 233, + QBVK_WORLD_74 = 234, + QBVK_WORLD_75 = 235, + QBVK_WORLD_76 = 236, + QBVK_WORLD_77 = 237, + QBVK_WORLD_78 = 238, + QBVK_WORLD_79 = 239, + QBVK_WORLD_80 = 240, + QBVK_WORLD_81 = 241, + QBVK_WORLD_82 = 242, + QBVK_WORLD_83 = 243, + QBVK_WORLD_84 = 244, + QBVK_WORLD_85 = 245, + QBVK_WORLD_86 = 246, + QBVK_WORLD_87 = 247, + QBVK_WORLD_88 = 248, + QBVK_WORLD_89 = 249, + QBVK_WORLD_90 = 250, + QBVK_WORLD_91 = 251, + QBVK_WORLD_92 = 252, + QBVK_WORLD_93 = 253, + QBVK_WORLD_94 = 254, + QBVK_WORLD_95 = 255, /* 0xFF */ + // Numeric keypad + QBVK_KP0 = 256, + QBVK_KP1 = 257, + QBVK_KP2 = 258, + QBVK_KP3 = 259, + QBVK_KP4 = 260, + QBVK_KP5 = 261, + QBVK_KP6 = 262, + QBVK_KP7 = 263, + QBVK_KP8 = 264, + QBVK_KP9 = 265, + QBVK_KP_PERIOD = 266, + QBVK_KP_DIVIDE = 267, + QBVK_KP_MULTIPLY = 268, + QBVK_KP_MINUS = 269, + QBVK_KP_PLUS = 270, + QBVK_KP_ENTER = 271, + QBVK_KP_EQUALS = 272, + // Arrows + Home/End pad + QBVK_UP = 273, + QBVK_DOWN = 274, + QBVK_RIGHT = 275, + QBVK_LEFT = 276, + QBVK_INSERT = 277, + QBVK_HOME = 278, + QBVK_END = 279, + QBVK_PAGEUP = 280, + QBVK_PAGEDOWN = 281, + // Function keys + QBVK_F1 = 282, + QBVK_F2 = 283, + QBVK_F3 = 284, + QBVK_F4 = 285, + QBVK_F5 = 286, + QBVK_F6 = 287, + QBVK_F7 = 288, + QBVK_F8 = 289, + QBVK_F9 = 290, + QBVK_F10 = 291, + QBVK_F11 = 292, + QBVK_F12 = 293, + QBVK_F13 = 294, + QBVK_F14 = 295, + QBVK_F15 = 296, + // Key state modifier keys + QBVK_NUMLOCK = 300, + QBVK_CAPSLOCK = 301, + QBVK_SCROLLOCK = 302, + // If more modifiers are added, the window defocus code in qb64_os_event_linux must be altered + QBVK_RSHIFT = 303, + QBVK_LSHIFT = 304, + QBVK_RCTRL = 305, + QBVK_LCTRL = 306, + QBVK_RALT = 307, + QBVK_LALT = 308, + QBVK_RMETA = 309, + QBVK_LMETA = 310, + QBVK_LSUPER = 311, /* Left "Windows" key */ + QBVK_RSUPER = 312, /* Right "Windows" key */ + QBVK_MODE = 313, /* "Alt Gr" key */ + QBVK_COMPOSE = 314, /* Multi-key compose key */ + // Miscellaneous function keys + QBVK_HELP = 315, + QBVK_PRINT = 316, + QBVK_SYSREQ = 317, + QBVK_BREAK = 318, + QBVK_MENU = 319, + QBVK_POWER = 320, /* Power Macintosh power key */ + QBVK_EURO = 321, /* Some european keyboards */ + QBVK_UNDO = 322, /* Atari keyboard has Undo */ + QBVK_LAST +} QBVKs; +// Enumeration of valid key mods (possibly OR'd together) +typedef enum { + KMOD_NONE = 0x0000, + KMOD_LSHIFT = 0x0001, + KMOD_RSHIFT = 0x0002, + KMOD_LCTRL = 0x0040, + KMOD_RCTRL = 0x0080, + KMOD_LALT = 0x0100, + KMOD_RALT = 0x0200, + KMOD_LMETA = 0x0400, + KMOD_RMETA = 0x0800, + KMOD_NUM = 0x1000, + KMOD_CAPS = 0x2000, + KMOD_MODE = 0x4000, + KMOD_RESERVED = 0x8000 +} KMODs; +#define KMOD_CTRL (KMOD_LCTRL | KMOD_RCTRL) +#define KMOD_SHIFT (KMOD_LSHIFT | KMOD_RSHIFT) +#define KMOD_ALT (KMOD_LALT | KMOD_RALT) +#define KMOD_META (KMOD_LMETA | KMOD_RMETA) + +#endif diff --git a/internal/c/libqb/src/console-only-main-thread.cpp b/internal/c/libqb/src/console-only-main-thread.cpp new file mode 100644 index 000000000..cb3a401f1 --- /dev/null +++ b/internal/c/libqb/src/console-only-main-thread.cpp @@ -0,0 +1,33 @@ + +#include "libqb-common.h" + +#include +#include +#include +#include + +#include "glut-thread.h" + +// This file is for Console-Only programs. They never invoke GLUT so the setup +// here is much simpler. + +// FIXME: PUt this definition somewhere else +void MAIN_LOOP(void *); + + +void libqb_glut_presetup(int argc, char **argv) { + +} + +void libqb_start_main_thread(int argc, char **argv) { + // Because GLUT is not used, we can just run MAIN_LOOP without creating a + // new thread for it. + MAIN_LOOP(NULL); +} + +void libqb_start_glut_thread() { +} + +bool libqb_is_glut_up() { + return false; +} diff --git a/internal/c/libqb/src/glut-main-thread.cpp b/internal/c/libqb/src/glut-main-thread.cpp new file mode 100644 index 000000000..819a5a233 --- /dev/null +++ b/internal/c/libqb/src/glut-main-thread.cpp @@ -0,0 +1,173 @@ + +#include "libqb-common.h" + +#include +#include +#include +#include +#include +#include +#include +#include "GL/glew.h" + +// note: MacOSX uses Apple's GLUT not FreeGLUT +#ifdef QB64_MACOSX +# include +#else +# define CORE_FREEGLUT +# include "freeglut.h" +#endif + +#include "mutex.h" +#include "thread.h" +#include "completion.h" +#include "gui.h" +#include "mac-key-monitor.h" +#include "glut-thread.h" + +// FIXME: These extern variable and function definitions should probably go +// somewhere more global so that they can be referenced by libqb.cpp +extern uint8_t *window_title; +extern int32_t framebufferobjects_supported; +extern int32_t screen_hide; + +void MAIN_LOOP(void *); +void GLUT_KEYBOARD_FUNC(unsigned char key, int x, int y); +void GLUT_DISPLAY_REQUEST(); +void GLUT_KEYBOARDUP_FUNC(unsigned char key, int x, int y); +void GLUT_SPECIAL_FUNC(int key, int x, int y); +void GLUT_SPECIALUP_FUNC(int key, int x, int y); +void GLUT_MOUSE_FUNC(int glut_button, int state, int x, int y); +void GLUT_MOTION_FUNC(int x, int y); +void GLUT_PASSIVEMOTION_FUNC(int x, int y); +void GLUT_RESHAPE_FUNC(int width, int height); + +#ifdef QB64_WINDOWS +void GLUT_TIMER_EVENT(int ignore); +#else +void GLUT_IDLEFUNC(); +#endif + +#ifdef CORE_FREEGLUT +void GLUT_MOUSEWHEEL_FUNC(int wheel, int direction, int x, int y); +#endif + +static void glutWarning(const char *fmt, va_list lst) { + // This keeps FreeGlut from dumping warnings to console +} + +// Performs all of the FreeGLUT initialization except for calling glutMainLoop() +static void initialize_glut(int argc, char **argv) { +# ifdef CORE_FREEGLUT + glutInitWarningFunc(glutWarning); + glutInitErrorFunc(glutWarning); +# endif + + glutInit(&argc, argv); + + mac_register_key_handler(); + +# ifdef QB64_WINDOWS + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE); +# else + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); +# endif + + glutInitWindowSize(640, 400); // cannot be changed unless display_x(etc) are modified + + if (!glutGet(GLUT_DISPLAY_MODE_POSSIBLE)) // must be called on Linux or GLUT crashes + { + exit(1); + } + + if (!window_title) { + glutCreateWindow("Untitled"); + } else { + glutCreateWindow((char *)window_title); + } + + GLenum err = glewInit(); + if (GLEW_OK != err) { + gui_alert((char *)glewGetErrorString(err)); + } + + if (glewIsSupported("GL_EXT_framebuffer_object")) + framebufferobjects_supported = 1; + + glutDisplayFunc(GLUT_DISPLAY_REQUEST); + +# ifdef QB64_WINDOWS + glutTimerFunc(8, GLUT_TIMER_EVENT, 0); +# else + glutIdleFunc(GLUT_IDLEFUNC); +# endif + + glutKeyboardFunc(GLUT_KEYBOARD_FUNC); + glutKeyboardUpFunc(GLUT_KEYBOARDUP_FUNC); + glutSpecialFunc(GLUT_SPECIAL_FUNC); + glutSpecialUpFunc(GLUT_SPECIALUP_FUNC); + glutMouseFunc(GLUT_MOUSE_FUNC); + glutMotionFunc(GLUT_MOTION_FUNC); + glutPassiveMotionFunc(GLUT_PASSIVEMOTION_FUNC); + glutReshapeFunc(GLUT_RESHAPE_FUNC); + +# ifdef CORE_FREEGLUT + glutMouseWheelFunc(GLUT_MOUSEWHEEL_FUNC); +# endif +} + +static bool glut_is_started; +static struct completion glut_thread_starter; +static struct completion *glut_thread_initialized; + +void libqb_start_glut_thread() { + if (glut_is_started) + return; + + struct completion init; + completion_init(&init); + + glut_thread_initialized = &init; + + completion_finish(&glut_thread_starter); + + completion_wait(&init); + completion_clear(&init); +} + +// Checks whether the GLUT thread is running +bool libqb_is_glut_up() { + return glut_is_started; +} + +void libqb_glut_presetup(int argc, char **argv) { + if (!screen_hide) { + initialize_glut(argc, argv); // Initialize GLUT if the screen isn't hidden + glut_is_started = true; + } else { + completion_init(&glut_thread_starter); + } +} + +void libqb_start_main_thread(int argc, char **argv) { + + // Start the 'MAIN_LOOP' in a separate thread, as GLUT has to run on the + // initial thread. + struct libqb_thread *main_loop = libqb_thread_new(); + libqb_thread_start(main_loop, MAIN_LOOP, NULL); + + // This happens for $SCREENHIDE programs. This thread waits on the + // `glut_thread_starter` completion, which will get completed if a + // _ScreenShow is used. + if (!glut_is_started) { + completion_wait(&glut_thread_starter); + + initialize_glut(argc, argv); + glut_is_started = true; + + if (glut_thread_initialized) + completion_finish(glut_thread_initialized); + } + + glutMainLoop(); +} diff --git a/internal/c/libqb/src/mac-key-monitor.h b/internal/c/libqb/src/mac-key-monitor.h new file mode 100644 index 000000000..b6f20581b --- /dev/null +++ b/internal/c/libqb/src/mac-key-monitor.h @@ -0,0 +1,10 @@ +#ifndef INCLUDE_INTERNAL_MAC_KEY_MONITOR_H +#define INCLUDE_INTERNAL_MAC_KEY_MONITOR_H + +#ifdef QB64_MACOSX +void mac_register_key_handler(); +#else +static inline void mac_register_key_handler() { }; +#endif + +#endif diff --git a/internal/c/libqb/src/mac-key-monitor.mm b/internal/c/libqb/src/mac-key-monitor.mm new file mode 100644 index 000000000..0e6987ebb --- /dev/null +++ b/internal/c/libqb/src/mac-key-monitor.mm @@ -0,0 +1,85 @@ + +#include "libqb-common.h" + +#include +#include +#include +#include + +#include "Cocoa/Cocoa.h" +#include + +#include "keyhandler.h" +#include "mac-key-monitor.h" + +void mac_register_key_handler() +{ + [NSEvent addLocalMonitorForEventsMatchingMask:NSFlagsChangedMask + handler:^NSEvent *(NSEvent *event) { + // notes on bitfields: + // if ([event modifierFlags] == 131330) keydown_vk(VK+QBVK_LSHIFT);// 100000000100000010 + // if ([event modifierFlags] == 131332) keydown_vk(VK+QBVK_RSHIFT);// 100000000100000100 + // if ([event modifierFlags] == 262401) keydown_vk(VK+QBVK_LCTRL); //1000000000100000001 + // if ([event modifierFlags] == 270592) keydown_vk(VK+QBVK_RCTRL); //1000010000100000000 + // if ([event modifierFlags] == 524576) keydown_vk(VK+QBVK_LALT); //10000000000100100000 + // if ([event modifierFlags] == 524608) keydown_vk(VK+QBVK_RALT); //10000000000101000000 + // caps lock // 10000000100000000 + + int x = [event modifierFlags]; + + if (x & (1 << 0)) { + if (!keyheld(VK + QBVK_LCTRL)) + keydown_vk(VK + QBVK_LCTRL); + } else { + if (keyheld(VK + QBVK_LCTRL)) + keyup_vk(VK + QBVK_LCTRL); + } + if (x & (1 << 13)) { + if (!keyheld(VK + QBVK_RCTRL)) + keydown_vk(VK + QBVK_RCTRL); + } else { + if (keyheld(VK + QBVK_RCTRL)) + keyup_vk(VK + QBVK_RCTRL); + } + + if (x & (1 << 1)) { + if (!keyheld(VK + QBVK_LSHIFT)) + keydown_vk(VK + QBVK_LSHIFT); + } else { + if (keyheld(VK + QBVK_LSHIFT)) + keyup_vk(VK + QBVK_LSHIFT); + } + if (x & (1 << 2)) { + if (!keyheld(VK + QBVK_RSHIFT)) + keydown_vk(VK + QBVK_RSHIFT); + } else { + if (keyheld(VK + QBVK_RSHIFT)) + keyup_vk(VK + QBVK_RSHIFT); + } + + if (x & (1 << 5)) { + if (!keyheld(VK + QBVK_LALT)) + keydown_vk(VK + QBVK_LALT); + } else { + if (keyheld(VK + QBVK_LALT)) + keyup_vk(VK + QBVK_LALT); + } + if (x & (1 << 6)) { + if (!keyheld(VK + QBVK_RALT)) + keydown_vk(VK + QBVK_RALT); + } else { + if (keyheld(VK + QBVK_RALT)) + keyup_vk(VK + QBVK_RALT); + } + + if (x & (1 << 16)) { + if (!keyheld(VK + QBVK_CAPSLOCK)) + keydown_vk(VK + QBVK_CAPSLOCK); + } else { + if (keyheld(VK + QBVK_CAPSLOCK)) + keyup_vk(VK + QBVK_CAPSLOCK); + } + + return event; + }]; +} diff --git a/internal/c/parts/core/build.mk b/internal/c/parts/core/build.mk index 6a7cc2b05..6a8e9b765 100644 --- a/internal/c/parts/core/build.mk +++ b/internal/c/parts/core/build.mk @@ -12,5 +12,7 @@ $(FREEGLUT_LIB): $(FREEGLUT_OBJS) QB_CORE_LIB := $(FREEGLUT_LIB) +CXXFLAGS += -I$(PATH_INTERNAL_C)/parts/core/src/ -I$(PATH_INTERNAL_C)/parts/core/glew/include/ + CLEAN_LIST += $(FREEGLUT_LIB) $(FREEGLUT_OBJS)