1
1
Fork 0
mirror of https://github.com/QB64-Phoenix-Edition/QB64pe.git synced 2024-09-20 03:14:45 +00:00

Add support for _MOUSEWHEEL and _MOUSEMOVEMENTx on macOS

This commit is contained in:
a740g 2024-03-09 21:55:34 +05:30
parent c7e912ace6
commit 787c9579b6
6 changed files with 123 additions and 27 deletions

View file

@ -155,7 +155,7 @@ ifeq ($(OS),win)
endif
ifeq ($(OS),osx)
CXXLIBS += -framework OpenGL -framework IOKit -framework GLUT -framework Cocoa
CXXLIBS += -framework OpenGL -framework IOKit -framework GLUT -framework Cocoa -framework ApplicationServices
# OSX doesn't strip using objcopy, so we're using `-s` instead
ifneq ($(STRIP_SYMBOLS),n)

View file

@ -29582,11 +29582,19 @@ void GLUT_MOUSE_FUNC(int glut_button, int state, int x, int y) {
# endif
}
// This is used to save the last mouse position which is then paired with the mouse wheel event on macOS
int g_MouseX = 0;
int g_MouseY = 0;
void GLUT_MOTION_FUNC(int x, int y) {
int32 i, last_i;
int32 handle;
int32 xrel, yrel;
g_MouseX = x;
g_MouseY = y;
handle = mouse_message_queue_first;
mouse_message_queue_struct *queue = (mouse_message_queue_struct *)list_get(mouse_message_queue_handles, handle);
@ -29601,12 +29609,14 @@ void GLUT_MOTION_FUNC(int x, int y) {
nextIndex = 0;
queue->current = nextIndex;
}
# ifdef QB64_WINDOWS
# if defined(QB64_WINDOWS) || defined(QB64_MACOSX)
// Windows calculates relative movement by intercepting WM_INPUT events
// instead
// macOS uses the Quartz Event Services to get relative movements
xrel = 0;
yrel = 0;
# else
// TODO: This needs to be correctly implemented on Linux
xrel = x - queue->queue[queue->last].x;
yrel = y - queue->queue[queue->last].y;
# endif

View file

@ -34,7 +34,7 @@ libqb-objs-y$(DEP_CONSOLE_ONLY) += $(PATH_LIBQB)/src/glut-msg-queue.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
libqb-objs-y$(DEP_CONSOLE_ONLY) += $(PATH_LIBQB)/src/mac-key-monitor.o $(PATH_LIBQB)/src/mac-mouse-support.o
endif
$(PATH_LIBQB)/src/%.o: $(PATH_LIBQB)/src/%.cpp

View file

@ -1,14 +1,14 @@
#include "libqb-common.h"
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <GL/glew.h>
#include <list>
#include <queue>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <unordered_map>
#include "GL/glew.h"
// note: MacOSX uses Apple's GLUT not FreeGLUT
#ifdef QB64_MACOSX
@ -18,12 +18,13 @@
# include <GL/freeglut.h>
#endif
#include "mutex.h"
#include "thread.h"
#include "completion.h"
#include "glut-thread.h"
#include "gui.h"
#include "mac-key-monitor.h"
#include "glut-thread.h"
#include "mac-mouse-support.h"
#include "mutex.h"
#include "thread.h"
// FIXME: These extern variable and function definitions should probably go
// somewhere more global so that they can be referenced by libqb.cpp
@ -114,6 +115,10 @@ static void initialize_glut(int argc, char **argv) {
#ifdef CORE_FREEGLUT
glutMouseWheelFunc(GLUT_MOUSEWHEEL_FUNC);
#endif
#ifdef QB64_MACOSX
macMouseInit();
#endif
}
static bool glut_is_started;
@ -136,9 +141,7 @@ void libqb_start_glut_thread() {
}
// Checks whether the GLUT thread is running
bool libqb_is_glut_up() {
return glut_is_started;
}
bool libqb_is_glut_up() { return glut_is_started; }
void libqb_glut_presetup(int argc, char **argv) {
if (!screen_hide) {
@ -178,8 +181,11 @@ void libqb_start_main_thread(int argc, char **argv) {
// from two threads at the same time).
//
// This is accomplished by simply queuing a GLUT message that calls exit() for us.
void libqb_exit(int exitcode)
{
void libqb_exit(int exitcode) {
#ifdef QB64_MACOSX
macMouseDone();
#endif
// If GLUT isn't running then we're free to do the exit() call from here
if (!libqb_is_glut_up())
exit(exitcode);

View file

@ -0,0 +1,74 @@
// Mouse support functions for macOS
// These are required to overcome the limitations of GLUT
#include "libqb-common.h"
#include "mac-mouse-support.h"
#include <ApplicationServices/ApplicationServices.h>
#include <GLUT/glut.h>
#include <unistd.h>
#define QB64_EVENT_CLOSE 1
#define QB64_EVENT_KEY 2
#define QB64_EVENT_RELATIVE_MOUSE_MOVEMENT 3
#define QB64_EVENT_FILE_DROP 4
extern "C" int qb64_custom_event(int event, int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, void *p1, void *p2);
void GLUT_MOUSEWHEEL_FUNC(int wheel, int direction, int x, int y);
extern int g_MouseX, g_MouseY;
static CFMachPortRef g_EventTap = nullptr;
static CFRunLoopSourceRef g_RunLoopSource = nullptr;
static CGEventRef macMouseCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *userInfo) {
auto appPID = reinterpret_cast<int64_t>(userInfo);
if (CGEventGetIntegerValueField(event, kCGEventTargetUnixProcessID) == appPID) {
if (type == kCGEventScrollWheel) {
auto deltaScroll = CGEventGetIntegerValueField(event, kCGScrollWheelEventPointDeltaAxis1);
GLUT_MOUSEWHEEL_FUNC(0, deltaScroll, g_MouseX, g_MouseY);
} else {
auto deltaX = CGEventGetIntegerValueField(event, kCGMouseEventDeltaX);
auto deltaY = CGEventGetIntegerValueField(event, kCGMouseEventDeltaY);
if (deltaX || deltaY)
qb64_custom_event(QB64_EVENT_RELATIVE_MOUSE_MOVEMENT, deltaX, deltaY, 0, 0, 0, 0, 0, 0, nullptr, nullptr);
}
}
return event;
}
void macMouseInit() {
if (!g_EventTap) {
CGEventMask eventMask = CGEventMaskBit(kCGEventLeftMouseDown) | CGEventMaskBit(kCGEventLeftMouseUp) | CGEventMaskBit(kCGEventRightMouseDown) |
CGEventMaskBit(kCGEventRightMouseUp) | CGEventMaskBit(kCGEventMouseMoved) | CGEventMaskBit(kCGEventLeftMouseDragged) |
CGEventMaskBit(kCGEventRightMouseDragged) | CGEventMaskBit(kCGEventScrollWheel) | CGEventMaskBit(kCGEventOtherMouseDown) |
CGEventMaskBit(kCGEventOtherMouseUp) | CGEventMaskBit(kCGEventOtherMouseDragged);
g_EventTap = CGEventTapCreate(kCGAnnotatedSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly, eventMask, macMouseCallback,
reinterpret_cast<void *>(getpid()));
if (g_EventTap) {
g_RunLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, g_EventTap, 0);
if (g_RunLoopSource) {
CFRunLoopAddSource(CFRunLoopGetCurrent(), g_RunLoopSource, kCFRunLoopCommonModes);
CGEventTapEnable(g_EventTap, true);
} else {
CFRelease(g_EventTap);
}
}
}
}
void macMouseDone() {
if (g_EventTap) {
CGEventTapEnable(g_EventTap, false);
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), g_RunLoopSource, kCFRunLoopCommonModes);
CFRelease(g_RunLoopSource);
CFRelease(g_EventTap);
g_RunLoopSource = nullptr;
g_EventTap = nullptr;
}
}

View file

@ -0,0 +1,6 @@
#pragma once
#ifdef QB64_MACOSX
void macMouseInit();
void macMouseDone();
#endif