1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <sal/config.h>
21
22#include <sal/macros.h>
23#include <tools/helpers.hxx>
24
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>
31
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>
38
39#define WHEEL_EVENT_FACTOR 1.5
40
41static sal_uInt16 ImplGetModifierMask( unsigned int nMask )
42{
43    sal_uInt16 nRet = 0;
44SAL_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 )
50        nRet |= KEY_SHIFT;
51    if( (nMask & NSControlKeyMask) != 0 )
52        nRet |= KEY_MOD3;
53    if( (nMask & NSAlternateKeyMask) != 0 )
54        nRet |= KEY_MOD2;
55    if( (nMask & NSCommandKeyMask) != 0 )
56        nRet |= KEY_MOD1;
57SAL_WNODEPRECATED_DECLARATIONS_POP
58    return nRet;
59}
60
61static sal_uInt16 ImplMapCharCode( sal_Unicode aCode )
62{
63    static sal_uInt16 aKeyCodeMap[ 128 ] =
64    {
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
81    };
82
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
86
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)
90
91    static sal_uInt16 aFunctionKeyCodeMap[ 128 ] =
92    {
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
109    };
110
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 ];
116    return nKeyCode;
117}
118
119static sal_uInt16 ImplMapKeyCode(sal_uInt16 nKeyCode)
120{
121    /*
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
124     */
125
126    static sal_uInt16 aKeyCodeMap[ 0x80 ] =
127    {
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
144    };
145
146    if (nKeyCode < SAL_N_ELEMENTS(aKeyCodeMap))
147        return aKeyCodeMap[nKeyCode];
148    return 0;
149}
150
151// store the frame the mouse last entered
152static AquaSalFrame* s_pMouseFrame = nullptr;
153// store the last pressed button for enter/exit events
154// which lack that information
155static sal_uInt16 s_nLastButton = 0;
156
157static AquaSalFrame* getMouseContainerFrame()
158{
159    AquaSalFrame* pDispatchFrame = nullptr;
160    NSArray* aWindows = [NSWindow windowNumbersWithOptions:0];
161    for(NSUInteger i = 0; i < [aWindows count] && ! pDispatchFrame; i++ )
162    {
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];
166    }
167    return pDispatchFrame;
168}
169
170@implementation SalFrameWindow
171-(id)initWithSalFrame: (AquaSalFrame*)pFrame
172{
173    mDraggingDestinationHandler = nil;
174    mpFrame = pFrame;
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()];
182
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
186    // intermixedly.
187
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.)
192
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.)
195
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.
200
201    [pNSWindow setCollectionBehavior: NSWindowCollectionBehaviorFullScreenNone];
202
203    // Disable window restoration until we support it directly
204    [pNSWindow setRestorable: NO];
205
206    return static_cast<SalFrameWindow *>(pNSWindow);
207}
208
209-(AquaSalFrame*)getSalFrame
210{
211    return mpFrame;
212}
213
214-(void)displayIfNeeded
215{
216    if( GetSalData() && GetSalData()->mpInstance )
217    {
218        SolarMutexGuard aGuard;
219        [super displayIfNeeded];
220    }
221}
222
223-(BOOL)containsMouse
224{
225    // is this event actually inside that NSWindow ?
226    NSPoint aPt = [NSEvent mouseLocation];
227    NSRect aFrameRect = [self frame];
228    BOOL bInRect = NSPointInRect( aPt, aFrameRect );
229    return bInRect;
230}
231
232-(BOOL)canBecomeKeyWindow
233{
234    if( (mpFrame->mnStyle &
235            ( SalFrameStyleFlags::FLOAT                 |
236              SalFrameStyleFlags::TOOLTIP               |
237              SalFrameStyleFlags::INTRO
238            )) == SalFrameStyleFlags::NONE )
239        return YES;
240    if( mpFrame->mnStyle & SalFrameStyleFlags::OWNERDRAWDECORATION )
241        return YES;
242    if( mpFrame->mbFullScreen )
243        return YES;
244    return [super canBecomeKeyWindow];
245}
246
247-(void)windowDidBecomeKey: (NSNotification*)pNotification
248{
249    (void)pNotification;
250    SolarMutexGuard aGuard;
251
252    if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
253    {
254        static const SalFrameStyleFlags nGuessDocument = SalFrameStyleFlags::MOVEABLE|
255                                            SalFrameStyleFlags::SIZEABLE|
256                                            SalFrameStyleFlags::CLOSEABLE;
257
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
263        {
264            AquaSalMenu::setDefaultMenu();
265        }
266        #if 0
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 );
272        #endif
273        mpFrame->CallCallback( SalEvent::GetFocus, nullptr );
274        mpFrame->SendPaintEvent(); // repaint controls as active
275    }
276}
277
278-(void)windowDidResignKey: (NSNotification*)pNotification
279{
280    (void)pNotification;
281    SolarMutexGuard aGuard;
282
283    if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
284    {
285        mpFrame->CallCallback(SalEvent::LoseFocus, nullptr);
286        mpFrame->SendPaintEvent(); // repaint controls as inactive
287    }
288}
289
290-(void)windowDidChangeScreen: (NSNotification*)pNotification
291{
292    (void)pNotification;
293    SolarMutexGuard aGuard;
294
295    if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
296        mpFrame->screenParametersChanged();
297}
298
299-(void)windowDidMove: (NSNotification*)pNotification
300{
301    (void)pNotification;
302    SolarMutexGuard aGuard;
303
304    if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
305    {
306        mpFrame->UpdateFrameGeometry();
307        mpFrame->CallCallback( SalEvent::Move, nullptr );
308    }
309}
310
311-(void)windowDidResize: (NSNotification*)pNotification
312{
313    (void)pNotification;
314    SolarMutexGuard aGuard;
315
316    if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
317    {
318        mpFrame->UpdateFrameGeometry();
319        mpFrame->CallCallback( SalEvent::Resize, nullptr );
320        mpFrame->SendPaintEvent();
321    }
322}
323
324-(void)windowDidMiniaturize: (NSNotification*)pNotification
325{
326    (void)pNotification;
327    SolarMutexGuard aGuard;
328
329    if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
330    {
331        mpFrame->mbShown = false;
332        mpFrame->UpdateFrameGeometry();
333        mpFrame->CallCallback( SalEvent::Resize, nullptr );
334    }
335}
336
337-(void)windowDidDeminiaturize: (NSNotification*)pNotification
338{
339    (void)pNotification;
340    SolarMutexGuard aGuard;
341
342    if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
343    {
344        mpFrame->mbShown = true;
345        mpFrame->UpdateFrameGeometry();
346        mpFrame->CallCallback( SalEvent::Resize, nullptr );
347    }
348}
349
350-(BOOL)windowShouldClose: (NSNotification*)pNotification
351{
352    (void)pNotification;
353    SolarMutexGuard aGuard;
354
355    BOOL bRet = YES;
356    if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
357    {
358        // #i84461# end possible input
359        mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
360        if( AquaSalFrame::isAlive( mpFrame ) )
361        {
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 );
365            assert( pTimer );
366            pTimer->handleWindowShouldClose();
367        }
368    }
369
370    return bRet;
371}
372
373-(void)windowDidEnterFullScreen: (NSNotification*)pNotification
374{
375    SolarMutexGuard aGuard;
376
377    if( !mpFrame || !AquaSalFrame::isAlive( mpFrame))
378        return;
379    mpFrame->mbFullScreen = true;
380    (void)pNotification;
381}
382
383-(void)windowDidExitFullScreen: (NSNotification*)pNotification
384{
385    SolarMutexGuard aGuard;
386
387    if( !mpFrame || !AquaSalFrame::isAlive( mpFrame))
388        return;
389    mpFrame->mbFullScreen = false;
390    (void)pNotification;
391}
392
393-(void)dockMenuItemTriggered: (id)sender
394{
395    (void)sender;
396    SolarMutexGuard aGuard;
397
398    if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
399        mpFrame->ToTop( SalFrameToTop::RestoreWhenMin | SalFrameToTop::GrabFocus );
400}
401
402-(css::uno::Reference < css::accessibility::XAccessibleContext >)accessibleContext
403{
404    return mpFrame -> GetWindow() -> GetAccessible() -> getAccessibleContext();
405}
406
407-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
408{
409  return [mDraggingDestinationHandler draggingEntered: sender];
410}
411
412-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
413{
414  return [mDraggingDestinationHandler draggingUpdated: sender];
415}
416
417-(void)draggingExited:(id <NSDraggingInfo>)sender
418{
419  [mDraggingDestinationHandler draggingExited: sender];
420}
421
422-(BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
423{
424  return [mDraggingDestinationHandler prepareForDragOperation: sender];
425}
426
427-(BOOL)performDragOperation:(id <NSDraggingInfo>)sender
428{
429  return [mDraggingDestinationHandler performDragOperation: sender];
430}
431
432-(void)concludeDragOperation:(id <NSDraggingInfo>)sender
433{
434  [mDraggingDestinationHandler concludeDragOperation: sender];
435}
436
437-(void)registerDraggingDestinationHandler:(id)theHandler
438{
439  mDraggingDestinationHandler = theHandler;
440}
441
442-(void)unregisterDraggingDestinationHandler:(id)theHandler
443{
444    (void)theHandler;
445    mDraggingDestinationHandler = nil;
446}
447
448@end
449
450@implementation SalFrameView
451+(void)unsetMouseFrame: (AquaSalFrame*)pFrame
452{
453    if( pFrame == s_pMouseFrame )
454        s_pMouseFrame = nullptr;
455}
456
457-(id)initWithSalFrame: (AquaSalFrame*)pFrame
458{
459    if ((self = [super initWithFrame: [NSWindow contentRectForFrameRect: [pFrame->getNSWindow() frame] styleMask: pFrame->mnStyleMask]]) != nil)
460    {
461        mDraggingDestinationHandler = nil;
462        mpFrame = pFrame;
463        mMarkedRange = NSMakeRange(NSNotFound, 0);
464        mSelectedRange = NSMakeRange(NSNotFound, 0);
465        mpReferenceWrapper = nil;
466        mpMouseEventListener = nil;
467        mpLastSuperEvent = nil;
468    }
469
470    mfLastMagnifyTime = 0.0;
471    return self;
472}
473
474-(AquaSalFrame*)getSalFrame
475{
476    return mpFrame;
477}
478
479-(void)resetCursorRects
480{
481    if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
482    {
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()];
486    }
487}
488
489-(BOOL)acceptsFirstResponder
490{
491    return YES;
492}
493
494-(BOOL)acceptsFirstMouse: (NSEvent*)pEvent
495{
496    (void)pEvent;
497    return YES;
498}
499
500-(BOOL)isOpaque
501{
502    if( !mpFrame)
503        return YES;
504    if( !AquaSalFrame::isAlive( mpFrame))
505        return YES;
506    if( !mpFrame->getClipPath())
507        return YES;
508    return NO;
509}
510
511-(void)drawRect: (NSRect)aRect
512{
513    AquaSalInstance *pInstance = GetSalData()->mpInstance;
514    assert(pInstance);
515    if (!pInstance)
516        return;
517
518    SolarMutexGuard aGuard;
519    if (!mpFrame || !AquaSalFrame::isAlive(mpFrame))
520        return;
521
522    const bool bIsLiveResize = [self inLiveResize];
523    const bool bWasLiveResize = pInstance->mbIsLiveResize;
524    if (bWasLiveResize != bIsLiveResize)
525    {
526        pInstance->mbIsLiveResize = bIsLiveResize;
527        Scheduler::ProcessTaskScheduling();
528    }
529
530    AquaSalGraphics* pGraphics = mpFrame->mpGraphics;
531    if (pGraphics)
532    {
533        pGraphics->UpdateWindow(aRect);
534        if (mpFrame->getClipPath())
535            [mpFrame->getNSWindow() invalidateShadow];
536    }
537}
538
539-(void)sendMouseEventToFrame: (NSEvent*)pEvent button:(sal_uInt16)nButton eventtype:(SalEvent)nEvent
540{
541    SolarMutexGuard aGuard;
542
543    AquaSalFrame* pDispatchFrame = AquaSalFrame::GetCaptureFrame();
544    bool bIsCaptured = false;
545    if( pDispatchFrame )
546    {
547        bIsCaptured = true;
548        if( nEvent == SalEvent::MouseLeave ) // no leave events if mouse is captured
549            nEvent = SalEvent::MouseMove;
550    }
551    else if( s_pMouseFrame )
552        pDispatchFrame = s_pMouseFrame;
553    else
554        pDispatchFrame = mpFrame;
555
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.
562    */
563    if( ! bIsCaptured && nButton && pDispatchFrame && AquaSalFrame::isAlive( pDispatchFrame ) )
564    {
565        // is this event actually inside that NSWindow ?
566        NSPoint aPt = [NSEvent mouseLocation];
567        NSRect aFrameRect = [pDispatchFrame->getNSWindow() frame];
568
569        if ( ! NSPointInRect( aPt, aFrameRect ) )
570        {
571            // no, it is not
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
575               code:
576
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];
581
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.
586            */
587            AquaSalFrame* pMouseFrame = getMouseContainerFrame();
588            if( pMouseFrame )
589                pDispatchFrame = pMouseFrame;
590        }
591    }
592
593    if( pDispatchFrame && AquaSalFrame::isAlive( pDispatchFrame ) )
594    {
595        pDispatchFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
596        pDispatchFrame->mnLastModifierFlags = [pEvent modifierFlags];
597
598        NSPoint aPt = [NSEvent mouseLocation];
599        pDispatchFrame->CocoaToVCL( aPt );
600
601        sal_uInt16 nModMask = ImplGetModifierMask( [pEvent modifierFlags] );
602        // #i82284# emulate ctrl left
603        if( nModMask == KEY_MOD3 && nButton == MOUSE_LEFT )
604        {
605            nModMask    = 0;
606            nButton     = MOUSE_RIGHT;
607        }
608
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;
615
616        if( AllSettings::GetLayoutRTL() )
617            aEvent.mnX = pDispatchFrame->maGeometry.nWidth-1-aEvent.mnX;
618
619        pDispatchFrame->CallCallback( nEvent, &aEvent );
620    }
621}
622
623-(void)mouseDown: (NSEvent*)pEvent
624{
625    if ( mpMouseEventListener != nil &&
626        [mpMouseEventListener respondsToSelector: @selector(mouseDown:)])
627    {
628        [mpMouseEventListener mouseDown: [pEvent copyWithZone: nullptr]];
629    }
630
631    s_nLastButton = MOUSE_LEFT;
632    [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SalEvent::MouseButtonDown];
633}
634
635-(void)mouseDragged: (NSEvent*)pEvent
636{
637    if ( mpMouseEventListener != nil &&
638         [mpMouseEventListener respondsToSelector: @selector(mouseDragged:)])
639    {
640        [mpMouseEventListener mouseDragged: [pEvent copyWithZone: nullptr]];
641    }
642    s_nLastButton = MOUSE_LEFT;
643    [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SalEvent::MouseMove];
644}
645
646-(void)mouseUp: (NSEvent*)pEvent
647{
648    s_nLastButton = 0;
649    [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SalEvent::MouseButtonUp];
650}
651
652-(void)mouseMoved: (NSEvent*)pEvent
653{
654    s_nLastButton = 0;
655    [self sendMouseEventToFrame:pEvent button:0 eventtype:SalEvent::MouseMove];
656}
657
658-(void)mouseEntered: (NSEvent*)pEvent
659{
660    s_pMouseFrame = mpFrame;
661
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];
666}
667
668-(void)mouseExited: (NSEvent*)pEvent
669{
670    if( s_pMouseFrame == mpFrame )
671        s_pMouseFrame = nullptr;
672
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];
677}
678
679-(void)rightMouseDown: (NSEvent*)pEvent
680{
681    s_nLastButton = MOUSE_RIGHT;
682    [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SalEvent::MouseButtonDown];
683}
684
685-(void)rightMouseDragged: (NSEvent*)pEvent
686{
687    s_nLastButton = MOUSE_RIGHT;
688    [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SalEvent::MouseMove];
689}
690
691-(void)rightMouseUp: (NSEvent*)pEvent
692{
693    s_nLastButton = 0;
694    [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SalEvent::MouseButtonUp];
695}
696
697-(void)otherMouseDown: (NSEvent*)pEvent
698{
699    if( [pEvent buttonNumber] == 2 )
700    {
701        s_nLastButton = MOUSE_MIDDLE;
702        [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SalEvent::MouseButtonDown];
703    }
704    else
705        s_nLastButton = 0;
706}
707
708-(void)otherMouseDragged: (NSEvent*)pEvent
709{
710    if( [pEvent buttonNumber] == 2 )
711    {
712        s_nLastButton = MOUSE_MIDDLE;
713        [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SalEvent::MouseMove];
714    }
715    else
716        s_nLastButton = 0;
717}
718
719-(void)otherMouseUp: (NSEvent*)pEvent
720{
721    s_nLastButton = 0;
722    if( [pEvent buttonNumber] == 2 )
723        [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SalEvent::MouseButtonUp];
724}
725
726- (void)magnifyWithEvent: (NSEvent*)pEvent
727{
728    SolarMutexGuard aGuard;
729
730    // TODO: ??  -(float)magnification;
731    if( AquaSalFrame::isAlive( mpFrame ) )
732    {
733        const NSTimeInterval fMagnifyTime = [pEvent timestamp];
734        mpFrame->mnLastEventTime = static_cast<sal_uInt64>( fMagnifyTime * 1000.0 );
735        mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
736
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);
740
741        if( bNewSeries )
742            mfMagnifyDeltaSum = 0.0;
743        mfMagnifyDeltaSum += [pEvent magnification];
744
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 )
750            return;
751
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 );
756        if( !nDeltaZ )
757        {
758            // handle new series immediately
759            if( !bNewSeries )
760                return;
761            nDeltaZ = (fDeltaZ >= 0.0) ? +1 : -1;
762        }
763        // eventually give credit for delta sum
764        mfMagnifyDeltaSum -= nDeltaZ / fMagnifyFactor;
765
766        NSPoint aPt = [NSEvent mouseLocation];
767        mpFrame->CocoaToVCL( aPt );
768
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;
776
777        if( AllSettings::GetLayoutRTL() )
778            aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
779
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)
787            nScrollLines = 1;
788        aEvent.mnScrollLines = nScrollLines;
789        mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent );
790    }
791}
792
793- (void)rotateWithEvent: (NSEvent*)pEvent
794{
795    //Rotation : -(float)rotation;
796    // TODO: create new CommandType so rotation is available to the applications
797    (void)pEvent;
798}
799
800- (void)swipeWithEvent: (NSEvent*)pEvent
801{
802    SolarMutexGuard aGuard;
803
804    if( AquaSalFrame::isAlive( mpFrame ) )
805    {
806        mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
807        mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
808
809        // merge pending scroll wheel events
810        CGFloat dX = 0.0;
811        CGFloat dY = 0.0;
812        for(;;)
813        {
814            dX += [pEvent deltaX];
815            dY += [pEvent deltaY];
816SAL_WNODEPRECATED_DECLARATIONS_PUSH
817    // 'NSScrollWheelMask' is deprecated: first deprecated in macOS 10.12
818            NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask
819SAL_WNODEPRECATED_DECLARATIONS_POP
820            untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ];
821            if( !pNextEvent )
822                break;
823            pEvent = pNextEvent;
824        }
825
826        NSPoint aPt = [NSEvent mouseLocation];
827        mpFrame->CocoaToVCL( aPt );
828
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;
835
836        if( AllSettings::GetLayoutRTL() )
837            aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
838
839        if( dX != 0.0 )
840        {
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 );
848        }
849        if( dY != 0.0 && AquaSalFrame::isAlive( mpFrame ))
850        {
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 );
858        }
859    }
860}
861
862-(void)scrollWheel: (NSEvent*)pEvent
863{
864    SolarMutexGuard aGuard;
865
866    if( AquaSalFrame::isAlive( mpFrame ) )
867    {
868        mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
869        mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
870
871        // merge pending scroll wheel events
872        CGFloat dX = 0.0;
873        CGFloat dY = 0.0;
874        for(;;)
875        {
876            dX += [pEvent deltaX];
877            dY += [pEvent deltaY];
878SAL_WNODEPRECATED_DECLARATIONS_PUSH
879    // 'NSScrollWheelMask' is deprecated: first deprecated in macOS 10.12
880            NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask
881SAL_WNODEPRECATED_DECLARATIONS_POP
882                untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ];
883            if( !pNextEvent )
884                break;
885            pEvent = pNextEvent;
886        }
887
888        NSPoint aPt = [NSEvent mouseLocation];
889        mpFrame->CocoaToVCL( aPt );
890
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;
897
898        if( AllSettings::GetLayoutRTL() )
899            aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
900
901        if( dX != 0.0 )
902        {
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)
910                nScrollLines = 1;
911            aEvent.mnScrollLines = nScrollLines;
912
913            mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent );
914        }
915        if( dY != 0.0 && AquaSalFrame::isAlive( mpFrame ) )
916        {
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)
924                nScrollLines = 1;
925            aEvent.mnScrollLines = nScrollLines;
926
927            mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent );
928        }
929    }
930}
931
932
933-(void)keyDown: (NSEvent*)pEvent
934{
935    SolarMutexGuard aGuard;
936
937    if( AquaSalFrame::isAlive( mpFrame ) )
938    {
939        mpLastEvent = pEvent;
940        mbInKeyInput = true;
941        mbNeedSpecialKeyHandle = false;
942        mbKeyHandled = false;
943
944        mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
945        mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
946
947        if( ! [self handleKeyDownException: pEvent] )
948        {
949            NSArray* pArray = [NSArray arrayWithObject: pEvent];
950            [self interpretKeyEvents: pArray];
951        }
952
953        mbInKeyInput = false;
954    }
955}
956
957-(BOOL)handleKeyDownException:(NSEvent*)pEvent
958{
959    // check for a very special set of modified characters
960    NSString* pUnmodifiedString = [pEvent charactersIgnoringModifiers];
961
962    if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
963    {
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
967        */
968SAL_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) )
973SAL_WNODEPRECATED_DECLARATIONS_POP
974        {
975            if( [self sendSingleCharacter: mpLastEvent] )
976                return YES;
977        }
978    }
979    return NO;
980}
981
982-(void)flagsChanged: (NSEvent*)pEvent
983{
984    SolarMutexGuard aGuard;
985
986    if( AquaSalFrame::isAlive( mpFrame ) )
987    {
988        mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
989        mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
990    }
991}
992
993-(void)insertText:(id)aString replacementRange:(NSRange)replacementRange
994{
995    (void) replacementRange; // FIXME: surely it must be used
996
997    SolarMutexGuard aGuard;
998
999    if( AquaSalFrame::isAlive( mpFrame ) )
1000    {
1001        NSString* pInsert = nil;
1002        if( [aString isMemberOfClass: [NSAttributedString class]] )
1003            pInsert = [aString string];
1004        else
1005            pInsert = aString;
1006
1007        int nLen = 0;
1008        if( pInsert && ( nLen = [pInsert length] ) > 0 )
1009        {
1010            OUString aInsertString( GetOUString( pInsert ) );
1011             // aCharCode initializer is safe since aInsertString will at least contain '\0'
1012            sal_Unicode aCharCode = *aInsertString.getStr();
1013
1014            if( nLen == 1 &&
1015                aCharCode < 0x80 &&
1016                aCharCode > 0x1f &&
1017                ! [self hasMarkedText ]
1018                )
1019            {
1020                sal_uInt16 nKeyCode = ImplMapCharCode( aCharCode );
1021                unsigned int nLastModifiers = mpFrame->mnLastModifierFlags;
1022
1023                // #i99567#
1024                // find out the unmodified key code
1025
1026SAL_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
1032                // sanity check
1033                if( mpLastEvent && ( [mpLastEvent type] == NSKeyDown || [mpLastEvent type] == NSKeyUp ) )
1034                {
1035                    // get unmodified string
1036                    NSString* pUnmodifiedString = [mpLastEvent charactersIgnoringModifiers];
1037                    if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
1038                    {
1039                        // map the unmodified key code
1040                        unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
1041                        nKeyCode = ImplMapCharCode( keyChar );
1042                    }
1043                    nLastModifiers = [mpLastEvent modifierFlags];
1044
1045                }
1046                // #i99567#
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 )
1052                {
1053                    nLastModifiers = 0;
1054                }
1055SAL_WNODEPRECATED_DECLARATIONS_POP
1056                [self sendKeyInputAndReleaseToFrame: nKeyCode character: aCharCode modifiers: nLastModifiers];
1057            }
1058            else
1059            {
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 );
1068            }
1069        }
1070        else
1071        {
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 );
1080
1081        }
1082        mbKeyHandled = true;
1083        [self unmarkText];
1084    }
1085}
1086
1087-(void)insertTab: (id)aSender
1088{
1089    (void)aSender;
1090    [self sendKeyInputAndReleaseToFrame: KEY_TAB character: '\t' modifiers: 0];
1091}
1092
1093-(void)insertBacktab: (id)aSender
1094{
1095    (void)aSender;
1096    [self sendKeyInputAndReleaseToFrame: (KEY_TAB | KEY_SHIFT) character: '\t' modifiers: 0];
1097}
1098
1099-(void)moveLeft: (id)aSender
1100{
1101    (void)aSender;
1102    [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: 0];
1103}
1104
1105-(void)moveLeftAndModifySelection: (id)aSender
1106{
1107    (void)aSender;
1108SAL_WNODEPRECATED_DECLARATIONS_PUSH
1109        // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12
1110    [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: NSShiftKeyMask];
1111SAL_WNODEPRECATED_DECLARATIONS_POP
1112}
1113
1114-(void)moveBackwardAndModifySelection: (id)aSender
1115{
1116    (void)aSender;
1117    [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_BACKWARD character: 0  modifiers: 0];
1118}
1119
1120-(void)moveRight: (id)aSender
1121{
1122    (void)aSender;
1123    [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: 0];
1124}
1125
1126-(void)moveRightAndModifySelection: (id)aSender
1127{
1128    (void)aSender;
1129SAL_WNODEPRECATED_DECLARATIONS_PUSH
1130        // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12
1131    [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: NSShiftKeyMask];
1132SAL_WNODEPRECATED_DECLARATIONS_POP
1133}
1134
1135-(void)moveForwardAndModifySelection: (id)aSender
1136{
1137    (void)aSender;
1138    [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_FORWARD character: 0  modifiers: 0];
1139}
1140
1141-(void)moveWordLeft: (id)aSender
1142{
1143    (void)aSender;
1144    [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_BACKWARD character: 0  modifiers: 0];
1145}
1146
1147-(void)moveWordBackward: (id)aSender
1148{
1149    (void)aSender;
1150    [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_BACKWARD character: 0  modifiers: 0];
1151}
1152
1153-(void)moveWordBackwardAndModifySelection: (id)aSender
1154{
1155    (void)aSender;
1156    [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_BACKWARD character: 0  modifiers: 0];
1157}
1158
1159-(void)moveWordLeftAndModifySelection: (id)aSender
1160{
1161    (void)aSender;
1162    [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_BACKWARD character: 0  modifiers: 0];
1163}
1164
1165-(void)moveWordRight: (id)aSender
1166{
1167    (void)aSender;
1168    [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_FORWARD character: 0  modifiers: 0];
1169}
1170
1171-(void)moveWordForward: (id)aSender
1172{
1173    (void)aSender;
1174    [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_FORWARD character: 0  modifiers: 0];
1175}
1176
1177-(void)moveWordForwardAndModifySelection: (id)aSender
1178{
1179    (void)aSender;
1180    [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_FORWARD character: 0  modifiers: 0];
1181}
1182
1183-(void)moveWordRightAndModifySelection: (id)aSender
1184{
1185    (void)aSender;
1186    [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_FORWARD character: 0  modifiers: 0];
1187}
1188
1189-(void)moveToEndOfLine: (id)aSender
1190{
1191    (void)aSender;
1192    [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_LINE character: 0  modifiers: 0];
1193}
1194
1195-(void)moveToRightEndOfLine: (id)aSender
1196{
1197    (void)aSender;
1198    [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_LINE character: 0  modifiers: 0];
1199}
1200
1201-(void)moveToEndOfLineAndModifySelection: (id)aSender
1202{
1203    (void)aSender;
1204    [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_LINE character: 0  modifiers: 0];
1205}
1206
1207-(void)moveToRightEndOfLineAndModifySelection: (id)aSender
1208{
1209    (void)aSender;
1210    [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_LINE character: 0  modifiers: 0];
1211}
1212
1213-(void)moveToBeginningOfLine: (id)aSender
1214{
1215    (void)aSender;
1216    [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0  modifiers: 0];
1217}
1218
1219-(void)moveToLeftEndOfLine: (id)aSender
1220{
1221    (void)aSender;
1222    [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0  modifiers: 0];
1223}
1224
1225-(void)moveToBeginningOfLineAndModifySelection: (id)aSender
1226{
1227    (void)aSender;
1228    [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0  modifiers: 0];
1229}
1230
1231-(void)moveToLeftEndOfLineAndModifySelection: (id)aSender
1232{
1233    (void)aSender;
1234    [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0  modifiers: 0];
1235}
1236
1237-(void)moveToEndOfParagraph: (id)aSender
1238{
1239    (void)aSender;
1240    [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0  modifiers: 0];
1241}
1242
1243-(void)moveToEndOfParagraphAndModifySelection: (id)aSender
1244{
1245    (void)aSender;
1246    [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0  modifiers: 0];
1247}
1248
1249-(void)moveParagraphForward: (id)aSender
1250{
1251    (void)aSender;
1252    [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0  modifiers: 0];
1253}
1254
1255-(void)moveParagraphForwardAndModifySelection: (id)aSender
1256{
1257    (void)aSender;
1258    [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0  modifiers: 0];
1259}
1260
1261-(void)moveToBeginningOfParagraph: (id)aSender
1262{
1263    (void)aSender;
1264    [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0  modifiers: 0];
1265}
1266
1267-(void)moveParagraphBackward: (id)aSender
1268{
1269    (void)aSender;
1270    [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0  modifiers: 0];
1271}
1272
1273-(void)moveToBeginningOfParagraphAndModifySelection: (id)aSender
1274{
1275    (void)aSender;
1276    [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0  modifiers: 0];
1277}
1278
1279-(void)moveParagraphBackwardAndModifySelection: (id)aSender
1280{
1281    (void)aSender;
1282    [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0  modifiers: 0];
1283}
1284
1285-(void)moveToEndOfDocument: (id)aSender
1286{
1287    (void)aSender;
1288    [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_DOCUMENT character: 0  modifiers: 0];
1289}
1290
1291-(void)scrollToEndOfDocument: (id)aSender
1292{
1293    (void)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];
1296}
1297
1298-(void)moveToEndOfDocumentAndModifySelection: (id)aSender
1299{
1300    (void)aSender;
1301    [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_DOCUMENT character: 0  modifiers: 0];
1302}
1303
1304-(void)moveToBeginningOfDocument: (id)aSender
1305{
1306    (void)aSender;
1307    [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT character: 0  modifiers: 0];
1308}
1309
1310-(void)scrollToBeginningOfDocument: (id)aSender
1311{
1312    (void)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];
1315}
1316
1317-(void)moveToBeginningOfDocumentAndModifySelection: (id)aSender
1318{
1319    (void)aSender;
1320    [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT character: 0  modifiers: 0];
1321}
1322
1323-(void)moveUp: (id)aSender
1324{
1325    (void)aSender;
1326    [self sendKeyInputAndReleaseToFrame: KEY_UP character: 0 modifiers: 0];
1327}
1328
1329-(void)moveDown: (id)aSender
1330{
1331    (void)aSender;
1332    [self sendKeyInputAndReleaseToFrame: KEY_DOWN character: 0 modifiers: 0];
1333}
1334
1335-(void)insertNewline: (id)aSender
1336{
1337    (void)aSender;
1338    // #i91267# make enter and shift-enter work by evaluating the modifiers
1339    [self sendKeyInputAndReleaseToFrame: KEY_RETURN character: '\n' modifiers: mpFrame->mnLastModifierFlags];
1340}
1341
1342-(void)deleteBackward: (id)aSender
1343{
1344    (void)aSender;
1345    [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0];
1346}
1347
1348-(void)deleteForward: (id)aSender
1349{
1350    (void)aSender;
1351    [self sendKeyInputAndReleaseToFrame: KEY_DELETE character: 0x7f modifiers: 0];
1352}
1353
1354-(void)deleteBackwardByDecomposingPreviousCharacter: (id)aSender
1355{
1356    (void)aSender;
1357    [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0];
1358}
1359
1360-(void)deleteWordBackward: (id)aSender
1361{
1362    (void)aSender;
1363    [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_WORD_BACKWARD character: 0  modifiers: 0];
1364}
1365
1366-(void)deleteWordForward: (id)aSender
1367{
1368    (void)aSender;
1369    [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_WORD_FORWARD character: 0  modifiers: 0];
1370}
1371
1372-(void)deleteToBeginningOfLine: (id)aSender
1373{
1374    (void)aSender;
1375    [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_BEGIN_OF_LINE character: 0  modifiers: 0];
1376}
1377
1378-(void)deleteToEndOfLine: (id)aSender
1379{
1380    (void)aSender;
1381    [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_END_OF_LINE character: 0  modifiers: 0];
1382}
1383
1384-(void)deleteToBeginningOfParagraph: (id)aSender
1385{
1386    (void)aSender;
1387    [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_BEGIN_OF_PARAGRAPH character: 0  modifiers: 0];
1388}
1389
1390-(void)deleteToEndOfParagraph: (id)aSender
1391{
1392    (void)aSender;
1393    [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_END_OF_PARAGRAPH character: 0  modifiers: 0];
1394}
1395
1396-(void)insertLineBreak: (id)aSender
1397{
1398    (void)aSender;
1399    [self sendKeyInputAndReleaseToFrame: css::awt::Key::INSERT_LINEBREAK character: 0  modifiers: 0];
1400}
1401
1402-(void)insertParagraphSeparator: (id)aSender
1403{
1404    (void)aSender;
1405    [self sendKeyInputAndReleaseToFrame: css::awt::Key::INSERT_PARAGRAPH character: 0  modifiers: 0];
1406}
1407
1408-(void)selectWord: (id)aSender
1409{
1410    (void)aSender;
1411    [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD character: 0  modifiers: 0];
1412}
1413
1414-(void)selectLine: (id)aSender
1415{
1416    (void)aSender;
1417    [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_LINE character: 0  modifiers: 0];
1418}
1419
1420-(void)selectParagraph: (id)aSender
1421{
1422    (void)aSender;
1423    [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_PARAGRAPH character: 0  modifiers: 0];
1424}
1425
1426-(void)selectAll: (id)aSender
1427{
1428    (void)aSender;
1429    [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_ALL character: 0  modifiers: 0];
1430}
1431
1432-(void)cancelOperation: (id)aSender
1433{
1434    (void)aSender;
1435    [self sendKeyInputAndReleaseToFrame: KEY_ESCAPE character: 0x1b modifiers: 0];
1436}
1437
1438-(void)noop: (id)aSender
1439{
1440    (void)aSender;
1441    if( ! mbKeyHandled )
1442    {
1443        if( ! [self sendSingleCharacter:mpLastEvent] )
1444        {
1445            /* prevent recursion */
1446            if( mpLastEvent != mpLastSuperEvent && [NSApp respondsToSelector: @selector(sendSuperEvent:)] )
1447            {
1448                id pLastSuperEvent = mpLastSuperEvent;
1449                mpLastSuperEvent = mpLastEvent;
1450                [NSApp performSelector:@selector(sendSuperEvent:) withObject: mpLastEvent];
1451                mpLastSuperEvent = pLastSuperEvent;
1452
1453                std::map< NSEvent*, bool >::iterator it = GetSalData()->maKeyEventAnswer.find( mpLastEvent );
1454                if( it != GetSalData()->maKeyEventAnswer.end() )
1455                    it->second = true;
1456            }
1457        }
1458    }
1459}
1460
1461-(BOOL)sendKeyInputAndReleaseToFrame: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar
1462{
1463    return [self sendKeyInputAndReleaseToFrame: nKeyCode character: aChar modifiers: mpFrame->mnLastModifierFlags];
1464}
1465
1466-(BOOL)sendKeyInputAndReleaseToFrame: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod
1467{
1468    return [self sendKeyToFrameDirect: nKeyCode character: aChar modifiers: nMod] ||
1469           [self sendSingleCharacter: mpLastEvent];
1470}
1471
1472-(BOOL)sendKeyToFrameDirect: (sal_uInt16)nKeyCode  character: (sal_Unicode)aChar modifiers: (unsigned int)nMod
1473{
1474    SolarMutexGuard aGuard;
1475
1476    bool nRet = false;
1477    if( AquaSalFrame::isAlive( mpFrame ) )
1478    {
1479        SalKeyEvent aEvent;
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() )
1486            it->second = nRet;
1487        if( AquaSalFrame::isAlive( mpFrame ) )
1488            mpFrame->CallCallback( SalEvent::KeyUp, &aEvent );
1489    }
1490    return nRet;
1491}
1492
1493
1494-(BOOL)sendSingleCharacter: (NSEvent *)pEvent
1495{
1496    NSString* pUnmodifiedString = [pEvent charactersIgnoringModifiers];
1497
1498    if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
1499    {
1500        unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
1501        sal_uInt16 nKeyCode = ImplMapCharCode( keyChar );
1502        if (nKeyCode == 0)
1503        {
1504            sal_uInt16 nOtherKeyCode = [pEvent keyCode];
1505            nKeyCode = ImplMapKeyCode(nOtherKeyCode);
1506        }
1507        if( nKeyCode != 0 )
1508        {
1509            // don't send code points in the private use area
1510            if( keyChar >= 0xf700 && keyChar < 0xf780 )
1511                keyChar = 0;
1512            BOOL bRet = [self sendKeyToFrameDirect: nKeyCode character: keyChar modifiers: mpFrame->mnLastModifierFlags];
1513            mbInKeyInput = false;
1514
1515            return bRet;
1516        }
1517    }
1518    return NO;
1519}
1520
1521
1522// NSTextInput/NSTextInputClient protocol
1523- (NSArray *)validAttributesForMarkedText
1524{
1525    return [NSArray arrayWithObjects:NSUnderlineStyleAttributeName, nil];
1526}
1527
1528- (BOOL)hasMarkedText
1529{
1530    BOOL bHasMarkedText;
1531
1532    bHasMarkedText = ( mMarkedRange.location != NSNotFound ) &&
1533                     ( mMarkedRange.length != 0 );
1534    // hack to check keys like "Control-j"
1535    if( mbInKeyInput )
1536    {
1537        mbNeedSpecialKeyHandle = true;
1538    }
1539
1540    // FIXME:
1541    // #i106901#
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;
1549
1550    return bHasMarkedText;
1551}
1552
1553- (NSRange)markedRange
1554{
1555    // FIXME:
1556    // #i106901#
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 );
1564
1565    return [self hasMarkedText] ? mMarkedRange : NSMakeRange( NSNotFound, 0 );
1566}
1567
1568- (NSRange)selectedRange
1569{
1570    return mSelectedRange;
1571}
1572
1573- (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange replacementRange:(NSRange)replacementRange
1574{
1575    (void) replacementRange; // FIXME - use it!
1576
1577    SolarMutexGuard aGuard;
1578
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 )
1583    {
1584        mMarkedRange = NSMakeRange( selRange.location, [aString length] );
1585        mSelectedRange = NSMakeRange( selRange.location, selRange.length );
1586    }
1587    else
1588    {
1589        mMarkedRange = NSMakeRange( rangeToReplace.location, [aString length] );
1590        mSelectedRange = NSMakeRange( rangeToReplace.location + selRange.location, selRange.length );
1591    }
1592
1593    int len = [aString length];
1594    SalExtTextInputEvent aInputEvent;
1595    if( len > 0 ) {
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++ )
1600        {
1601            unsigned int nUnderlineValue;
1602            NSRange effectiveRange;
1603
1604            effectiveRange = NSMakeRange(i, 1);
1605            nUnderlineValue = [[aString attribute:NSUnderlineStyleAttributeName atIndex:i effectiveRange:&effectiveRange] unsignedIntValue];
1606
1607            switch (nUnderlineValue & 0xff) {
1608            case NSUnderlineStyleSingle:
1609                aInputFlags[i] = ExtTextInputAttr::Underline;
1610                break;
1611            case NSUnderlineStyleThick:
1612                aInputFlags[i] = ExtTextInputAttr::Underline | ExtTextInputAttr::Highlight;
1613                break;
1614            case NSUnderlineStyleDouble:
1615                aInputFlags[i] = ExtTextInputAttr::BoldUnderline;
1616                break;
1617            default:
1618                aInputFlags[i] = ExtTextInputAttr::Highlight;
1619                break;
1620            }
1621        }
1622
1623        aInputEvent.maText = aInsertString;
1624        aInputEvent.mnCursorPos = selRange.location;
1625        aInputEvent.mpTextAttr = aInputFlags.data();
1626        mpFrame->CallCallback( SalEvent::ExtTextInput, static_cast<void *>(&aInputEvent) );
1627    } else {
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 );
1634    }
1635    mbKeyHandled= true;
1636}
1637
1638- (void)unmarkText
1639{
1640    mSelectedRange = mMarkedRange = NSMakeRange(NSNotFound, 0);
1641}
1642
1643- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
1644{
1645    (void) aRange;
1646    (void) actualRange;
1647
1648    // FIXME - Implement
1649    return nil;
1650}
1651
1652- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
1653{
1654    (void)thePoint;
1655    // FIXME
1656    return 0;
1657}
1658
1659- (NSInteger)conversationIdentifier
1660{
1661    return reinterpret_cast<long>(self);
1662}
1663
1664- (void)doCommandBySelector:(SEL)aSelector
1665{
1666    if( AquaSalFrame::isAlive( mpFrame ) )
1667    {
1668        if( (mpFrame->mnICOptions & InputContextFlags::Text) &&
1669            aSelector != nullptr && [self respondsToSelector: aSelector] )
1670        {
1671            [self performSelector: aSelector];
1672        }
1673        else
1674        {
1675            [self sendSingleCharacter:mpLastEvent];
1676        }
1677    }
1678
1679    mbKeyHandled = true;
1680}
1681
1682-(void)clearLastEvent
1683{
1684    mpLastEvent = nil;
1685}
1686
1687- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
1688{
1689     // FIXME - These should probably be used?
1690    (void) aRange;
1691    (void) actualRange;
1692
1693    SolarMutexGuard aGuard;
1694
1695    SalExtTextInputPosEvent aPosEvent;
1696    mpFrame->CallCallback( SalEvent::ExtTextInputPos, static_cast<void *>(&aPosEvent) );
1697
1698    NSRect rect;
1699
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;
1704
1705    mpFrame->VCLToCocoa( rect );
1706    return rect;
1707}
1708
1709-(id)parentAttribute {
1710    return reinterpret_cast<NSView*>(mpFrame->getNSWindow());
1711        //TODO: odd cast really needed for fdo#74121?
1712}
1713
1714-(css::accessibility::XAccessibleContext *)accessibleContext
1715{
1716    if ( !mpReferenceWrapper ) {
1717        // some frames never become visible ..
1718        vcl::Window *pWindow = mpFrame -> GetWindow();
1719        if ( ! pWindow )
1720            return nil;
1721
1722        mpReferenceWrapper = new ReferenceWrapper;
1723        mpReferenceWrapper -> rAccessibleContext =  pWindow -> /*GetAccessibleChildWindow( 0 ) ->*/ GetAccessible() -> getAccessibleContext();
1724        [ AquaA11yFactory insertIntoWrapperRepository: self forAccessibleContext: mpReferenceWrapper -> rAccessibleContext ];
1725    }
1726    return [ super accessibleContext ];
1727}
1728
1729-(NSWindow*)windowForParent
1730{
1731    return mpFrame->getNSWindow();
1732}
1733
1734-(void)registerMouseEventListener: (id)theListener
1735{
1736  mpMouseEventListener = theListener;
1737}
1738
1739-(void)unregisterMouseEventListener: (id)theListener
1740{
1741    (void)theListener;
1742    mpMouseEventListener = nil;
1743}
1744
1745-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
1746{
1747  return [mDraggingDestinationHandler draggingEntered: sender];
1748}
1749
1750-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
1751{
1752  return [mDraggingDestinationHandler draggingUpdated: sender];
1753}
1754
1755-(void)draggingExited:(id <NSDraggingInfo>)sender
1756{
1757  [mDraggingDestinationHandler draggingExited: sender];
1758}
1759
1760-(BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
1761{
1762  return [mDraggingDestinationHandler prepareForDragOperation: sender];
1763}
1764
1765-(BOOL)performDragOperation:(id <NSDraggingInfo>)sender
1766{
1767  return [mDraggingDestinationHandler performDragOperation: sender];
1768}
1769
1770-(void)concludeDragOperation:(id <NSDraggingInfo>)sender
1771{
1772  [mDraggingDestinationHandler concludeDragOperation: sender];
1773}
1774
1775-(void)registerDraggingDestinationHandler:(id)theHandler
1776{
1777  mDraggingDestinationHandler = theHandler;
1778}
1779
1780-(void)unregisterDraggingDestinationHandler:(id)theHandler
1781{
1782    (void)theHandler;
1783    mDraggingDestinationHandler = nil;
1784}
1785
1786@end
1787
1788/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1789