summaryrefslogtreecommitdiff
path: root/src/video/cocoa
diff options
context:
space:
mode:
authorMichael Lutz <michi@icosahedron.de>2021-02-06 02:49:09 +0100
committerMichael Lutz <michi@icosahedron.de>2021-02-13 22:21:17 +0100
commitf4bd54fedd40806ff34d884c0fa17e0b7403ede1 (patch)
tree18bf9b2c89bef9a84888935060aa7739fc2c9658 /src/video/cocoa
parentbd42fc94cc1dc064d0c20cfa4fad108dc64931c6 (diff)
downloadopenttd-f4bd54fedd40806ff34d884c0fa17e0b7403ede1.tar.xz
Codechange: [OSX] Move mouse event handling to our NSView.
Diffstat (limited to 'src/video/cocoa')
-rw-r--r--src/video/cocoa/cocoa_v.h4
-rw-r--r--src/video/cocoa/cocoa_v.mm52
-rw-r--r--src/video/cocoa/cocoa_wnd.h8
-rw-r--r--src/video/cocoa/cocoa_wnd.mm147
-rw-r--r--src/video/cocoa/event.mm214
5 files changed, 154 insertions, 271 deletions
diff --git a/src/video/cocoa/cocoa_v.h b/src/video/cocoa/cocoa_v.h
index 4c53cdb8f..0112f5751 100644
--- a/src/video/cocoa/cocoa_v.h
+++ b/src/video/cocoa/cocoa_v.h
@@ -78,11 +78,7 @@ protected:
Dimension GetScreenSize() const override;
private:
- NSPoint GetMouseLocation(NSEvent *event);
- bool MouseIsInsideView(NSPoint *pt);
- CGPoint PrivateLocalToCG(NSPoint *p);
bool PollEvent(); // In event.mm.
- void MouseMovedEvent(int x, int y); // In event.mm.
bool IsFullscreen();
void GameSizeChanged();
diff --git a/src/video/cocoa/cocoa_v.mm b/src/video/cocoa/cocoa_v.mm
index 88f461234..07640a0f8 100644
--- a/src/video/cocoa/cocoa_v.mm
+++ b/src/video/cocoa/cocoa_v.mm
@@ -397,6 +397,7 @@ bool VideoDriver_Cocoa::MakeWindow(int width, int height)
[ this->window setContentView:this->cocoaview ];
[ this->cocoaview addSubview:draw_view ];
+ [ this->window makeFirstResponder:this->cocoaview ];
[ draw_view release ];
[ this->window setColorSpace:[ NSColorSpace sRGBColorSpace ] ];
@@ -497,57 +498,6 @@ void VideoDriver_Cocoa::UpdatePalette(uint first_color, uint num_colors)
this->num_dirty_rects = lengthof(this->dirty_rects);
}
-/**
- * Convert local coordinate to window server (CoreGraphics) coordinate
- * @param p local coordinates
- * @return window driver coordinates
- */
-CGPoint VideoDriver_Cocoa::PrivateLocalToCG(NSPoint *p)
-{
-
- p->y = this->window_height - p->y;
- *p = [ this->cocoaview convertPoint:*p toView:nil ];
- *p = [ this->window convertRectToScreen:NSMakeRect(p->x, p->y, 0, 0) ].origin;
-
- p->y = NSScreen.screens[0].frame.size.height - p->y;
-
- CGPoint cgp;
- cgp.x = p->x;
- cgp.y = p->y;
-
- return cgp;
-}
-
-/**
- * Return the mouse location
- * @param event UI event
- * @return mouse location as NSPoint
- */
-NSPoint VideoDriver_Cocoa::GetMouseLocation(NSEvent *event)
-{
- NSPoint pt;
-
- if ( [ event window ] == nil) {
- pt = [ this->cocoaview convertPoint:[ [ this->cocoaview window ] convertRectFromScreen:NSMakeRect([ event locationInWindow ].x, [ event locationInWindow ].y, 0, 0) ].origin fromView:nil ];
- } else {
- pt = [ event locationInWindow ];
- }
-
- pt.y = this->window_height - pt.y;
-
- return pt;
-}
-
-/**
- * Return whether the mouse is within our view
- * @param pt Mouse coordinates
- * @return Whether mouse coordinates are within view
- */
-bool VideoDriver_Cocoa::MouseIsInsideView(NSPoint *pt)
-{
- return [ cocoaview mouse:*pt inRect:[ this->cocoaview bounds ] ];
-}
-
/** Clear buffer to opaque black. */
static void ClearWindowBuffer(uint32 *buffer, uint32 pitch, uint32 height)
{
diff --git a/src/video/cocoa/cocoa_wnd.h b/src/video/cocoa/cocoa_wnd.h
index 449b457af..98ed7df7e 100644
--- a/src/video/cocoa/cocoa_wnd.h
+++ b/src/video/cocoa/cocoa_wnd.h
@@ -14,6 +14,13 @@
class VideoDriver_Cocoa;
+/* Right Mouse Button Emulation enum */
+enum RightMouseButtonEmulationState {
+ RMBE_COMMAND = 0,
+ RMBE_CONTROL = 1,
+ RMBE_OFF = 2,
+};
+
extern NSString *OTTDMainLaunchGameEngine;
/** Category of NSCursor to allow cursor showing/hiding */
@@ -34,6 +41,7 @@ extern NSString *OTTDMainLaunchGameEngine;
/** Subclass of NSView to support mouse awareness and text input. */
@interface OTTD_CocoaView : NSView <NSTextInputClient>
+- (NSPoint)mousePositionFromEvent:(NSEvent *)e;
@end
/** Delegate for our NSWindow to send ask for quit on close */
diff --git a/src/video/cocoa/cocoa_wnd.mm b/src/video/cocoa/cocoa_wnd.mm
index dd1d269f8..e9ea69705 100644
--- a/src/video/cocoa/cocoa_wnd.mm
+++ b/src/video/cocoa/cocoa_wnd.mm
@@ -27,6 +27,7 @@
#include "../../rev.h"
#include "cocoa_v.h"
#include "cocoa_wnd.h"
+#include "../../settings_type.h"
#include "../../string_func.h"
#include "../../gfx_func.h"
#include "../../window_func.h"
@@ -348,7 +349,6 @@ void CocoaDialog(const char *title, const char *message, const char *buttonLabel
self->driver = drv;
[ self setContentMinSize:NSMakeSize(64.0f, 64.0f) ];
- [ self setAcceptsMouseMovedEvents:YES ];
std::string caption = std::string{"OpenTTD "} + _openttd_revision;
NSString *nsscaption = [ [ NSString alloc ] initWithUTF8String:caption.c_str() ];
@@ -417,7 +417,9 @@ void CocoaDialog(const char *title, const char *message, const char *buttonLabel
@end
-@implementation OTTD_CocoaView
+@implementation OTTD_CocoaView {
+ float _current_magnification;
+}
/**
* Allow to handle events
@@ -451,7 +453,7 @@ void CocoaDialog(const char *title, const char *message, const char *buttonLabel
- (void)viewDidMoveToWindow
{
/* Install mouse tracking area. */
- NSTrackingAreaOptions track_opt = NSTrackingInVisibleRect | NSTrackingActiveInActiveApp | NSTrackingMouseEnteredAndExited | NSTrackingCursorUpdate;
+ NSTrackingAreaOptions track_opt = NSTrackingInVisibleRect | NSTrackingActiveInActiveApp | NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingCursorUpdate;
NSTrackingArea *track = [ [ NSTrackingArea alloc ] initWithRect:[ self bounds ] options:track_opt owner:self userInfo:nil ];
[ self addTrackingArea:track ];
[ track release ];
@@ -472,6 +474,145 @@ void CocoaDialog(const char *title, const char *message, const char *buttonLabel
_cursor.in_window = false;
}
+/**
+ * Return the mouse location
+ * @param event UI event
+ * @return mouse location as NSPoint
+ */
+- (NSPoint)mousePositionFromEvent:(NSEvent *)e
+{
+ NSPoint pt = e.locationInWindow;
+ if ([ e window ] == nil) pt = [ self.window convertRectFromScreen:NSMakeRect(pt.x, pt.y, 0, 0) ].origin;
+ pt = [ self convertPoint:pt fromView:nil ];
+
+ pt.y = self.bounds.size.height - pt.y;
+
+ return pt;
+}
+
+- (void)internalMouseMoveEvent:(NSEvent *)event
+{
+ NSPoint pt = [ self mousePositionFromEvent:event ];
+
+ if (_cursor.UpdateCursorPosition(pt.x, pt.y, false) && [ NSApp isActive ]) {
+ /* Warping cursor when in foreground */
+ NSPoint warp = [ self convertPoint:NSMakePoint(_cursor.pos.x, self.bounds.size.height - _cursor.pos.y) toView:nil ];
+ warp = [ self.window convertRectToScreen:NSMakeRect(warp.x, warp.y, 0, 0) ].origin;
+ warp.y = NSScreen.screens[0].frame.size.height - warp.y;
+
+ /* Do the actual warp */
+ CGWarpMouseCursorPosition(NSPointToCGPoint(warp));
+ /* this is the magic call that fixes cursor "freezing" after warp */
+ CGAssociateMouseAndMouseCursorPosition(true);
+ }
+ HandleMouseEvents();
+}
+
+- (BOOL)emulateRightButton:(NSEvent *)event
+{
+ uint32 keymask = 0;
+ if (_settings_client.gui.right_mouse_btn_emulation == RMBE_COMMAND) keymask |= NSCommandKeyMask;
+ if (_settings_client.gui.right_mouse_btn_emulation == RMBE_CONTROL) keymask |= NSControlKeyMask;
+
+ return (event.modifierFlags & keymask) != 0;
+}
+
+- (void)mouseMoved:(NSEvent *)event
+{
+ [ self internalMouseMoveEvent:event ];
+}
+
+- (void)mouseDragged:(NSEvent *)event
+{
+ [ self internalMouseMoveEvent:event ];
+}
+- (void)mouseDown:(NSEvent *)event
+{
+ if ([ self emulateRightButton:event ]) {
+ [ self rightMouseDown:event ];
+ } else {
+ _left_button_down = true;
+ [ self internalMouseMoveEvent:event ];
+ }
+}
+- (void)mouseUp:(NSEvent *)event
+{
+ if ([ self emulateRightButton:event ]) {
+ [ self rightMouseUp:event ];
+ } else {
+ _left_button_down = false;
+ _left_button_clicked = false;
+ [ self internalMouseMoveEvent:event ];
+ }
+}
+
+- (void)rightMouseDragged:(NSEvent *)event
+{
+ [ self internalMouseMoveEvent:event ];
+}
+- (void)rightMouseDown:(NSEvent *)event
+{
+ _right_button_down = true;
+ _right_button_clicked = true;
+ [ self internalMouseMoveEvent:event ];
+}
+- (void)rightMouseUp:(NSEvent *)event
+{
+ _right_button_down = false;
+ [ self internalMouseMoveEvent:event ];
+}
+
+- (void)scrollWheel:(NSEvent *)event
+{
+ if ([ event deltaY ] > 0.0) { /* Scroll up */
+ _cursor.wheel--;
+ } else if ([ event deltaY ] < 0.0) { /* Scroll down */
+ _cursor.wheel++;
+ } /* else: deltaY was 0.0 and we don't want to do anything */
+
+ /* Update the scroll count for 2D scrolling */
+ CGFloat deltaX;
+ CGFloat deltaY;
+
+ /* Use precise scrolling-specific deltas if they're supported. */
+ if ([ event respondsToSelector:@selector(hasPreciseScrollingDeltas) ]) {
+ /* No precise deltas indicates a scroll wheel is being used, so we don't want 2D scrolling. */
+ if (![ event hasPreciseScrollingDeltas ]) return;
+
+ deltaX = [ event scrollingDeltaX ] * 0.5f;
+ deltaY = [ event scrollingDeltaY ] * 0.5f;
+ } else {
+ deltaX = [ event deltaX ] * 5;
+ deltaY = [ event deltaY ] * 5;
+ }
+
+ _cursor.h_wheel -= (int)(deltaX * _settings_client.gui.scrollwheel_multiplier);
+ _cursor.v_wheel -= (int)(deltaY * _settings_client.gui.scrollwheel_multiplier);
+}
+
+- (void)magnifyWithEvent:(NSEvent *)event
+{
+ /* Pinch open or close gesture. */
+ self->_current_magnification += [ event magnification ] * 5.0f;
+
+ while (self->_current_magnification >= 1.0f) {
+ self->_current_magnification -= 1.0f;
+ _cursor.wheel--;
+ HandleMouseEvents();
+ }
+ while (self->_current_magnification <= -1.0f) {
+ self->_current_magnification += 1.0f;
+ _cursor.wheel++;
+ HandleMouseEvents();
+ }
+}
+
+- (void)endGestureWithEvent:(NSEvent *)event
+{
+ /* Gesture ended. */
+ self->_current_magnification = 0.0f;
+}
+
/** Insert the given text at the given range. */
- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange
diff --git a/src/video/cocoa/event.mm b/src/video/cocoa/event.mm
index 00559e6bc..d6c4e5552 100644
--- a/src/video/cocoa/event.mm
+++ b/src/video/cocoa/event.mm
@@ -27,6 +27,7 @@
#include "../../settings_type.h"
#include "../../core/geometry_type.hpp"
#include "cocoa_v.h"
+#include "cocoa_wnd.h"
#include "cocoa_keys.h"
#include "../../blitter/factory.hpp"
#include "../../gfx_func.h"
@@ -48,18 +49,8 @@
*/
-/* Right Mouse Button Emulation enum */
-enum RightMouseButtonEmulationState {
- RMBE_COMMAND,
- RMBE_CONTROL,
- RMBE_OFF,
-};
-
-
static unsigned int _current_mods;
static bool _tab_is_down;
-static bool _emulating_right_button;
-static float _current_magnification;
#ifdef _DEBUG
static uint32 _tEvent;
#endif
@@ -300,47 +291,6 @@ static void QZ_DoUnsidedModifiers(unsigned int newMods)
_current_mods = newMods;
}
-void VideoDriver_Cocoa::MouseMovedEvent(int x, int y)
-{
- if (_cursor.UpdateCursorPosition(x, y, false) && [ NSApp isActive ]) {
- /* Warping cursor when in foreground */
- NSPoint p = NSMakePoint(_cursor.pos.x, _cursor.pos.y);
- CGPoint cgp = this->PrivateLocalToCG(&p);
-
- /* Do the actual warp */
- CGWarpMouseCursorPosition(cgp);
- /* this is the magic call that fixes cursor "freezing" after warp */
- CGAssociateMouseAndMouseCursorPosition(true);
- }
- HandleMouseEvents();
-}
-
-
-static void QZ_MouseButtonEvent(int button, BOOL down)
-{
- switch (button) {
- case 0:
- if (down) {
- _left_button_down = true;
- } else {
- _left_button_down = false;
- _left_button_clicked = false;
- }
- HandleMouseEvents();
- break;
-
- case 1:
- if (down) {
- _right_button_down = true;
- _right_button_clicked = true;
- } else {
- _right_button_down = false;
- }
- HandleMouseEvents();
- break;
- }
-}
-
@@ -365,111 +315,7 @@ bool VideoDriver_Cocoa::PollEvent()
QZ_DoUnsidedModifiers( [ event modifierFlags ] );
NSString *chars;
- NSPoint pt;
switch ([ event type ]) {
- case NSMouseMoved:
- case NSOtherMouseDragged:
- case NSLeftMouseDragged:
- pt = this->GetMouseLocation(event);
- if (!this->MouseIsInsideView(&pt) && !_emulating_right_button) {
- [ NSApp sendEvent:event ];
- break;
- }
-
- this->MouseMovedEvent((int)pt.x, (int)pt.y);
- break;
-
- case NSRightMouseDragged:
- pt = this->GetMouseLocation(event);
- this->MouseMovedEvent((int)pt.x, (int)pt.y);
- break;
-
- case NSLeftMouseDown:
- {
- uint32 keymask = 0;
- if (_settings_client.gui.right_mouse_btn_emulation == RMBE_COMMAND) keymask |= NSCommandKeyMask;
- if (_settings_client.gui.right_mouse_btn_emulation == RMBE_CONTROL) keymask |= NSControlKeyMask;
-
- pt = this->GetMouseLocation(event);
-
- if (!([ event modifierFlags ] & keymask) || !this->MouseIsInsideView(&pt)) {
- [ NSApp sendEvent:event ];
- }
-
- this->MouseMovedEvent((int)pt.x, (int)pt.y);
-
- /* Right mouse button emulation */
- if ([ event modifierFlags ] & keymask) {
- _emulating_right_button = true;
- QZ_MouseButtonEvent(1, YES);
- } else {
- QZ_MouseButtonEvent(0, YES);
- }
- break;
- }
- case NSLeftMouseUp:
- [ NSApp sendEvent:event ];
-
- pt = this->GetMouseLocation(event);
-
- this->MouseMovedEvent((int)pt.x, (int)pt.y);
-
- /* Right mouse button emulation */
- if (_emulating_right_button) {
- _emulating_right_button = false;
- QZ_MouseButtonEvent(1, NO);
- } else {
- QZ_MouseButtonEvent(0, NO);
- }
- break;
-
- case NSRightMouseDown:
- pt = this->GetMouseLocation(event);
- if (!this->MouseIsInsideView(&pt)) {
- [ NSApp sendEvent:event ];
- break;
- }
-
- this->MouseMovedEvent((int)pt.x, (int)pt.y);
- QZ_MouseButtonEvent(1, YES);
- break;
-
- case NSRightMouseUp:
- pt = this->GetMouseLocation(event);
- if (!this->MouseIsInsideView(&pt)) {
- [ NSApp sendEvent:event ];
- break;
- }
-
- this->MouseMovedEvent((int)pt.x, (int)pt.y);
- QZ_MouseButtonEvent(1, NO);
- break;
-
-#if 0
- /* This is not needed since openttd currently only use two buttons */
- case NSOtherMouseDown:
- pt = QZ_GetMouseLocation(event);
- if (!QZ_MouseIsInsideView(&pt)) {
- [ NSApp sendEvent:event ];
- break;
- }
-
- this->MouseMovedEvent((int)pt.x, (int)pt.y);
- QZ_MouseButtonEvent([ event buttonNumber ], YES);
- break;
-
- case NSOtherMouseUp:
- pt = QZ_GetMouseLocation(event);
- if (!QZ_MouseIsInsideView(&pt)) {
- [ NSApp sendEvent:event ];
- break;
- }
-
- this->MouseMovedEvent((int)pt.x, (int)pt.y);
- QZ_MouseButtonEvent([ event buttonNumber ], NO);
- break;
-#endif
-
case NSKeyDown: {
/* Quit, hide and minimize */
switch ([ event keyCode ]) {
@@ -513,64 +359,6 @@ bool VideoDriver_Cocoa::PollEvent()
QZ_KeyEvent([ event keyCode ], [ chars length ] ? [ chars characterAtIndex:0 ] : 0, NO);
break;
- case NSScrollWheel:
- if ([ event deltaY ] > 0.0) { /* Scroll up */
- _cursor.wheel--;
- } else if ([ event deltaY ] < 0.0) { /* Scroll down */
- _cursor.wheel++;
- } /* else: deltaY was 0.0 and we don't want to do anything */
-
- /* Update the scroll count for 2D scrolling */
- CGFloat deltaX;
- CGFloat deltaY;
-
- /* Use precise scrolling-specific deltas if they're supported. */
- if ([event respondsToSelector:@selector(hasPreciseScrollingDeltas)]) {
- /* No precise deltas indicates a scroll wheel is being used, so we don't want 2D scrolling. */
- if (![ event hasPreciseScrollingDeltas ]) break;
-
- deltaX = [ event scrollingDeltaX ] * 0.5f;
- deltaY = [ event scrollingDeltaY ] * 0.5f;
- } else {
- deltaX = [ event deltaX ] * 5;
- deltaY = [ event deltaY ] * 5;
- }
-
- _cursor.h_wheel -= (int)(deltaX * _settings_client.gui.scrollwheel_multiplier);
- _cursor.v_wheel -= (int)(deltaY * _settings_client.gui.scrollwheel_multiplier);
-
- break;
-
- case NSEventTypeMagnify:
- /* Pinch open or close gesture. */
- _current_magnification += [ event magnification ] * 5.0f;
-
- while (_current_magnification >= 1.0f) {
- _current_magnification -= 1.0f;
- _cursor.wheel--;
- HandleMouseEvents();
- }
- while (_current_magnification <= -1.0f) {
- _current_magnification += 1.0f;
- _cursor.wheel++;
- HandleMouseEvents();
- }
- break;
-
- case NSEventTypeEndGesture:
- /* Gesture ended. */
- _current_magnification = 0.0f;
- break;
-
- case NSCursorUpdate:
- case NSMouseEntered:
- case NSMouseExited:
- /* Catch these events if the cursor is dragging. During dragging, we reset
- * the mouse position programmatically, which would trigger OS X to show
- * the default arrow cursor if the events are propagated. */
- if (_cursor.fix_at) break;
- FALLTHROUGH;
-
default:
[ NSApp sendEvent:event ];
}