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>
24 #include <tools/long.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 // tdf#137468: Restrict to 24-bit RGB as that is all that we can
207 // handle anyway. HDR is far off in the future for LibreOffice.
208 [pNSWindow setDynamicDepthLimit: NO];
209 [pNSWindow setDepthLimit: NSWindowDepthTwentyfourBitRGB];
211 return static_cast<SalFrameWindow *>(pNSWindow);
214 -(AquaSalFrame*)getSalFrame
219 -(void)displayIfNeeded
221 if( GetSalData() && GetSalData()->mpInstance )
223 SolarMutexGuard aGuard;
224 [super displayIfNeeded];
230 // is this event actually inside that NSWindow ?
231 NSPoint aPt = [NSEvent mouseLocation];
232 NSRect aFrameRect = [self frame];
233 bool bInRect = NSPointInRect( aPt, aFrameRect );
237 -(BOOL)canBecomeKeyWindow
239 if( (mpFrame->mnStyle &
240 ( SalFrameStyleFlags::FLOAT |
241 SalFrameStyleFlags::TOOLTIP |
242 SalFrameStyleFlags::INTRO
243 )) == SalFrameStyleFlags::NONE )
245 if( mpFrame->mnStyle & SalFrameStyleFlags::OWNERDRAWDECORATION )
247 if( mpFrame->mbFullScreen )
249 return [super canBecomeKeyWindow];
252 -(void)windowDidBecomeKey: (NSNotification*)pNotification
255 SolarMutexGuard aGuard;
257 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
259 static const SalFrameStyleFlags nGuessDocument = SalFrameStyleFlags::MOVEABLE|
260 SalFrameStyleFlags::SIZEABLE|
261 SalFrameStyleFlags::CLOSEABLE;
263 if( mpFrame->mpMenu )
264 mpFrame->mpMenu->setMainMenu();
265 else if( ! mpFrame->mpParent &&
266 ( (mpFrame->mnStyle & nGuessDocument) == nGuessDocument || // set default menu for e.g. help
267 mpFrame->mbFullScreen ) ) // set default menu for e.g. presentation
269 AquaSalMenu::setDefaultMenu();
272 // FIXME: we should disable menus while in modal mode
273 // however from down here there is currently no reliable way to
274 // find out when to do this
275 if( (mpFrame->mpParent && mpFrame->mpParent->GetWindow()->IsInModalMode()) )
276 AquaSalMenu::enableMainMenu( false );
278 mpFrame->CallCallback( SalEvent::GetFocus, nullptr );
279 mpFrame->SendPaintEvent(); // repaint controls as active
283 -(void)windowDidResignKey: (NSNotification*)pNotification
286 SolarMutexGuard aGuard;
288 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
290 mpFrame->CallCallback(SalEvent::LoseFocus, nullptr);
291 mpFrame->SendPaintEvent(); // repaint controls as inactive
295 -(void)windowDidChangeScreen: (NSNotification*)pNotification
298 SolarMutexGuard aGuard;
300 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
301 mpFrame->screenParametersChanged();
304 -(void)windowDidMove: (NSNotification*)pNotification
307 SolarMutexGuard aGuard;
309 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
311 mpFrame->UpdateFrameGeometry();
312 mpFrame->CallCallback( SalEvent::Move, nullptr );
316 -(void)windowDidResize: (NSNotification*)pNotification
319 SolarMutexGuard aGuard;
321 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
323 mpFrame->UpdateFrameGeometry();
324 mpFrame->CallCallback( SalEvent::Resize, nullptr );
325 mpFrame->SendPaintEvent();
329 -(void)windowDidMiniaturize: (NSNotification*)pNotification
332 SolarMutexGuard aGuard;
334 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
336 mpFrame->mbShown = false;
337 mpFrame->UpdateFrameGeometry();
338 mpFrame->CallCallback( SalEvent::Resize, nullptr );
342 -(void)windowDidDeminiaturize: (NSNotification*)pNotification
345 SolarMutexGuard aGuard;
347 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
349 mpFrame->mbShown = true;
350 mpFrame->UpdateFrameGeometry();
351 mpFrame->CallCallback( SalEvent::Resize, nullptr );
355 -(BOOL)windowShouldClose: (NSNotification*)pNotification
358 SolarMutexGuard aGuard;
361 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
363 // #i84461# end possible input
364 mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
365 if( AquaSalFrame::isAlive( mpFrame ) )
367 mpFrame->CallCallback( SalEvent::Close, nullptr );
368 bRet = false; // application will close the window or not, AppKit shouldn't
369 AquaSalTimer *pTimer = static_cast<AquaSalTimer*>( ImplGetSVData()->maSchedCtx.mpSalTimer );
371 pTimer->handleWindowShouldClose();
378 -(void)windowDidEnterFullScreen: (NSNotification*)pNotification
380 SolarMutexGuard aGuard;
382 if( !mpFrame || !AquaSalFrame::isAlive( mpFrame))
384 mpFrame->mbFullScreen = true;
388 -(void)windowDidExitFullScreen: (NSNotification*)pNotification
390 SolarMutexGuard aGuard;
392 if( !mpFrame || !AquaSalFrame::isAlive( mpFrame))
394 mpFrame->mbFullScreen = false;
398 -(void)dockMenuItemTriggered: (id)sender
401 SolarMutexGuard aGuard;
403 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
404 mpFrame->ToTop( SalFrameToTop::RestoreWhenMin | SalFrameToTop::GrabFocus );
407 -(css::uno::Reference < css::accessibility::XAccessibleContext >)accessibleContext
409 return mpFrame -> GetWindow() -> GetAccessible() -> getAccessibleContext();
412 -(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
414 return [mDraggingDestinationHandler draggingEntered: sender];
417 -(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
419 return [mDraggingDestinationHandler draggingUpdated: sender];
422 -(void)draggingExited:(id <NSDraggingInfo>)sender
424 [mDraggingDestinationHandler draggingExited: sender];
427 -(BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
429 return [mDraggingDestinationHandler prepareForDragOperation: sender];
432 -(BOOL)performDragOperation:(id <NSDraggingInfo>)sender
434 return [mDraggingDestinationHandler performDragOperation: sender];
437 -(void)concludeDragOperation:(id <NSDraggingInfo>)sender
439 [mDraggingDestinationHandler concludeDragOperation: sender];
442 -(void)registerDraggingDestinationHandler:(id)theHandler
444 mDraggingDestinationHandler = theHandler;
447 -(void)unregisterDraggingDestinationHandler:(id)theHandler
450 mDraggingDestinationHandler = nil;
455 @implementation SalFrameView
456 +(void)unsetMouseFrame: (AquaSalFrame*)pFrame
458 if( pFrame == s_pMouseFrame )
459 s_pMouseFrame = nullptr;
462 -(id)initWithSalFrame: (AquaSalFrame*)pFrame
464 if ((self = [super initWithFrame: [NSWindow contentRectForFrameRect: [pFrame->getNSWindow() frame] styleMask: pFrame->mnStyleMask]]) != nil)
466 mDraggingDestinationHandler = nil;
468 mMarkedRange = NSMakeRange(NSNotFound, 0);
469 mSelectedRange = NSMakeRange(NSNotFound, 0);
470 mpReferenceWrapper = nil;
471 mpMouseEventListener = nil;
472 mpLastSuperEvent = nil;
475 mfLastMagnifyTime = 0.0;
479 -(AquaSalFrame*)getSalFrame
484 -(void)resetCursorRects
486 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
488 // FIXME: does this leak the returned NSCursor of getCurrentCursor ?
489 const NSRect aRect = { NSZeroPoint, NSMakeSize( mpFrame->maGeometry.nWidth, mpFrame->maGeometry.nHeight) };
490 [self addCursorRect: aRect cursor: mpFrame->getCurrentCursor()];
494 -(BOOL)acceptsFirstResponder
499 -(BOOL)acceptsFirstMouse: (NSEvent*)pEvent
509 if( !AquaSalFrame::isAlive( mpFrame))
511 if( !mpFrame->getClipPath())
516 -(void)drawRect: (NSRect)aRect
518 AquaSalInstance *pInstance = GetSalData()->mpInstance;
523 SolarMutexGuard aGuard;
524 if (!mpFrame || !AquaSalFrame::isAlive(mpFrame))
527 const bool bIsLiveResize = [self inLiveResize];
528 const bool bWasLiveResize = pInstance->mbIsLiveResize;
529 if (bWasLiveResize != bIsLiveResize)
531 pInstance->mbIsLiveResize = bIsLiveResize;
532 Scheduler::ProcessTaskScheduling();
535 AquaSalGraphics* pGraphics = mpFrame->mpGraphics;
538 pGraphics->UpdateWindow(aRect);
539 if (mpFrame->getClipPath())
540 [mpFrame->getNSWindow() invalidateShadow];
544 -(void)sendMouseEventToFrame: (NSEvent*)pEvent button:(sal_uInt16)nButton eventtype:(SalEvent)nEvent
546 SolarMutexGuard aGuard;
548 AquaSalFrame* pDispatchFrame = AquaSalFrame::GetCaptureFrame();
549 bool bIsCaptured = false;
553 if( nEvent == SalEvent::MouseLeave ) // no leave events if mouse is captured
554 nEvent = SalEvent::MouseMove;
556 else if( s_pMouseFrame )
557 pDispatchFrame = s_pMouseFrame;
559 pDispatchFrame = mpFrame;
561 /* #i81645# Cocoa reports mouse events while a button is pressed
562 to the window in which it was first pressed. This is reasonable and fine and
563 gets one around most cases where on other platforms one uses CaptureMouse or XGrabPointer,
564 however vcl expects mouse events to occur in the window the mouse is over, unless the
565 mouse is explicitly captured. So we need to find the window the mouse is actually
566 over for conformance with other platforms.
568 if( ! bIsCaptured && nButton && pDispatchFrame && AquaSalFrame::isAlive( pDispatchFrame ) )
570 // is this event actually inside that NSWindow ?
571 NSPoint aPt = [NSEvent mouseLocation];
572 NSRect aFrameRect = [pDispatchFrame->getNSWindow() frame];
574 if ( ! NSPointInRect( aPt, aFrameRect ) )
577 // now we need to find the one it may be in
578 /* #i93756# we ant to get enumerate the application windows in z-order
579 to check if any contains the mouse. This could be elegantly done with this
582 // use NSApp to check windows in ZOrder whether they contain the mouse pointer
583 NSWindow* pWindow = [NSApp makeWindowsPerform: @selector(containsMouse) inOrder: YES];
584 if( pWindow && [pWindow isMemberOfClass: [SalFrameWindow class]] )
585 pDispatchFrame = [(SalFrameWindow*)pWindow getSalFrame];
587 However if a non SalFrameWindow is on screen (like e.g. the file dialog)
588 it can be hit with the containsMouse selector, which it doesn't support.
589 Sadly NSApplication:makeWindowsPerform does not check (for performance reasons
590 I assume) whether a window supports a selector before sending it.
592 AquaSalFrame* pMouseFrame = getMouseContainerFrame();
594 pDispatchFrame = pMouseFrame;
598 if( pDispatchFrame && AquaSalFrame::isAlive( pDispatchFrame ) )
600 pDispatchFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
601 pDispatchFrame->mnLastModifierFlags = [pEvent modifierFlags];
603 NSPoint aPt = [NSEvent mouseLocation];
604 pDispatchFrame->CocoaToVCL( aPt );
606 sal_uInt16 nModMask = ImplGetModifierMask( [pEvent modifierFlags] );
607 // #i82284# emulate ctrl left
608 if( nModMask == KEY_MOD3 && nButton == MOUSE_LEFT )
611 nButton = MOUSE_RIGHT;
614 SalMouseEvent aEvent;
615 aEvent.mnTime = pDispatchFrame->mnLastEventTime;
616 aEvent.mnX = static_cast<tools::Long>(aPt.x) - pDispatchFrame->maGeometry.nX;
617 aEvent.mnY = static_cast<tools::Long>(aPt.y) - pDispatchFrame->maGeometry.nY;
618 aEvent.mnButton = nButton;
619 aEvent.mnCode = aEvent.mnButton | nModMask;
621 if( AllSettings::GetLayoutRTL() )
622 aEvent.mnX = pDispatchFrame->maGeometry.nWidth-1-aEvent.mnX;
624 pDispatchFrame->CallCallback( nEvent, &aEvent );
628 -(void)mouseDown: (NSEvent*)pEvent
630 if ( mpMouseEventListener != nil &&
631 [mpMouseEventListener respondsToSelector: @selector(mouseDown:)])
633 [mpMouseEventListener mouseDown: [pEvent copyWithZone: nullptr]];
636 s_nLastButton = MOUSE_LEFT;
637 [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SalEvent::MouseButtonDown];
640 -(void)mouseDragged: (NSEvent*)pEvent
642 if ( mpMouseEventListener != nil &&
643 [mpMouseEventListener respondsToSelector: @selector(mouseDragged:)])
645 [mpMouseEventListener mouseDragged: [pEvent copyWithZone: nullptr]];
647 s_nLastButton = MOUSE_LEFT;
648 [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SalEvent::MouseMove];
651 -(void)mouseUp: (NSEvent*)pEvent
654 [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SalEvent::MouseButtonUp];
657 -(void)mouseMoved: (NSEvent*)pEvent
660 [self sendMouseEventToFrame:pEvent button:0 eventtype:SalEvent::MouseMove];
663 -(void)mouseEntered: (NSEvent*)pEvent
665 s_pMouseFrame = mpFrame;
667 // #i107215# the only mouse events we get when inactive are enter/exit
668 // actually we would like to have all of them, but better none than some
669 if( [NSApp isActive] )
670 [self sendMouseEventToFrame:pEvent button:s_nLastButton eventtype:SalEvent::MouseMove];
673 -(void)mouseExited: (NSEvent*)pEvent
675 if( s_pMouseFrame == mpFrame )
676 s_pMouseFrame = nullptr;
678 // #i107215# the only mouse events we get when inactive are enter/exit
679 // actually we would like to have all of them, but better none than some
680 if( [NSApp isActive] )
681 [self sendMouseEventToFrame:pEvent button:s_nLastButton eventtype:SalEvent::MouseLeave];
684 -(void)rightMouseDown: (NSEvent*)pEvent
686 s_nLastButton = MOUSE_RIGHT;
687 [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SalEvent::MouseButtonDown];
690 -(void)rightMouseDragged: (NSEvent*)pEvent
692 s_nLastButton = MOUSE_RIGHT;
693 [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SalEvent::MouseMove];
696 -(void)rightMouseUp: (NSEvent*)pEvent
699 [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SalEvent::MouseButtonUp];
702 -(void)otherMouseDown: (NSEvent*)pEvent
704 if( [pEvent buttonNumber] == 2 )
706 s_nLastButton = MOUSE_MIDDLE;
707 [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SalEvent::MouseButtonDown];
713 -(void)otherMouseDragged: (NSEvent*)pEvent
715 if( [pEvent buttonNumber] == 2 )
717 s_nLastButton = MOUSE_MIDDLE;
718 [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SalEvent::MouseMove];
724 -(void)otherMouseUp: (NSEvent*)pEvent
727 if( [pEvent buttonNumber] == 2 )
728 [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SalEvent::MouseButtonUp];
731 - (void)magnifyWithEvent: (NSEvent*)pEvent
733 SolarMutexGuard aGuard;
735 // TODO: ?? -(float)magnification;
736 if( AquaSalFrame::isAlive( mpFrame ) )
738 const NSTimeInterval fMagnifyTime = [pEvent timestamp];
739 mpFrame->mnLastEventTime = static_cast<sal_uInt64>( fMagnifyTime * 1000.0 );
740 mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
742 // check if this is a new series of magnify events
743 static const NSTimeInterval fMaxDiffTime = 0.3;
744 const bool bNewSeries = (fMagnifyTime - mfLastMagnifyTime > fMaxDiffTime);
747 mfMagnifyDeltaSum = 0.0;
748 mfMagnifyDeltaSum += [pEvent magnification];
750 mfLastMagnifyTime = [pEvent timestamp];
751 // TODO: change to 0.1 when CommandWheelMode::ZOOM handlers allow finer zooming control
752 static const float fMagnifyFactor = 0.25*500; // steps are 500 times smaller for -magnification
753 static const float fMinMagnifyStep = 15.0 / fMagnifyFactor;
754 if( fabs(mfMagnifyDeltaSum) <= fMinMagnifyStep )
757 // adapt NSEvent-sensitivity to application expectations
758 // TODO: rather make CommandWheelMode::ZOOM handlers smarter
759 const float fDeltaZ = mfMagnifyDeltaSum * fMagnifyFactor;
760 int nDeltaZ = FRound( fDeltaZ );
763 // handle new series immediately
766 nDeltaZ = (fDeltaZ >= 0.0) ? +1 : -1;
768 // eventually give credit for delta sum
769 mfMagnifyDeltaSum -= nDeltaZ / fMagnifyFactor;
771 NSPoint aPt = [NSEvent mouseLocation];
772 mpFrame->CocoaToVCL( aPt );
774 SalWheelMouseEvent aEvent;
775 aEvent.mnTime = mpFrame->mnLastEventTime;
776 aEvent.mnX = static_cast<tools::Long>(aPt.x) - mpFrame->maGeometry.nX;
777 aEvent.mnY = static_cast<tools::Long>(aPt.y) - mpFrame->maGeometry.nY;
778 aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
779 aEvent.mnCode |= KEY_MOD1; // we want zooming, no scrolling
780 aEvent.mbDeltaIsPixel = true;
782 if( AllSettings::GetLayoutRTL() )
783 aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
785 aEvent.mnDelta = nDeltaZ;
786 aEvent.mnNotchDelta = (nDeltaZ >= 0) ? +1 : -1;
787 if( aEvent.mnDelta == 0 )
788 aEvent.mnDelta = aEvent.mnNotchDelta;
789 aEvent.mbHorz = false;
790 sal_uInt32 nScrollLines = nDeltaZ;
791 if (nScrollLines == 0)
793 aEvent.mnScrollLines = nScrollLines;
794 mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent );
798 - (void)rotateWithEvent: (NSEvent*)pEvent
800 //Rotation : -(float)rotation;
801 // TODO: create new CommandType so rotation is available to the applications
805 - (void)swipeWithEvent: (NSEvent*)pEvent
807 SolarMutexGuard aGuard;
809 if( AquaSalFrame::isAlive( mpFrame ) )
811 mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
812 mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
814 // merge pending scroll wheel events
819 dX += [pEvent deltaX];
820 dY += [pEvent deltaY];
821 SAL_WNODEPRECATED_DECLARATIONS_PUSH
822 // 'NSScrollWheelMask' is deprecated: first deprecated in macOS 10.12
823 NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask
824 SAL_WNODEPRECATED_DECLARATIONS_POP
825 untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ];
831 NSPoint aPt = [NSEvent mouseLocation];
832 mpFrame->CocoaToVCL( aPt );
834 SalWheelMouseEvent aEvent;
835 aEvent.mnTime = mpFrame->mnLastEventTime;
836 aEvent.mnX = static_cast<tools::Long>(aPt.x) - mpFrame->maGeometry.nX;
837 aEvent.mnY = static_cast<tools::Long>(aPt.y) - mpFrame->maGeometry.nY;
838 aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
839 aEvent.mbDeltaIsPixel = true;
841 if( AllSettings::GetLayoutRTL() )
842 aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
846 aEvent.mnDelta = static_cast<tools::Long>(floor(dX));
847 aEvent.mnNotchDelta = (dX < 0) ? -1 : +1;
848 if( aEvent.mnDelta == 0 )
849 aEvent.mnDelta = aEvent.mnNotchDelta;
850 aEvent.mbHorz = true;
851 aEvent.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
852 mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent );
854 if( dY != 0.0 && AquaSalFrame::isAlive( mpFrame ))
856 aEvent.mnDelta = static_cast<tools::Long>(floor(dY));
857 aEvent.mnNotchDelta = (dY < 0) ? -1 : +1;
858 if( aEvent.mnDelta == 0 )
859 aEvent.mnDelta = aEvent.mnNotchDelta;
860 aEvent.mbHorz = false;
861 aEvent.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
862 mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent );
867 -(void)scrollWheel: (NSEvent*)pEvent
869 SolarMutexGuard aGuard;
871 if( AquaSalFrame::isAlive( mpFrame ) )
873 mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
874 mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
876 // merge pending scroll wheel events
881 dX += [pEvent deltaX];
882 dY += [pEvent deltaY];
883 SAL_WNODEPRECATED_DECLARATIONS_PUSH
884 // 'NSScrollWheelMask' is deprecated: first deprecated in macOS 10.12
885 NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask
886 SAL_WNODEPRECATED_DECLARATIONS_POP
887 untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ];
893 NSPoint aPt = [NSEvent mouseLocation];
894 mpFrame->CocoaToVCL( aPt );
896 SalWheelMouseEvent aEvent;
897 aEvent.mnTime = mpFrame->mnLastEventTime;
898 aEvent.mnX = static_cast<tools::Long>(aPt.x) - mpFrame->maGeometry.nX;
899 aEvent.mnY = static_cast<tools::Long>(aPt.y) - mpFrame->maGeometry.nY;
900 aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
901 aEvent.mbDeltaIsPixel = false;
903 if( AllSettings::GetLayoutRTL() )
904 aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
908 aEvent.mnDelta = static_cast<tools::Long>(floor(dX));
909 aEvent.mnNotchDelta = (dX < 0) ? -1 : +1;
910 if( aEvent.mnDelta == 0 )
911 aEvent.mnDelta = aEvent.mnNotchDelta;
912 aEvent.mbHorz = true;
913 sal_uInt32 nScrollLines = fabs(dX) / WHEEL_EVENT_FACTOR;
914 if (nScrollLines == 0)
916 aEvent.mnScrollLines = nScrollLines;
918 mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent );
920 if( dY != 0.0 && AquaSalFrame::isAlive( mpFrame ) )
922 aEvent.mnDelta = static_cast<tools::Long>(floor(dY));
923 aEvent.mnNotchDelta = (dY < 0) ? -1 : +1;
924 if( aEvent.mnDelta == 0 )
925 aEvent.mnDelta = aEvent.mnNotchDelta;
926 aEvent.mbHorz = false;
927 sal_uInt32 nScrollLines = fabs(dY) / WHEEL_EVENT_FACTOR;
928 if (nScrollLines == 0)
930 aEvent.mnScrollLines = nScrollLines;
932 mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent );
938 -(void)keyDown: (NSEvent*)pEvent
940 SolarMutexGuard aGuard;
942 if( AquaSalFrame::isAlive( mpFrame ) )
944 mpLastEvent = pEvent;
946 mbNeedSpecialKeyHandle = false;
947 mbKeyHandled = false;
949 mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
950 mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
952 if( ! [self handleKeyDownException: pEvent] )
954 NSArray* pArray = [NSArray arrayWithObject: pEvent];
955 [self interpretKeyEvents: pArray];
958 mbInKeyInput = false;
962 -(BOOL)handleKeyDownException:(NSEvent*)pEvent
964 // check for a very special set of modified characters
965 NSString* pUnmodifiedString = [pEvent charactersIgnoringModifiers];
967 if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
969 /* #i103102# key events with command and alternate don't make it through
970 interpretKeyEvents (why?). Try to dispatch them here first,
971 if not successful continue normally
973 SAL_WNODEPRECATED_DECLARATIONS_PUSH
974 // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12
975 // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12
976 if( (mpFrame->mnLastModifierFlags & (NSAlternateKeyMask | NSCommandKeyMask))
977 == (NSAlternateKeyMask | NSCommandKeyMask) )
978 SAL_WNODEPRECATED_DECLARATIONS_POP
980 if( [self sendSingleCharacter: mpLastEvent] )
987 -(void)flagsChanged: (NSEvent*)pEvent
989 SolarMutexGuard aGuard;
991 if( AquaSalFrame::isAlive( mpFrame ) )
993 mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
994 mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
998 -(void)insertText:(id)aString replacementRange:(NSRange)replacementRange
1000 (void) replacementRange; // FIXME: surely it must be used
1002 SolarMutexGuard aGuard;
1004 if( AquaSalFrame::isAlive( mpFrame ) )
1006 NSString* pInsert = nil;
1007 if( [aString isMemberOfClass: [NSAttributedString class]] )
1008 pInsert = [aString string];
1013 if( pInsert && ( nLen = [pInsert length] ) > 0 )
1015 OUString aInsertString( GetOUString( pInsert ) );
1016 // aCharCode initializer is safe since aInsertString will at least contain '\0'
1017 sal_Unicode aCharCode = *aInsertString.getStr();
1022 ! [self hasMarkedText ]
1025 sal_uInt16 nKeyCode = ImplMapCharCode( aCharCode );
1026 unsigned int nLastModifiers = mpFrame->mnLastModifierFlags;
1029 // find out the unmodified key code
1031 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1032 // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12
1033 // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12
1034 // 'NSControlKeyMask' is deprecated: first deprecated in macOS 10.12
1035 // 'NSKeyDown' is deprecated: first deprecated in macOS 10.12
1036 // 'NSKeyUp' is deprecated: first deprecated in macOS 10.12
1038 if( mpLastEvent && ( [mpLastEvent type] == NSKeyDown || [mpLastEvent type] == NSKeyUp ) )
1040 // get unmodified string
1041 NSString* pUnmodifiedString = [mpLastEvent charactersIgnoringModifiers];
1042 if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
1044 // map the unmodified key code
1045 unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
1046 nKeyCode = ImplMapCharCode( keyChar );
1048 nLastModifiers = [mpLastEvent modifierFlags];
1052 // applications and vcl's edit fields ignore key events with ALT
1053 // however we're at a place where we know text should be inserted
1054 // so it seems we need to strip the Alt modifier here
1055 if( (nLastModifiers & (NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask))
1056 == NSAlternateKeyMask )
1060 SAL_WNODEPRECATED_DECLARATIONS_POP
1061 [self sendKeyInputAndReleaseToFrame: nKeyCode character: aCharCode modifiers: nLastModifiers];
1065 SalExtTextInputEvent aEvent;
1066 aEvent.maText = aInsertString;
1067 aEvent.mpTextAttr = nullptr;
1068 aEvent.mnCursorPos = aInsertString.getLength();
1069 aEvent.mnCursorFlags = 0;
1070 mpFrame->CallCallback( SalEvent::ExtTextInput, &aEvent );
1071 if( AquaSalFrame::isAlive( mpFrame ) )
1072 mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
1077 SalExtTextInputEvent aEvent;
1078 aEvent.maText.clear();
1079 aEvent.mpTextAttr = nullptr;
1080 aEvent.mnCursorPos = 0;
1081 aEvent.mnCursorFlags = 0;
1082 mpFrame->CallCallback( SalEvent::ExtTextInput, &aEvent );
1083 if( AquaSalFrame::isAlive( mpFrame ) )
1084 mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
1087 mbKeyHandled = true;
1092 -(void)insertTab: (id)aSender
1095 [self sendKeyInputAndReleaseToFrame: KEY_TAB character: '\t' modifiers: 0];
1098 -(void)insertBacktab: (id)aSender
1101 [self sendKeyInputAndReleaseToFrame: (KEY_TAB | KEY_SHIFT) character: '\t' modifiers: 0];
1104 -(void)moveLeft: (id)aSender
1107 [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: 0];
1110 -(void)moveLeftAndModifySelection: (id)aSender
1113 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1114 // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12
1115 [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: NSShiftKeyMask];
1116 SAL_WNODEPRECATED_DECLARATIONS_POP
1119 -(void)moveBackwardAndModifySelection: (id)aSender
1122 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_BACKWARD character: 0 modifiers: 0];
1125 -(void)moveRight: (id)aSender
1128 [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: 0];
1131 -(void)moveRightAndModifySelection: (id)aSender
1134 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1135 // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12
1136 [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: NSShiftKeyMask];
1137 SAL_WNODEPRECATED_DECLARATIONS_POP
1140 -(void)moveForwardAndModifySelection: (id)aSender
1143 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_FORWARD character: 0 modifiers: 0];
1146 -(void)moveWordLeft: (id)aSender
1149 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_BACKWARD character: 0 modifiers: 0];
1152 -(void)moveWordBackward: (id)aSender
1155 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_BACKWARD character: 0 modifiers: 0];
1158 -(void)moveWordBackwardAndModifySelection: (id)aSender
1161 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_BACKWARD character: 0 modifiers: 0];
1164 -(void)moveWordLeftAndModifySelection: (id)aSender
1167 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_BACKWARD character: 0 modifiers: 0];
1170 -(void)moveWordRight: (id)aSender
1173 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_FORWARD character: 0 modifiers: 0];
1176 -(void)moveWordForward: (id)aSender
1179 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_FORWARD character: 0 modifiers: 0];
1182 -(void)moveWordForwardAndModifySelection: (id)aSender
1185 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_FORWARD character: 0 modifiers: 0];
1188 -(void)moveWordRightAndModifySelection: (id)aSender
1191 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_FORWARD character: 0 modifiers: 0];
1194 -(void)moveToEndOfLine: (id)aSender
1197 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_LINE character: 0 modifiers: 0];
1200 -(void)moveToRightEndOfLine: (id)aSender
1203 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_LINE character: 0 modifiers: 0];
1206 -(void)moveToEndOfLineAndModifySelection: (id)aSender
1209 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_LINE character: 0 modifiers: 0];
1212 -(void)moveToRightEndOfLineAndModifySelection: (id)aSender
1215 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_LINE character: 0 modifiers: 0];
1218 -(void)moveToBeginningOfLine: (id)aSender
1221 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
1224 -(void)moveToLeftEndOfLine: (id)aSender
1227 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
1230 -(void)moveToBeginningOfLineAndModifySelection: (id)aSender
1233 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
1236 -(void)moveToLeftEndOfLineAndModifySelection: (id)aSender
1239 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
1242 -(void)moveToEndOfParagraph: (id)aSender
1245 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
1248 -(void)moveToEndOfParagraphAndModifySelection: (id)aSender
1251 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
1254 -(void)moveParagraphForward: (id)aSender
1257 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
1260 -(void)moveParagraphForwardAndModifySelection: (id)aSender
1263 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
1266 -(void)moveToBeginningOfParagraph: (id)aSender
1269 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
1272 -(void)moveParagraphBackward: (id)aSender
1275 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
1278 -(void)moveToBeginningOfParagraphAndModifySelection: (id)aSender
1281 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
1284 -(void)moveParagraphBackwardAndModifySelection: (id)aSender
1287 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
1290 -(void)moveToEndOfDocument: (id)aSender
1293 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_DOCUMENT character: 0 modifiers: 0];
1296 -(void)scrollToEndOfDocument: (id)aSender
1299 // this is not exactly what we should do, but it makes "End" and "Shift-End" behave consistent
1300 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_DOCUMENT character: 0 modifiers: 0];
1303 -(void)moveToEndOfDocumentAndModifySelection: (id)aSender
1306 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_DOCUMENT character: 0 modifiers: 0];
1309 -(void)moveToBeginningOfDocument: (id)aSender
1312 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0];
1315 -(void)scrollToBeginningOfDocument: (id)aSender
1318 // this is not exactly what we should do, but it makes "Home" and "Shift-Home" behave consistent
1319 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0];
1322 -(void)moveToBeginningOfDocumentAndModifySelection: (id)aSender
1325 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0];
1328 -(void)moveUp: (id)aSender
1331 [self sendKeyInputAndReleaseToFrame: KEY_UP character: 0 modifiers: 0];
1334 -(void)moveDown: (id)aSender
1337 [self sendKeyInputAndReleaseToFrame: KEY_DOWN character: 0 modifiers: 0];
1340 -(void)insertNewline: (id)aSender
1343 // #i91267# make enter and shift-enter work by evaluating the modifiers
1344 [self sendKeyInputAndReleaseToFrame: KEY_RETURN character: '\n' modifiers: mpFrame->mnLastModifierFlags];
1347 -(void)deleteBackward: (id)aSender
1350 [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0];
1353 -(void)deleteForward: (id)aSender
1356 [self sendKeyInputAndReleaseToFrame: KEY_DELETE character: 0x7f modifiers: 0];
1359 -(void)deleteBackwardByDecomposingPreviousCharacter: (id)aSender
1362 [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0];
1365 -(void)deleteWordBackward: (id)aSender
1368 [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_WORD_BACKWARD character: 0 modifiers: 0];
1371 -(void)deleteWordForward: (id)aSender
1374 [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_WORD_FORWARD character: 0 modifiers: 0];
1377 -(void)deleteToBeginningOfLine: (id)aSender
1380 [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
1383 -(void)deleteToEndOfLine: (id)aSender
1386 [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_END_OF_LINE character: 0 modifiers: 0];
1389 -(void)deleteToBeginningOfParagraph: (id)aSender
1392 [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
1395 -(void)deleteToEndOfParagraph: (id)aSender
1398 [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
1401 -(void)insertLineBreak: (id)aSender
1404 [self sendKeyInputAndReleaseToFrame: css::awt::Key::INSERT_LINEBREAK character: 0 modifiers: 0];
1407 -(void)insertParagraphSeparator: (id)aSender
1410 [self sendKeyInputAndReleaseToFrame: css::awt::Key::INSERT_PARAGRAPH character: 0 modifiers: 0];
1413 -(void)selectWord: (id)aSender
1416 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD character: 0 modifiers: 0];
1419 -(void)selectLine: (id)aSender
1422 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_LINE character: 0 modifiers: 0];
1425 -(void)selectParagraph: (id)aSender
1428 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_PARAGRAPH character: 0 modifiers: 0];
1431 -(void)selectAll: (id)aSender
1434 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_ALL character: 0 modifiers: 0];
1437 -(void)cancelOperation: (id)aSender
1440 [self sendKeyInputAndReleaseToFrame: KEY_ESCAPE character: 0x1b modifiers: 0];
1443 -(void)noop: (id)aSender
1446 if( ! mbKeyHandled )
1448 if( ! [self sendSingleCharacter:mpLastEvent] )
1450 /* prevent recursion */
1451 if( mpLastEvent != mpLastSuperEvent && [NSApp respondsToSelector: @selector(sendSuperEvent:)] )
1453 id pLastSuperEvent = mpLastSuperEvent;
1454 mpLastSuperEvent = mpLastEvent;
1455 [NSApp performSelector:@selector(sendSuperEvent:) withObject: mpLastEvent];
1456 mpLastSuperEvent = pLastSuperEvent;
1458 std::map< NSEvent*, bool >::iterator it = GetSalData()->maKeyEventAnswer.find( mpLastEvent );
1459 if( it != GetSalData()->maKeyEventAnswer.end() )
1466 -(BOOL)sendKeyInputAndReleaseToFrame: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar
1468 return [self sendKeyInputAndReleaseToFrame: nKeyCode character: aChar modifiers: mpFrame->mnLastModifierFlags];
1471 -(BOOL)sendKeyInputAndReleaseToFrame: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod
1473 return [self sendKeyToFrameDirect: nKeyCode character: aChar modifiers: nMod] ||
1474 [self sendSingleCharacter: mpLastEvent];
1477 -(BOOL)sendKeyToFrameDirect: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod
1479 SolarMutexGuard aGuard;
1482 if( AquaSalFrame::isAlive( mpFrame ) )
1485 aEvent.mnCode = nKeyCode | ImplGetModifierMask( nMod );
1486 aEvent.mnCharCode = aChar;
1487 aEvent.mnRepeat = FALSE;
1488 nRet = mpFrame->CallCallback( SalEvent::KeyInput, &aEvent );
1489 std::map< NSEvent*, bool >::iterator it = GetSalData()->maKeyEventAnswer.find( mpLastEvent );
1490 if( it != GetSalData()->maKeyEventAnswer.end() )
1492 if( AquaSalFrame::isAlive( mpFrame ) )
1493 mpFrame->CallCallback( SalEvent::KeyUp, &aEvent );
1499 -(BOOL)sendSingleCharacter: (NSEvent *)pEvent
1501 NSString* pUnmodifiedString = [pEvent charactersIgnoringModifiers];
1503 if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
1505 unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
1506 sal_uInt16 nKeyCode = ImplMapCharCode( keyChar );
1509 sal_uInt16 nOtherKeyCode = [pEvent keyCode];
1510 nKeyCode = ImplMapKeyCode(nOtherKeyCode);
1514 // don't send code points in the private use area
1515 if( keyChar >= 0xf700 && keyChar < 0xf780 )
1517 bool bRet = [self sendKeyToFrameDirect: nKeyCode character: keyChar modifiers: mpFrame->mnLastModifierFlags];
1518 mbInKeyInput = false;
1527 // NSTextInput/NSTextInputClient protocol
1528 - (NSArray *)validAttributesForMarkedText
1530 return [NSArray arrayWithObjects:NSUnderlineStyleAttributeName, nil];
1533 - (BOOL)hasMarkedText
1535 bool bHasMarkedText;
1537 bHasMarkedText = ( mMarkedRange.location != NSNotFound ) &&
1538 ( mMarkedRange.length != 0 );
1539 // hack to check keys like "Control-j"
1542 mbNeedSpecialKeyHandle = true;
1547 // if we come here outside of mbInKeyInput, this is likely to be because
1548 // of the keyboard viewer. For unknown reasons having no marked range
1549 // in this case causes a crash. So we say we have a marked range anyway
1550 // This is a hack, since it is not understood what a) causes that crash
1551 // and b) why we should have a marked range at this point.
1552 if( ! mbInKeyInput )
1553 bHasMarkedText = true;
1555 return bHasMarkedText;
1558 - (NSRange)markedRange
1562 // if we come here outside of mbInKeyInput, this is likely to be because
1563 // of the keyboard viewer. For unknown reasons having no marked range
1564 // in this case causes a crash. So we say we have a marked range anyway
1565 // This is a hack, since it is not understood what a) causes that crash
1566 // and b) why we should have a marked range at this point.
1567 if( ! mbInKeyInput )
1568 return NSMakeRange( 0, 0 );
1570 return [self hasMarkedText] ? mMarkedRange : NSMakeRange( NSNotFound, 0 );
1573 - (NSRange)selectedRange
1575 return mSelectedRange;
1578 - (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange replacementRange:(NSRange)replacementRange
1580 (void) replacementRange; // FIXME - use it!
1582 SolarMutexGuard aGuard;
1584 if( ![aString isKindOfClass:[NSAttributedString class]] )
1585 aString = [[[NSAttributedString alloc] initWithString:aString] autorelease];
1586 NSRange rangeToReplace = [self hasMarkedText] ? [self markedRange] : [self selectedRange];
1587 if( rangeToReplace.location == NSNotFound )
1589 mMarkedRange = NSMakeRange( selRange.location, [aString length] );
1590 mSelectedRange = NSMakeRange( selRange.location, selRange.length );
1594 mMarkedRange = NSMakeRange( rangeToReplace.location, [aString length] );
1595 mSelectedRange = NSMakeRange( rangeToReplace.location + selRange.location, selRange.length );
1598 int len = [aString length];
1599 SalExtTextInputEvent aInputEvent;
1601 NSString *pString = [aString string];
1602 OUString aInsertString( GetOUString( pString ) );
1603 std::vector<ExtTextInputAttr> aInputFlags( std::max( 1, len ), ExtTextInputAttr::NONE );
1604 for ( int i = 0; i < len; i++ )
1606 unsigned int nUnderlineValue;
1607 NSRange effectiveRange;
1609 effectiveRange = NSMakeRange(i, 1);
1610 nUnderlineValue = [[aString attribute:NSUnderlineStyleAttributeName atIndex:i effectiveRange:&effectiveRange] unsignedIntValue];
1612 switch (nUnderlineValue & 0xff) {
1613 case NSUnderlineStyleSingle:
1614 aInputFlags[i] = ExtTextInputAttr::Underline;
1616 case NSUnderlineStyleThick:
1617 aInputFlags[i] = ExtTextInputAttr::Underline | ExtTextInputAttr::Highlight;
1619 case NSUnderlineStyleDouble:
1620 aInputFlags[i] = ExtTextInputAttr::BoldUnderline;
1623 aInputFlags[i] = ExtTextInputAttr::Highlight;
1628 aInputEvent.maText = aInsertString;
1629 aInputEvent.mnCursorPos = selRange.location;
1630 aInputEvent.mpTextAttr = aInputFlags.data();
1631 mpFrame->CallCallback( SalEvent::ExtTextInput, static_cast<void *>(&aInputEvent) );
1633 aInputEvent.maText.clear();
1634 aInputEvent.mnCursorPos = 0;
1635 aInputEvent.mnCursorFlags = 0;
1636 aInputEvent.mpTextAttr = nullptr;
1637 mpFrame->CallCallback( SalEvent::ExtTextInput, static_cast<void *>(&aInputEvent) );
1638 mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
1645 mSelectedRange = mMarkedRange = NSMakeRange(NSNotFound, 0);
1648 - (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
1653 // FIXME - Implement
1657 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
1664 - (NSInteger)conversationIdentifier
1666 return reinterpret_cast<long>(self);
1669 - (void)doCommandBySelector:(SEL)aSelector
1671 if( AquaSalFrame::isAlive( mpFrame ) )
1673 if( (mpFrame->mnICOptions & InputContextFlags::Text) &&
1674 aSelector != nullptr && [self respondsToSelector: aSelector] )
1676 [self performSelector: aSelector];
1680 [self sendSingleCharacter:mpLastEvent];
1684 mbKeyHandled = true;
1687 -(void)clearLastEvent
1692 - (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
1694 // FIXME - These should probably be used?
1698 SolarMutexGuard aGuard;
1700 SalExtTextInputPosEvent aPosEvent;
1701 mpFrame->CallCallback( SalEvent::ExtTextInputPos, static_cast<void *>(&aPosEvent) );
1705 rect.origin.x = aPosEvent.mnX + mpFrame->maGeometry.nX;
1706 rect.origin.y = aPosEvent.mnY + mpFrame->maGeometry.nY + 4; // add some space for underlines
1707 rect.size.width = aPosEvent.mnWidth;
1708 rect.size.height = aPosEvent.mnHeight;
1710 mpFrame->VCLToCocoa( rect );
1714 -(id)parentAttribute {
1715 return reinterpret_cast<NSView*>(mpFrame->getNSWindow());
1716 //TODO: odd cast really needed for fdo#74121?
1719 -(css::accessibility::XAccessibleContext *)accessibleContext
1721 if ( !mpReferenceWrapper ) {
1722 // some frames never become visible ..
1723 vcl::Window *pWindow = mpFrame -> GetWindow();
1727 mpReferenceWrapper = new ReferenceWrapper;
1728 mpReferenceWrapper -> rAccessibleContext = pWindow -> /*GetAccessibleChildWindow( 0 ) ->*/ GetAccessible() -> getAccessibleContext();
1729 [ AquaA11yFactory insertIntoWrapperRepository: self forAccessibleContext: mpReferenceWrapper -> rAccessibleContext ];
1731 return [ super accessibleContext ];
1734 -(NSWindow*)windowForParent
1736 return mpFrame->getNSWindow();
1739 -(void)registerMouseEventListener: (id)theListener
1741 mpMouseEventListener = theListener;
1744 -(void)unregisterMouseEventListener: (id)theListener
1747 mpMouseEventListener = nil;
1750 -(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
1752 return [mDraggingDestinationHandler draggingEntered: sender];
1755 -(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
1757 return [mDraggingDestinationHandler draggingUpdated: sender];
1760 -(void)draggingExited:(id <NSDraggingInfo>)sender
1762 [mDraggingDestinationHandler draggingExited: sender];
1765 -(BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
1767 return [mDraggingDestinationHandler prepareForDragOperation: sender];
1770 -(BOOL)performDragOperation:(id <NSDraggingInfo>)sender
1772 return [mDraggingDestinationHandler performDragOperation: sender];
1775 -(void)concludeDragOperation:(id <NSDraggingInfo>)sender
1777 [mDraggingDestinationHandler concludeDragOperation: sender];
1780 -(void)registerDraggingDestinationHandler:(id)theHandler
1782 mDraggingDestinationHandler = theHandler;
1785 -(void)unregisterDraggingDestinationHandler:(id)theHandler
1788 mDraggingDestinationHandler = nil;
1793 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */