1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <sal/macros.h>
23 #include <tools/helpers.hxx>
25 #include <vcl/event.hxx>
26 #include <vcl/inputctx.hxx>
27 #include <vcl/settings.hxx>
28 #include <vcl/svapp.hxx>
29 #include <vcl/window.hxx>
30 #include <vcl/commandevent.hxx>
32 #include <osx/a11yfactory.h>
33 #include <osx/salframe.h>
34 #include <osx/salframeview.h>
35 #include <osx/salinst.h>
36 #include <quartz/salgdi.h>
37 #include <quartz/utils.h>
39 #define WHEEL_EVENT_FACTOR 1.5
41 static sal_uInt16 ImplGetModifierMask( unsigned int nMask )
44 SAL_WNODEPRECATED_DECLARATIONS_PUSH
45 // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12
46 // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12
47 // 'NSControlKeyMask' is deprecated: first deprecated in macOS 10.12
48 // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12
49 if( (nMask & NSShiftKeyMask) != 0 )
51 if( (nMask & NSControlKeyMask) != 0 )
53 if( (nMask & NSAlternateKeyMask) != 0 )
55 if( (nMask & NSCommandKeyMask) != 0 )
57 SAL_WNODEPRECATED_DECLARATIONS_POP
61 static sal_uInt16 ImplMapCharCode( sal_Unicode aCode )
63 static sal_uInt16 aKeyCodeMap[ 128 ] =
65 0, 0, 0, 0, 0, 0, 0, 0,
66 KEY_BACKSPACE, KEY_TAB, KEY_RETURN, 0, 0, KEY_RETURN, 0, 0,
67 0, 0, 0, 0, 0, 0, 0, 0,
68 0, KEY_TAB, 0, KEY_ESCAPE, 0, 0, 0, 0,
69 KEY_SPACE, 0, 0, 0, 0, 0, 0, 0,
70 0, 0, KEY_MULTIPLY, KEY_ADD, KEY_COMMA, KEY_SUBTRACT, KEY_POINT, KEY_DIVIDE,
71 KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7,
72 KEY_8, KEY_9, 0, 0, KEY_LESS, KEY_EQUAL, KEY_GREATER, 0,
73 0, KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G,
74 KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O,
75 KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W,
76 KEY_X, KEY_Y, KEY_Z, 0, 0, 0, 0, 0,
77 KEY_QUOTELEFT, KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G,
78 KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O,
79 KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W,
80 KEY_X, KEY_Y, KEY_Z, 0, 0, 0, KEY_TILDE, KEY_BACKSPACE
83 // Note: the mapping 0x7f should by rights be KEY_DELETE
84 // however if you press "backspace" 0x7f is reported
85 // whereas for "delete" 0xf728 gets reported
87 // Note: the mapping of 0x19 to KEY_TAB is because for unknown reasons
88 // tab alone is reported as 0x09 (as expected) but shift-tab is
89 // reported as 0x19 (end of medium)
91 static sal_uInt16 aFunctionKeyCodeMap[ 128 ] =
93 KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_F1, KEY_F2, KEY_F3, KEY_F4,
94 KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12,
95 KEY_F13, KEY_F14, KEY_F15, KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20,
96 KEY_F21, KEY_F22, KEY_F23, KEY_F24, KEY_F25, KEY_F26, 0, 0,
97 0, 0, 0, 0, 0, 0, 0, KEY_INSERT,
98 KEY_DELETE, KEY_HOME, 0, KEY_END, KEY_PAGEUP, KEY_PAGEDOWN, 0, 0,
99 0, 0, 0, 0, 0, KEY_MENU, 0, 0,
100 0, 0, 0, 0, 0, 0, 0, 0,
101 0, 0, 0, KEY_UNDO, KEY_REPEAT, KEY_FIND, KEY_HELP, 0,
102 0, 0, 0, 0, 0, 0, 0, 0,
103 0, 0, 0, 0, 0, 0, 0, 0,
104 0, 0, 0, 0, 0, 0, 0, 0,
105 0, 0, 0, 0, 0, 0, 0, 0,
106 0, 0, 0, 0, 0, 0, 0, 0,
107 0, 0, 0, 0, 0, 0, 0, 0,
108 0, 0, 0, 0, 0, 0, 0, 0
111 sal_uInt16 nKeyCode = 0;
112 if( aCode < SAL_N_ELEMENTS( aKeyCodeMap) )
113 nKeyCode = aKeyCodeMap[ aCode ];
114 else if( aCode >= 0xf700 && aCode < 0xf780 )
115 nKeyCode = aFunctionKeyCodeMap[ aCode - 0xf700 ];
119 static sal_uInt16 ImplMapKeyCode(sal_uInt16 nKeyCode)
122 http://stackoverflow.com/questions/2080312/where-can-i-find-a-list-of-key-codes-for-use-with-cocoas-nsevent-class/2080324#2080324
123 /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h
126 static sal_uInt16 aKeyCodeMap[ 0x80 ] =
128 KEY_A, KEY_S, KEY_D, KEY_F, KEY_H, KEY_G, KEY_Z, KEY_X,
129 KEY_C, KEY_V, 0, KEY_B, KEY_Q, KEY_W, KEY_E, KEY_R,
130 KEY_Y, KEY_T, KEY_1, KEY_2, KEY_3, KEY_4, KEY_6, KEY_5,
131 KEY_EQUAL, KEY_9, KEY_7, KEY_SUBTRACT, KEY_8, KEY_0, KEY_BRACKETRIGHT, KEY_0,
132 KEY_U, KEY_BRACKETLEFT, KEY_I, KEY_P, KEY_RETURN, KEY_L, KEY_J, KEY_QUOTERIGHT,
133 KEY_K, KEY_SEMICOLON, 0, KEY_COMMA, KEY_DIVIDE, KEY_N, KEY_M, KEY_POINT,
134 KEY_TAB, KEY_SPACE, KEY_QUOTELEFT, KEY_DELETE, 0, KEY_ESCAPE, 0, 0,
135 0, KEY_CAPSLOCK, 0, 0, 0, 0, 0, 0,
136 KEY_F17, KEY_DECIMAL, 0, KEY_MULTIPLY, 0, KEY_ADD, 0, 0,
137 0, 0, 0, KEY_DIVIDE, KEY_RETURN, 0, KEY_SUBTRACT, KEY_F18,
138 KEY_F19, KEY_EQUAL, 0, 0, 0, 0, 0, 0,
139 0, 0, KEY_F20, 0, 0, 0, 0, 0,
140 KEY_F5, KEY_F6, KEY_F7, KEY_F3, KEY_F8, KEY_F9, 0, KEY_F11,
141 0, KEY_F13, KEY_F16, KEY_F14, 0, KEY_F10, 0, KEY_F12,
142 0, KEY_F15, KEY_HELP, KEY_HOME, KEY_PAGEUP, KEY_DELETE, KEY_F4, KEY_END,
143 KEY_F2, KEY_PAGEDOWN, KEY_F1, KEY_LEFT, KEY_RIGHT, KEY_DOWN, KEY_UP, 0
146 if (nKeyCode < SAL_N_ELEMENTS(aKeyCodeMap))
147 return aKeyCodeMap[nKeyCode];
151 // store the frame the mouse last entered
152 static AquaSalFrame* s_pMouseFrame = nullptr;
153 // store the last pressed button for enter/exit events
154 // which lack that information
155 static sal_uInt16 s_nLastButton = 0;
157 static AquaSalFrame* getMouseContainerFrame()
159 AquaSalFrame* pDispatchFrame = nullptr;
160 NSArray* aWindows = [NSWindow windowNumbersWithOptions:0];
161 for(NSUInteger i = 0; i < [aWindows count] && ! pDispatchFrame; i++ )
163 NSWindow* pWin = [NSApp windowWithWindowNumber:[[aWindows objectAtIndex:i] integerValue]];
164 if( pWin && [pWin isMemberOfClass: [SalFrameWindow class]] && [static_cast<SalFrameWindow*>(pWin) containsMouse] )
165 pDispatchFrame = [static_cast<SalFrameWindow*>(pWin) getSalFrame];
167 return pDispatchFrame;
170 @implementation SalFrameWindow
171 -(id)initWithSalFrame: (AquaSalFrame*)pFrame
173 mDraggingDestinationHandler = nil;
175 NSRect aRect = { { static_cast<CGFloat>(pFrame->maGeometry.nX), static_cast<CGFloat>(pFrame->maGeometry.nY) },
176 { static_cast<CGFloat>(pFrame->maGeometry.nWidth), static_cast<CGFloat>(pFrame->maGeometry.nHeight) } };
177 pFrame->VCLToCocoa( aRect );
178 NSWindow* pNSWindow = [super initWithContentRect: aRect
179 styleMask: mpFrame->getStyleMask()
180 backing: NSBackingStoreBuffered
181 defer: Application::IsHeadlessModeEnabled()];
183 // Disallow full-screen mode on macOS >= 10.11 where it is enabled by default. We don't want it
184 // for now as it will just be confused with LibreOffice's home-grown full-screen concept, with
185 // which it has nothing to do, and one can get into all kinds of weird states by using them
188 // Ideally we should use the system full-screen mode and adapt the code for the home-grown thing
189 // to be in sync with that instead. (And we would then not need the button to get out of
190 // full-screen mode, as the normal way to get out of it is to either click on the green bubble
191 // again, or invoke the keyboard command again.)
193 // (Confusingly, at the moment the home-grown full-screen mode is bound to Cmd+Shift+F, which is
194 // the keyboard command normally used in apps to get in and out of the system full-screen mode.)
196 // Disabling system full-screen mode makes the green button on the title bar (on macOS >= 10.11)
197 // show a plus sign instead, and clicking it becomes identical to double-clicking the title bar,
198 // i.e. it maximizes / unmaximises the window. Sure, that state can also be confused with LO's
199 // home-grown full-screen mode. Oh well.
201 [pNSWindow setCollectionBehavior: NSWindowCollectionBehaviorFullScreenNone];
203 // Disable window restoration until we support it directly
204 [pNSWindow setRestorable: NO];
206 return static_cast<SalFrameWindow *>(pNSWindow);
209 -(AquaSalFrame*)getSalFrame
214 -(void)displayIfNeeded
216 if( GetSalData() && GetSalData()->mpInstance )
218 SolarMutexGuard aGuard;
219 [super displayIfNeeded];
225 // is this event actually inside that NSWindow ?
226 NSPoint aPt = [NSEvent mouseLocation];
227 NSRect aFrameRect = [self frame];
228 BOOL bInRect = NSPointInRect( aPt, aFrameRect );
232 -(BOOL)canBecomeKeyWindow
234 if( (mpFrame->mnStyle &
235 ( SalFrameStyleFlags::FLOAT |
236 SalFrameStyleFlags::TOOLTIP |
237 SalFrameStyleFlags::INTRO
238 )) == SalFrameStyleFlags::NONE )
240 if( mpFrame->mnStyle & SalFrameStyleFlags::OWNERDRAWDECORATION )
242 if( mpFrame->mbFullScreen )
244 return [super canBecomeKeyWindow];
247 -(void)windowDidBecomeKey: (NSNotification*)pNotification
250 SolarMutexGuard aGuard;
252 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
254 static const SalFrameStyleFlags nGuessDocument = SalFrameStyleFlags::MOVEABLE|
255 SalFrameStyleFlags::SIZEABLE|
256 SalFrameStyleFlags::CLOSEABLE;
258 if( mpFrame->mpMenu )
259 mpFrame->mpMenu->setMainMenu();
260 else if( ! mpFrame->mpParent &&
261 ( (mpFrame->mnStyle & nGuessDocument) == nGuessDocument || // set default menu for e.g. help
262 mpFrame->mbFullScreen ) ) // set default menu for e.g. presentation
264 AquaSalMenu::setDefaultMenu();
267 // FIXME: we should disable menus while in modal mode
268 // however from down here there is currently no reliable way to
269 // find out when to do this
270 if( (mpFrame->mpParent && mpFrame->mpParent->GetWindow()->IsInModalMode()) )
271 AquaSalMenu::enableMainMenu( false );
273 mpFrame->CallCallback( SalEvent::GetFocus, nullptr );
274 mpFrame->SendPaintEvent(); // repaint controls as active
278 -(void)windowDidResignKey: (NSNotification*)pNotification
281 SolarMutexGuard aGuard;
283 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
285 mpFrame->CallCallback(SalEvent::LoseFocus, nullptr);
286 mpFrame->SendPaintEvent(); // repaint controls as inactive
290 -(void)windowDidChangeScreen: (NSNotification*)pNotification
293 SolarMutexGuard aGuard;
295 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
296 mpFrame->screenParametersChanged();
299 -(void)windowDidMove: (NSNotification*)pNotification
302 SolarMutexGuard aGuard;
304 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
306 mpFrame->UpdateFrameGeometry();
307 mpFrame->CallCallback( SalEvent::Move, nullptr );
311 -(void)windowDidResize: (NSNotification*)pNotification
314 SolarMutexGuard aGuard;
316 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
318 mpFrame->UpdateFrameGeometry();
319 mpFrame->CallCallback( SalEvent::Resize, nullptr );
320 mpFrame->SendPaintEvent();
324 -(void)windowDidMiniaturize: (NSNotification*)pNotification
327 SolarMutexGuard aGuard;
329 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
331 mpFrame->mbShown = false;
332 mpFrame->UpdateFrameGeometry();
333 mpFrame->CallCallback( SalEvent::Resize, nullptr );
337 -(void)windowDidDeminiaturize: (NSNotification*)pNotification
340 SolarMutexGuard aGuard;
342 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
344 mpFrame->mbShown = true;
345 mpFrame->UpdateFrameGeometry();
346 mpFrame->CallCallback( SalEvent::Resize, nullptr );
350 -(BOOL)windowShouldClose: (NSNotification*)pNotification
353 SolarMutexGuard aGuard;
356 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
358 // #i84461# end possible input
359 mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
360 if( AquaSalFrame::isAlive( mpFrame ) )
362 mpFrame->CallCallback( SalEvent::Close, nullptr );
363 bRet = NO; // application will close the window or not, AppKit shouldn't
364 AquaSalTimer *pTimer = static_cast<AquaSalTimer*>( ImplGetSVData()->maSchedCtx.mpSalTimer );
366 pTimer->handleWindowShouldClose();
373 -(void)windowDidEnterFullScreen: (NSNotification*)pNotification
375 SolarMutexGuard aGuard;
377 if( !mpFrame || !AquaSalFrame::isAlive( mpFrame))
379 mpFrame->mbFullScreen = true;
383 -(void)windowDidExitFullScreen: (NSNotification*)pNotification
385 SolarMutexGuard aGuard;
387 if( !mpFrame || !AquaSalFrame::isAlive( mpFrame))
389 mpFrame->mbFullScreen = false;
393 -(void)dockMenuItemTriggered: (id)sender
396 SolarMutexGuard aGuard;
398 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
399 mpFrame->ToTop( SalFrameToTop::RestoreWhenMin | SalFrameToTop::GrabFocus );
402 -(css::uno::Reference < css::accessibility::XAccessibleContext >)accessibleContext
404 return mpFrame -> GetWindow() -> GetAccessible() -> getAccessibleContext();
407 -(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
409 return [mDraggingDestinationHandler draggingEntered: sender];
412 -(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
414 return [mDraggingDestinationHandler draggingUpdated: sender];
417 -(void)draggingExited:(id <NSDraggingInfo>)sender
419 [mDraggingDestinationHandler draggingExited: sender];
422 -(BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
424 return [mDraggingDestinationHandler prepareForDragOperation: sender];
427 -(BOOL)performDragOperation:(id <NSDraggingInfo>)sender
429 return [mDraggingDestinationHandler performDragOperation: sender];
432 -(void)concludeDragOperation:(id <NSDraggingInfo>)sender
434 [mDraggingDestinationHandler concludeDragOperation: sender];
437 -(void)registerDraggingDestinationHandler:(id)theHandler
439 mDraggingDestinationHandler = theHandler;
442 -(void)unregisterDraggingDestinationHandler:(id)theHandler
445 mDraggingDestinationHandler = nil;
450 @implementation SalFrameView
451 +(void)unsetMouseFrame: (AquaSalFrame*)pFrame
453 if( pFrame == s_pMouseFrame )
454 s_pMouseFrame = nullptr;
457 -(id)initWithSalFrame: (AquaSalFrame*)pFrame
459 if ((self = [super initWithFrame: [NSWindow contentRectForFrameRect: [pFrame->getNSWindow() frame] styleMask: pFrame->mnStyleMask]]) != nil)
461 mDraggingDestinationHandler = nil;
463 mMarkedRange = NSMakeRange(NSNotFound, 0);
464 mSelectedRange = NSMakeRange(NSNotFound, 0);
465 mpReferenceWrapper = nil;
466 mpMouseEventListener = nil;
467 mpLastSuperEvent = nil;
470 mfLastMagnifyTime = 0.0;
474 -(AquaSalFrame*)getSalFrame
479 -(void)resetCursorRects
481 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
483 // FIXME: does this leak the returned NSCursor of getCurrentCursor ?
484 const NSRect aRect = { NSZeroPoint, NSMakeSize( mpFrame->maGeometry.nWidth, mpFrame->maGeometry.nHeight) };
485 [self addCursorRect: aRect cursor: mpFrame->getCurrentCursor()];
489 -(BOOL)acceptsFirstResponder
494 -(BOOL)acceptsFirstMouse: (NSEvent*)pEvent
504 if( !AquaSalFrame::isAlive( mpFrame))
506 if( !mpFrame->getClipPath())
511 -(void)drawRect: (NSRect)aRect
513 AquaSalInstance *pInstance = GetSalData()->mpInstance;
518 SolarMutexGuard aGuard;
519 if (!mpFrame || !AquaSalFrame::isAlive(mpFrame))
522 const bool bIsLiveResize = [self inLiveResize];
523 const bool bWasLiveResize = pInstance->mbIsLiveResize;
524 if (bWasLiveResize != bIsLiveResize)
526 pInstance->mbIsLiveResize = bIsLiveResize;
527 Scheduler::ProcessTaskScheduling();
530 AquaSalGraphics* pGraphics = mpFrame->mpGraphics;
533 pGraphics->UpdateWindow(aRect);
534 if (mpFrame->getClipPath())
535 [mpFrame->getNSWindow() invalidateShadow];
539 -(void)sendMouseEventToFrame: (NSEvent*)pEvent button:(sal_uInt16)nButton eventtype:(SalEvent)nEvent
541 SolarMutexGuard aGuard;
543 AquaSalFrame* pDispatchFrame = AquaSalFrame::GetCaptureFrame();
544 bool bIsCaptured = false;
548 if( nEvent == SalEvent::MouseLeave ) // no leave events if mouse is captured
549 nEvent = SalEvent::MouseMove;
551 else if( s_pMouseFrame )
552 pDispatchFrame = s_pMouseFrame;
554 pDispatchFrame = mpFrame;
556 /* #i81645# Cocoa reports mouse events while a button is pressed
557 to the window in which it was first pressed. This is reasonable and fine and
558 gets one around most cases where on other platforms one uses CaptureMouse or XGrabPointer,
559 however vcl expects mouse events to occur in the window the mouse is over, unless the
560 mouse is explicitly captured. So we need to find the window the mouse is actually
561 over for conformance with other platforms.
563 if( ! bIsCaptured && nButton && pDispatchFrame && AquaSalFrame::isAlive( pDispatchFrame ) )
565 // is this event actually inside that NSWindow ?
566 NSPoint aPt = [NSEvent mouseLocation];
567 NSRect aFrameRect = [pDispatchFrame->getNSWindow() frame];
569 if ( ! NSPointInRect( aPt, aFrameRect ) )
572 // now we need to find the one it may be in
573 /* #i93756# we ant to get enumerate the application windows in z-order
574 to check if any contains the mouse. This could be elegantly done with this
577 // use NSApp to check windows in ZOrder whether they contain the mouse pointer
578 NSWindow* pWindow = [NSApp makeWindowsPerform: @selector(containsMouse) inOrder: YES];
579 if( pWindow && [pWindow isMemberOfClass: [SalFrameWindow class]] )
580 pDispatchFrame = [(SalFrameWindow*)pWindow getSalFrame];
582 However if a non SalFrameWindow is on screen (like e.g. the file dialog)
583 it can be hit with the containsMouse selector, which it doesn't support.
584 Sadly NSApplication:makeWindowsPerform does not check (for performance reasons
585 I assume) whether a window supports a selector before sending it.
587 AquaSalFrame* pMouseFrame = getMouseContainerFrame();
589 pDispatchFrame = pMouseFrame;
593 if( pDispatchFrame && AquaSalFrame::isAlive( pDispatchFrame ) )
595 pDispatchFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
596 pDispatchFrame->mnLastModifierFlags = [pEvent modifierFlags];
598 NSPoint aPt = [NSEvent mouseLocation];
599 pDispatchFrame->CocoaToVCL( aPt );
601 sal_uInt16 nModMask = ImplGetModifierMask( [pEvent modifierFlags] );
602 // #i82284# emulate ctrl left
603 if( nModMask == KEY_MOD3 && nButton == MOUSE_LEFT )
606 nButton = MOUSE_RIGHT;
609 SalMouseEvent aEvent;
610 aEvent.mnTime = pDispatchFrame->mnLastEventTime;
611 aEvent.mnX = static_cast<long>(aPt.x) - pDispatchFrame->maGeometry.nX;
612 aEvent.mnY = static_cast<long>(aPt.y) - pDispatchFrame->maGeometry.nY;
613 aEvent.mnButton = nButton;
614 aEvent.mnCode = aEvent.mnButton | nModMask;
616 if( AllSettings::GetLayoutRTL() )
617 aEvent.mnX = pDispatchFrame->maGeometry.nWidth-1-aEvent.mnX;
619 pDispatchFrame->CallCallback( nEvent, &aEvent );
623 -(void)mouseDown: (NSEvent*)pEvent
625 if ( mpMouseEventListener != nil &&
626 [mpMouseEventListener respondsToSelector: @selector(mouseDown:)])
628 [mpMouseEventListener mouseDown: [pEvent copyWithZone: nullptr]];
631 s_nLastButton = MOUSE_LEFT;
632 [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SalEvent::MouseButtonDown];
635 -(void)mouseDragged: (NSEvent*)pEvent
637 if ( mpMouseEventListener != nil &&
638 [mpMouseEventListener respondsToSelector: @selector(mouseDragged:)])
640 [mpMouseEventListener mouseDragged: [pEvent copyWithZone: nullptr]];
642 s_nLastButton = MOUSE_LEFT;
643 [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SalEvent::MouseMove];
646 -(void)mouseUp: (NSEvent*)pEvent
649 [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SalEvent::MouseButtonUp];
652 -(void)mouseMoved: (NSEvent*)pEvent
655 [self sendMouseEventToFrame:pEvent button:0 eventtype:SalEvent::MouseMove];
658 -(void)mouseEntered: (NSEvent*)pEvent
660 s_pMouseFrame = mpFrame;
662 // #i107215# the only mouse events we get when inactive are enter/exit
663 // actually we would like to have all of them, but better none than some
664 if( [NSApp isActive] )
665 [self sendMouseEventToFrame:pEvent button:s_nLastButton eventtype:SalEvent::MouseMove];
668 -(void)mouseExited: (NSEvent*)pEvent
670 if( s_pMouseFrame == mpFrame )
671 s_pMouseFrame = nullptr;
673 // #i107215# the only mouse events we get when inactive are enter/exit
674 // actually we would like to have all of them, but better none than some
675 if( [NSApp isActive] )
676 [self sendMouseEventToFrame:pEvent button:s_nLastButton eventtype:SalEvent::MouseLeave];
679 -(void)rightMouseDown: (NSEvent*)pEvent
681 s_nLastButton = MOUSE_RIGHT;
682 [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SalEvent::MouseButtonDown];
685 -(void)rightMouseDragged: (NSEvent*)pEvent
687 s_nLastButton = MOUSE_RIGHT;
688 [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SalEvent::MouseMove];
691 -(void)rightMouseUp: (NSEvent*)pEvent
694 [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SalEvent::MouseButtonUp];
697 -(void)otherMouseDown: (NSEvent*)pEvent
699 if( [pEvent buttonNumber] == 2 )
701 s_nLastButton = MOUSE_MIDDLE;
702 [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SalEvent::MouseButtonDown];
708 -(void)otherMouseDragged: (NSEvent*)pEvent
710 if( [pEvent buttonNumber] == 2 )
712 s_nLastButton = MOUSE_MIDDLE;
713 [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SalEvent::MouseMove];
719 -(void)otherMouseUp: (NSEvent*)pEvent
722 if( [pEvent buttonNumber] == 2 )
723 [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SalEvent::MouseButtonUp];
726 - (void)magnifyWithEvent: (NSEvent*)pEvent
728 SolarMutexGuard aGuard;
730 // TODO: ?? -(float)magnification;
731 if( AquaSalFrame::isAlive( mpFrame ) )
733 const NSTimeInterval fMagnifyTime = [pEvent timestamp];
734 mpFrame->mnLastEventTime = static_cast<sal_uInt64>( fMagnifyTime * 1000.0 );
735 mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
737 // check if this is a new series of magnify events
738 static const NSTimeInterval fMaxDiffTime = 0.3;
739 const bool bNewSeries = (fMagnifyTime - mfLastMagnifyTime > fMaxDiffTime);
742 mfMagnifyDeltaSum = 0.0;
743 mfMagnifyDeltaSum += [pEvent magnification];
745 mfLastMagnifyTime = [pEvent timestamp];
746 // TODO: change to 0.1 when CommandWheelMode::ZOOM handlers allow finer zooming control
747 static const float fMagnifyFactor = 0.25*500; // steps are 500 times smaller for -magnification
748 static const float fMinMagnifyStep = 15.0 / fMagnifyFactor;
749 if( fabs(mfMagnifyDeltaSum) <= fMinMagnifyStep )
752 // adapt NSEvent-sensitivity to application expectations
753 // TODO: rather make CommandWheelMode::ZOOM handlers smarter
754 const float fDeltaZ = mfMagnifyDeltaSum * fMagnifyFactor;
755 int nDeltaZ = FRound( fDeltaZ );
758 // handle new series immediately
761 nDeltaZ = (fDeltaZ >= 0.0) ? +1 : -1;
763 // eventually give credit for delta sum
764 mfMagnifyDeltaSum -= nDeltaZ / fMagnifyFactor;
766 NSPoint aPt = [NSEvent mouseLocation];
767 mpFrame->CocoaToVCL( aPt );
769 SalWheelMouseEvent aEvent;
770 aEvent.mnTime = mpFrame->mnLastEventTime;
771 aEvent.mnX = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX;
772 aEvent.mnY = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY;
773 aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
774 aEvent.mnCode |= KEY_MOD1; // we want zooming, no scrolling
775 aEvent.mbDeltaIsPixel = TRUE;
777 if( AllSettings::GetLayoutRTL() )
778 aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
780 aEvent.mnDelta = nDeltaZ;
781 aEvent.mnNotchDelta = (nDeltaZ >= 0) ? +1 : -1;
782 if( aEvent.mnDelta == 0 )
783 aEvent.mnDelta = aEvent.mnNotchDelta;
784 aEvent.mbHorz = FALSE;
785 sal_uInt32 nScrollLines = nDeltaZ;
786 if (nScrollLines == 0)
788 aEvent.mnScrollLines = nScrollLines;
789 mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent );
793 - (void)rotateWithEvent: (NSEvent*)pEvent
795 //Rotation : -(float)rotation;
796 // TODO: create new CommandType so rotation is available to the applications
800 - (void)swipeWithEvent: (NSEvent*)pEvent
802 SolarMutexGuard aGuard;
804 if( AquaSalFrame::isAlive( mpFrame ) )
806 mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
807 mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
809 // merge pending scroll wheel events
814 dX += [pEvent deltaX];
815 dY += [pEvent deltaY];
816 SAL_WNODEPRECATED_DECLARATIONS_PUSH
817 // 'NSScrollWheelMask' is deprecated: first deprecated in macOS 10.12
818 NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask
819 SAL_WNODEPRECATED_DECLARATIONS_POP
820 untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ];
826 NSPoint aPt = [NSEvent mouseLocation];
827 mpFrame->CocoaToVCL( aPt );
829 SalWheelMouseEvent aEvent;
830 aEvent.mnTime = mpFrame->mnLastEventTime;
831 aEvent.mnX = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX;
832 aEvent.mnY = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY;
833 aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
834 aEvent.mbDeltaIsPixel = TRUE;
836 if( AllSettings::GetLayoutRTL() )
837 aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
841 aEvent.mnDelta = static_cast<long>(floor(dX));
842 aEvent.mnNotchDelta = (dX < 0) ? -1 : +1;
843 if( aEvent.mnDelta == 0 )
844 aEvent.mnDelta = aEvent.mnNotchDelta;
845 aEvent.mbHorz = TRUE;
846 aEvent.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
847 mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent );
849 if( dY != 0.0 && AquaSalFrame::isAlive( mpFrame ))
851 aEvent.mnDelta = static_cast<long>(floor(dY));
852 aEvent.mnNotchDelta = (dY < 0) ? -1 : +1;
853 if( aEvent.mnDelta == 0 )
854 aEvent.mnDelta = aEvent.mnNotchDelta;
855 aEvent.mbHorz = FALSE;
856 aEvent.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
857 mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent );
862 -(void)scrollWheel: (NSEvent*)pEvent
864 SolarMutexGuard aGuard;
866 if( AquaSalFrame::isAlive( mpFrame ) )
868 mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
869 mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
871 // merge pending scroll wheel events
876 dX += [pEvent deltaX];
877 dY += [pEvent deltaY];
878 SAL_WNODEPRECATED_DECLARATIONS_PUSH
879 // 'NSScrollWheelMask' is deprecated: first deprecated in macOS 10.12
880 NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask
881 SAL_WNODEPRECATED_DECLARATIONS_POP
882 untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ];
888 NSPoint aPt = [NSEvent mouseLocation];
889 mpFrame->CocoaToVCL( aPt );
891 SalWheelMouseEvent aEvent;
892 aEvent.mnTime = mpFrame->mnLastEventTime;
893 aEvent.mnX = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX;
894 aEvent.mnY = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY;
895 aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
896 aEvent.mbDeltaIsPixel = FALSE;
898 if( AllSettings::GetLayoutRTL() )
899 aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
903 aEvent.mnDelta = static_cast<long>(floor(dX));
904 aEvent.mnNotchDelta = (dX < 0) ? -1 : +1;
905 if( aEvent.mnDelta == 0 )
906 aEvent.mnDelta = aEvent.mnNotchDelta;
907 aEvent.mbHorz = TRUE;
908 sal_uInt32 nScrollLines = fabs(dX) / WHEEL_EVENT_FACTOR;
909 if (nScrollLines == 0)
911 aEvent.mnScrollLines = nScrollLines;
913 mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent );
915 if( dY != 0.0 && AquaSalFrame::isAlive( mpFrame ) )
917 aEvent.mnDelta = static_cast<long>(floor(dY));
918 aEvent.mnNotchDelta = (dY < 0) ? -1 : +1;
919 if( aEvent.mnDelta == 0 )
920 aEvent.mnDelta = aEvent.mnNotchDelta;
921 aEvent.mbHorz = FALSE;
922 sal_uInt32 nScrollLines = fabs(dY) / WHEEL_EVENT_FACTOR;
923 if (nScrollLines == 0)
925 aEvent.mnScrollLines = nScrollLines;
927 mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent );
933 -(void)keyDown: (NSEvent*)pEvent
935 SolarMutexGuard aGuard;
937 if( AquaSalFrame::isAlive( mpFrame ) )
939 mpLastEvent = pEvent;
941 mbNeedSpecialKeyHandle = false;
942 mbKeyHandled = false;
944 mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
945 mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
947 if( ! [self handleKeyDownException: pEvent] )
949 NSArray* pArray = [NSArray arrayWithObject: pEvent];
950 [self interpretKeyEvents: pArray];
953 mbInKeyInput = false;
957 -(BOOL)handleKeyDownException:(NSEvent*)pEvent
959 // check for a very special set of modified characters
960 NSString* pUnmodifiedString = [pEvent charactersIgnoringModifiers];
962 if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
964 /* #i103102# key events with command and alternate don't make it through
965 interpretKeyEvents (why?). Try to dispatch them here first,
966 if not successful continue normally
968 SAL_WNODEPRECATED_DECLARATIONS_PUSH
969 // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12
970 // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12
971 if( (mpFrame->mnLastModifierFlags & (NSAlternateKeyMask | NSCommandKeyMask))
972 == (NSAlternateKeyMask | NSCommandKeyMask) )
973 SAL_WNODEPRECATED_DECLARATIONS_POP
975 if( [self sendSingleCharacter: mpLastEvent] )
982 -(void)flagsChanged: (NSEvent*)pEvent
984 SolarMutexGuard aGuard;
986 if( AquaSalFrame::isAlive( mpFrame ) )
988 mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
989 mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
993 -(void)insertText:(id)aString replacementRange:(NSRange)replacementRange
995 (void) replacementRange; // FIXME: surely it must be used
997 SolarMutexGuard aGuard;
999 if( AquaSalFrame::isAlive( mpFrame ) )
1001 NSString* pInsert = nil;
1002 if( [aString isMemberOfClass: [NSAttributedString class]] )
1003 pInsert = [aString string];
1008 if( pInsert && ( nLen = [pInsert length] ) > 0 )
1010 OUString aInsertString( GetOUString( pInsert ) );
1011 // aCharCode initializer is safe since aInsertString will at least contain '\0'
1012 sal_Unicode aCharCode = *aInsertString.getStr();
1017 ! [self hasMarkedText ]
1020 sal_uInt16 nKeyCode = ImplMapCharCode( aCharCode );
1021 unsigned int nLastModifiers = mpFrame->mnLastModifierFlags;
1024 // find out the unmodified key code
1026 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1027 // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12
1028 // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12
1029 // 'NSControlKeyMask' is deprecated: first deprecated in macOS 10.12
1030 // 'NSKeyDown' is deprecated: first deprecated in macOS 10.12
1031 // 'NSKeyUp' is deprecated: first deprecated in macOS 10.12
1033 if( mpLastEvent && ( [mpLastEvent type] == NSKeyDown || [mpLastEvent type] == NSKeyUp ) )
1035 // get unmodified string
1036 NSString* pUnmodifiedString = [mpLastEvent charactersIgnoringModifiers];
1037 if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
1039 // map the unmodified key code
1040 unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
1041 nKeyCode = ImplMapCharCode( keyChar );
1043 nLastModifiers = [mpLastEvent modifierFlags];
1047 // applications and vcl's edit fields ignore key events with ALT
1048 // however we're at a place where we know text should be inserted
1049 // so it seems we need to strip the Alt modifier here
1050 if( (nLastModifiers & (NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask))
1051 == NSAlternateKeyMask )
1055 SAL_WNODEPRECATED_DECLARATIONS_POP
1056 [self sendKeyInputAndReleaseToFrame: nKeyCode character: aCharCode modifiers: nLastModifiers];
1060 SalExtTextInputEvent aEvent;
1061 aEvent.maText = aInsertString;
1062 aEvent.mpTextAttr = nullptr;
1063 aEvent.mnCursorPos = aInsertString.getLength();
1064 aEvent.mnCursorFlags = 0;
1065 mpFrame->CallCallback( SalEvent::ExtTextInput, &aEvent );
1066 if( AquaSalFrame::isAlive( mpFrame ) )
1067 mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
1072 SalExtTextInputEvent aEvent;
1073 aEvent.maText.clear();
1074 aEvent.mpTextAttr = nullptr;
1075 aEvent.mnCursorPos = 0;
1076 aEvent.mnCursorFlags = 0;
1077 mpFrame->CallCallback( SalEvent::ExtTextInput, &aEvent );
1078 if( AquaSalFrame::isAlive( mpFrame ) )
1079 mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
1082 mbKeyHandled = true;
1087 -(void)insertTab: (id)aSender
1090 [self sendKeyInputAndReleaseToFrame: KEY_TAB character: '\t' modifiers: 0];
1093 -(void)insertBacktab: (id)aSender
1096 [self sendKeyInputAndReleaseToFrame: (KEY_TAB | KEY_SHIFT) character: '\t' modifiers: 0];
1099 -(void)moveLeft: (id)aSender
1102 [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: 0];
1105 -(void)moveLeftAndModifySelection: (id)aSender
1108 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1109 // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12
1110 [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: NSShiftKeyMask];
1111 SAL_WNODEPRECATED_DECLARATIONS_POP
1114 -(void)moveBackwardAndModifySelection: (id)aSender
1117 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_BACKWARD character: 0 modifiers: 0];
1120 -(void)moveRight: (id)aSender
1123 [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: 0];
1126 -(void)moveRightAndModifySelection: (id)aSender
1129 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1130 // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12
1131 [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: NSShiftKeyMask];
1132 SAL_WNODEPRECATED_DECLARATIONS_POP
1135 -(void)moveForwardAndModifySelection: (id)aSender
1138 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_FORWARD character: 0 modifiers: 0];
1141 -(void)moveWordLeft: (id)aSender
1144 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_BACKWARD character: 0 modifiers: 0];
1147 -(void)moveWordBackward: (id)aSender
1150 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_BACKWARD character: 0 modifiers: 0];
1153 -(void)moveWordBackwardAndModifySelection: (id)aSender
1156 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_BACKWARD character: 0 modifiers: 0];
1159 -(void)moveWordLeftAndModifySelection: (id)aSender
1162 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_BACKWARD character: 0 modifiers: 0];
1165 -(void)moveWordRight: (id)aSender
1168 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_FORWARD character: 0 modifiers: 0];
1171 -(void)moveWordForward: (id)aSender
1174 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_FORWARD character: 0 modifiers: 0];
1177 -(void)moveWordForwardAndModifySelection: (id)aSender
1180 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_FORWARD character: 0 modifiers: 0];
1183 -(void)moveWordRightAndModifySelection: (id)aSender
1186 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_FORWARD character: 0 modifiers: 0];
1189 -(void)moveToEndOfLine: (id)aSender
1192 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_LINE character: 0 modifiers: 0];
1195 -(void)moveToRightEndOfLine: (id)aSender
1198 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_LINE character: 0 modifiers: 0];
1201 -(void)moveToEndOfLineAndModifySelection: (id)aSender
1204 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_LINE character: 0 modifiers: 0];
1207 -(void)moveToRightEndOfLineAndModifySelection: (id)aSender
1210 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_LINE character: 0 modifiers: 0];
1213 -(void)moveToBeginningOfLine: (id)aSender
1216 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
1219 -(void)moveToLeftEndOfLine: (id)aSender
1222 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
1225 -(void)moveToBeginningOfLineAndModifySelection: (id)aSender
1228 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
1231 -(void)moveToLeftEndOfLineAndModifySelection: (id)aSender
1234 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
1237 -(void)moveToEndOfParagraph: (id)aSender
1240 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
1243 -(void)moveToEndOfParagraphAndModifySelection: (id)aSender
1246 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
1249 -(void)moveParagraphForward: (id)aSender
1252 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
1255 -(void)moveParagraphForwardAndModifySelection: (id)aSender
1258 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
1261 -(void)moveToBeginningOfParagraph: (id)aSender
1264 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
1267 -(void)moveParagraphBackward: (id)aSender
1270 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
1273 -(void)moveToBeginningOfParagraphAndModifySelection: (id)aSender
1276 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
1279 -(void)moveParagraphBackwardAndModifySelection: (id)aSender
1282 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
1285 -(void)moveToEndOfDocument: (id)aSender
1288 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_DOCUMENT character: 0 modifiers: 0];
1291 -(void)scrollToEndOfDocument: (id)aSender
1294 // this is not exactly what we should do, but it makes "End" and "Shift-End" behave consistent
1295 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_DOCUMENT character: 0 modifiers: 0];
1298 -(void)moveToEndOfDocumentAndModifySelection: (id)aSender
1301 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_DOCUMENT character: 0 modifiers: 0];
1304 -(void)moveToBeginningOfDocument: (id)aSender
1307 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0];
1310 -(void)scrollToBeginningOfDocument: (id)aSender
1313 // this is not exactly what we should do, but it makes "Home" and "Shift-Home" behave consistent
1314 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0];
1317 -(void)moveToBeginningOfDocumentAndModifySelection: (id)aSender
1320 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0];
1323 -(void)moveUp: (id)aSender
1326 [self sendKeyInputAndReleaseToFrame: KEY_UP character: 0 modifiers: 0];
1329 -(void)moveDown: (id)aSender
1332 [self sendKeyInputAndReleaseToFrame: KEY_DOWN character: 0 modifiers: 0];
1335 -(void)insertNewline: (id)aSender
1338 // #i91267# make enter and shift-enter work by evaluating the modifiers
1339 [self sendKeyInputAndReleaseToFrame: KEY_RETURN character: '\n' modifiers: mpFrame->mnLastModifierFlags];
1342 -(void)deleteBackward: (id)aSender
1345 [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0];
1348 -(void)deleteForward: (id)aSender
1351 [self sendKeyInputAndReleaseToFrame: KEY_DELETE character: 0x7f modifiers: 0];
1354 -(void)deleteBackwardByDecomposingPreviousCharacter: (id)aSender
1357 [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0];
1360 -(void)deleteWordBackward: (id)aSender
1363 [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_WORD_BACKWARD character: 0 modifiers: 0];
1366 -(void)deleteWordForward: (id)aSender
1369 [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_WORD_FORWARD character: 0 modifiers: 0];
1372 -(void)deleteToBeginningOfLine: (id)aSender
1375 [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
1378 -(void)deleteToEndOfLine: (id)aSender
1381 [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_END_OF_LINE character: 0 modifiers: 0];
1384 -(void)deleteToBeginningOfParagraph: (id)aSender
1387 [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
1390 -(void)deleteToEndOfParagraph: (id)aSender
1393 [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
1396 -(void)insertLineBreak: (id)aSender
1399 [self sendKeyInputAndReleaseToFrame: css::awt::Key::INSERT_LINEBREAK character: 0 modifiers: 0];
1402 -(void)insertParagraphSeparator: (id)aSender
1405 [self sendKeyInputAndReleaseToFrame: css::awt::Key::INSERT_PARAGRAPH character: 0 modifiers: 0];
1408 -(void)selectWord: (id)aSender
1411 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD character: 0 modifiers: 0];
1414 -(void)selectLine: (id)aSender
1417 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_LINE character: 0 modifiers: 0];
1420 -(void)selectParagraph: (id)aSender
1423 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_PARAGRAPH character: 0 modifiers: 0];
1426 -(void)selectAll: (id)aSender
1429 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_ALL character: 0 modifiers: 0];
1432 -(void)cancelOperation: (id)aSender
1435 [self sendKeyInputAndReleaseToFrame: KEY_ESCAPE character: 0x1b modifiers: 0];
1438 -(void)noop: (id)aSender
1441 if( ! mbKeyHandled )
1443 if( ! [self sendSingleCharacter:mpLastEvent] )
1445 /* prevent recursion */
1446 if( mpLastEvent != mpLastSuperEvent && [NSApp respondsToSelector: @selector(sendSuperEvent:)] )
1448 id pLastSuperEvent = mpLastSuperEvent;
1449 mpLastSuperEvent = mpLastEvent;
1450 [NSApp performSelector:@selector(sendSuperEvent:) withObject: mpLastEvent];
1451 mpLastSuperEvent = pLastSuperEvent;
1453 std::map< NSEvent*, bool >::iterator it = GetSalData()->maKeyEventAnswer.find( mpLastEvent );
1454 if( it != GetSalData()->maKeyEventAnswer.end() )
1461 -(BOOL)sendKeyInputAndReleaseToFrame: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar
1463 return [self sendKeyInputAndReleaseToFrame: nKeyCode character: aChar modifiers: mpFrame->mnLastModifierFlags];
1466 -(BOOL)sendKeyInputAndReleaseToFrame: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod
1468 return [self sendKeyToFrameDirect: nKeyCode character: aChar modifiers: nMod] ||
1469 [self sendSingleCharacter: mpLastEvent];
1472 -(BOOL)sendKeyToFrameDirect: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod
1474 SolarMutexGuard aGuard;
1477 if( AquaSalFrame::isAlive( mpFrame ) )
1480 aEvent.mnCode = nKeyCode | ImplGetModifierMask( nMod );
1481 aEvent.mnCharCode = aChar;
1482 aEvent.mnRepeat = FALSE;
1483 nRet = mpFrame->CallCallback( SalEvent::KeyInput, &aEvent );
1484 std::map< NSEvent*, bool >::iterator it = GetSalData()->maKeyEventAnswer.find( mpLastEvent );
1485 if( it != GetSalData()->maKeyEventAnswer.end() )
1487 if( AquaSalFrame::isAlive( mpFrame ) )
1488 mpFrame->CallCallback( SalEvent::KeyUp, &aEvent );
1494 -(BOOL)sendSingleCharacter: (NSEvent *)pEvent
1496 NSString* pUnmodifiedString = [pEvent charactersIgnoringModifiers];
1498 if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
1500 unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
1501 sal_uInt16 nKeyCode = ImplMapCharCode( keyChar );
1504 sal_uInt16 nOtherKeyCode = [pEvent keyCode];
1505 nKeyCode = ImplMapKeyCode(nOtherKeyCode);
1509 // don't send code points in the private use area
1510 if( keyChar >= 0xf700 && keyChar < 0xf780 )
1512 BOOL bRet = [self sendKeyToFrameDirect: nKeyCode character: keyChar modifiers: mpFrame->mnLastModifierFlags];
1513 mbInKeyInput = false;
1522 // NSTextInput/NSTextInputClient protocol
1523 - (NSArray *)validAttributesForMarkedText
1525 return [NSArray arrayWithObjects:NSUnderlineStyleAttributeName, nil];
1528 - (BOOL)hasMarkedText
1530 BOOL bHasMarkedText;
1532 bHasMarkedText = ( mMarkedRange.location != NSNotFound ) &&
1533 ( mMarkedRange.length != 0 );
1534 // hack to check keys like "Control-j"
1537 mbNeedSpecialKeyHandle = true;
1542 // if we come here outside of mbInKeyInput, this is likely to be because
1543 // of the keyboard viewer. For unknown reasons having no marked range
1544 // in this case causes a crash. So we say we have a marked range anyway
1545 // This is a hack, since it is not understood what a) causes that crash
1546 // and b) why we should have a marked range at this point.
1547 if( ! mbInKeyInput )
1548 bHasMarkedText = YES;
1550 return bHasMarkedText;
1553 - (NSRange)markedRange
1557 // if we come here outside of mbInKeyInput, this is likely to be because
1558 // of the keyboard viewer. For unknown reasons having no marked range
1559 // in this case causes a crash. So we say we have a marked range anyway
1560 // This is a hack, since it is not understood what a) causes that crash
1561 // and b) why we should have a marked range at this point.
1562 if( ! mbInKeyInput )
1563 return NSMakeRange( 0, 0 );
1565 return [self hasMarkedText] ? mMarkedRange : NSMakeRange( NSNotFound, 0 );
1568 - (NSRange)selectedRange
1570 return mSelectedRange;
1573 - (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange replacementRange:(NSRange)replacementRange
1575 (void) replacementRange; // FIXME - use it!
1577 SolarMutexGuard aGuard;
1579 if( ![aString isKindOfClass:[NSAttributedString class]] )
1580 aString = [[[NSAttributedString alloc] initWithString:aString] autorelease];
1581 NSRange rangeToReplace = [self hasMarkedText] ? [self markedRange] : [self selectedRange];
1582 if( rangeToReplace.location == NSNotFound )
1584 mMarkedRange = NSMakeRange( selRange.location, [aString length] );
1585 mSelectedRange = NSMakeRange( selRange.location, selRange.length );
1589 mMarkedRange = NSMakeRange( rangeToReplace.location, [aString length] );
1590 mSelectedRange = NSMakeRange( rangeToReplace.location + selRange.location, selRange.length );
1593 int len = [aString length];
1594 SalExtTextInputEvent aInputEvent;
1596 NSString *pString = [aString string];
1597 OUString aInsertString( GetOUString( pString ) );
1598 std::vector<ExtTextInputAttr> aInputFlags( std::max( 1, len ), ExtTextInputAttr::NONE );
1599 for ( int i = 0; i < len; i++ )
1601 unsigned int nUnderlineValue;
1602 NSRange effectiveRange;
1604 effectiveRange = NSMakeRange(i, 1);
1605 nUnderlineValue = [[aString attribute:NSUnderlineStyleAttributeName atIndex:i effectiveRange:&effectiveRange] unsignedIntValue];
1607 switch (nUnderlineValue & 0xff) {
1608 case NSUnderlineStyleSingle:
1609 aInputFlags[i] = ExtTextInputAttr::Underline;
1611 case NSUnderlineStyleThick:
1612 aInputFlags[i] = ExtTextInputAttr::Underline | ExtTextInputAttr::Highlight;
1614 case NSUnderlineStyleDouble:
1615 aInputFlags[i] = ExtTextInputAttr::BoldUnderline;
1618 aInputFlags[i] = ExtTextInputAttr::Highlight;
1623 aInputEvent.maText = aInsertString;
1624 aInputEvent.mnCursorPos = selRange.location;
1625 aInputEvent.mpTextAttr = aInputFlags.data();
1626 mpFrame->CallCallback( SalEvent::ExtTextInput, static_cast<void *>(&aInputEvent) );
1628 aInputEvent.maText.clear();
1629 aInputEvent.mnCursorPos = 0;
1630 aInputEvent.mnCursorFlags = 0;
1631 aInputEvent.mpTextAttr = nullptr;
1632 mpFrame->CallCallback( SalEvent::ExtTextInput, static_cast<void *>(&aInputEvent) );
1633 mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
1640 mSelectedRange = mMarkedRange = NSMakeRange(NSNotFound, 0);
1643 - (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
1648 // FIXME - Implement
1652 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
1659 - (NSInteger)conversationIdentifier
1661 return reinterpret_cast<long>(self);
1664 - (void)doCommandBySelector:(SEL)aSelector
1666 if( AquaSalFrame::isAlive( mpFrame ) )
1668 if( (mpFrame->mnICOptions & InputContextFlags::Text) &&
1669 aSelector != nullptr && [self respondsToSelector: aSelector] )
1671 [self performSelector: aSelector];
1675 [self sendSingleCharacter:mpLastEvent];
1679 mbKeyHandled = true;
1682 -(void)clearLastEvent
1687 - (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
1689 // FIXME - These should probably be used?
1693 SolarMutexGuard aGuard;
1695 SalExtTextInputPosEvent aPosEvent;
1696 mpFrame->CallCallback( SalEvent::ExtTextInputPos, static_cast<void *>(&aPosEvent) );
1700 rect.origin.x = aPosEvent.mnX + mpFrame->maGeometry.nX;
1701 rect.origin.y = aPosEvent.mnY + mpFrame->maGeometry.nY + 4; // add some space for underlines
1702 rect.size.width = aPosEvent.mnWidth;
1703 rect.size.height = aPosEvent.mnHeight;
1705 mpFrame->VCLToCocoa( rect );
1709 -(id)parentAttribute {
1710 return reinterpret_cast<NSView*>(mpFrame->getNSWindow());
1711 //TODO: odd cast really needed for fdo#74121?
1714 -(css::accessibility::XAccessibleContext *)accessibleContext
1716 if ( !mpReferenceWrapper ) {
1717 // some frames never become visible ..
1718 vcl::Window *pWindow = mpFrame -> GetWindow();
1722 mpReferenceWrapper = new ReferenceWrapper;
1723 mpReferenceWrapper -> rAccessibleContext = pWindow -> /*GetAccessibleChildWindow( 0 ) ->*/ GetAccessible() -> getAccessibleContext();
1724 [ AquaA11yFactory insertIntoWrapperRepository: self forAccessibleContext: mpReferenceWrapper -> rAccessibleContext ];
1726 return [ super accessibleContext ];
1729 -(NSWindow*)windowForParent
1731 return mpFrame->getNSWindow();
1734 -(void)registerMouseEventListener: (id)theListener
1736 mpMouseEventListener = theListener;
1739 -(void)unregisterMouseEventListener: (id)theListener
1742 mpMouseEventListener = nil;
1745 -(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
1747 return [mDraggingDestinationHandler draggingEntered: sender];
1750 -(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
1752 return [mDraggingDestinationHandler draggingUpdated: sender];
1755 -(void)draggingExited:(id <NSDraggingInfo>)sender
1757 [mDraggingDestinationHandler draggingExited: sender];
1760 -(BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
1762 return [mDraggingDestinationHandler prepareForDragOperation: sender];
1765 -(BOOL)performDragOperation:(id <NSDraggingInfo>)sender
1767 return [mDraggingDestinationHandler performDragOperation: sender];
1770 -(void)concludeDragOperation:(id <NSDraggingInfo>)sender
1772 [mDraggingDestinationHandler concludeDragOperation: sender];
1775 -(void)registerDraggingDestinationHandler:(id)theHandler
1777 mDraggingDestinationHandler = theHandler;
1780 -(void)unregisterDraggingDestinationHandler:(id)theHandler
1783 mDraggingDestinationHandler = nil;
1788 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */