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