1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/alloca.h>
21 #include <sal/macros.h>
23 #include "tools/helpers.hxx"
24 #include "vcl/window.hxx"
25 #include "vcl/svapp.hxx"
26 #include <vcl/settings.hxx>
28 #include "osx/salinst.h"
29 #include "quartz/salgdi.h"
30 #include "osx/salframe.h"
31 #include "osx/salframeview.h"
32 #include "osx/a11yfactory.h"
33 #include "quartz/utils.h"
35 #define WHEEL_EVENT_FACTOR 1.5
37 static sal_uInt16 ImplGetModifierMask( unsigned int nMask )
40 if( (nMask & NSShiftKeyMask) != 0 )
42 if( (nMask & NSControlKeyMask) != 0 )
44 if( (nMask & NSAlternateKeyMask) != 0 )
46 if( (nMask & NSCommandKeyMask) != 0 )
51 static sal_uInt16 ImplMapCharCode( sal_Unicode aCode )
53 static sal_uInt16 aKeyCodeMap[ 128 ] =
55 0, 0, 0, 0, 0, 0, 0, 0,
56 KEY_BACKSPACE, KEY_TAB, KEY_RETURN, 0, 0, KEY_RETURN, 0, 0,
57 0, 0, 0, 0, 0, 0, 0, 0,
58 0, KEY_TAB, 0, KEY_ESCAPE, 0, 0, 0, 0,
59 KEY_SPACE, 0, 0, 0, 0, 0, 0, 0,
60 0, 0, KEY_MULTIPLY, KEY_ADD, KEY_COMMA, KEY_SUBTRACT, KEY_POINT, KEY_DIVIDE,
61 KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7,
62 KEY_8, KEY_9, 0, 0, KEY_LESS, KEY_EQUAL, KEY_GREATER, 0,
63 0, KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G,
64 KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O,
65 KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W,
66 KEY_X, KEY_Y, KEY_Z, 0, 0, 0, 0, 0,
67 KEY_QUOTELEFT, KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G,
68 KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O,
69 KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W,
70 KEY_X, KEY_Y, KEY_Z, 0, 0, 0, KEY_TILDE, KEY_BACKSPACE
73 // Note: the mapping 0x7f should by rights be KEY_DELETE
74 // however if you press "backspace" 0x7f is reported
75 // whereas for "delete" 0xf728 gets reported
77 // Note: the mapping of 0x19 to KEY_TAB is because for unknown reasons
78 // tab alone is reported as 0x09 (as expected) but shift-tab is
79 // reported as 0x19 (end of medium)
81 static sal_uInt16 aFunctionKeyCodeMap[ 128 ] =
83 KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_F1, KEY_F2, KEY_F3, KEY_F4,
84 KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12,
85 KEY_F13, KEY_F14, KEY_F15, KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20,
86 KEY_F21, KEY_F22, KEY_F23, KEY_F24, KEY_F25, KEY_F26, 0, 0,
87 0, 0, 0, 0, 0, 0, 0, KEY_INSERT,
88 KEY_DELETE, KEY_HOME, 0, KEY_END, KEY_PAGEUP, KEY_PAGEDOWN, 0, 0,
89 0, 0, 0, 0, 0, KEY_MENU, 0, 0,
90 0, 0, 0, 0, 0, 0, 0, 0,
91 0, 0, 0, KEY_UNDO, KEY_REPEAT, KEY_FIND, KEY_HELP, 0,
92 0, 0, 0, 0, 0, 0, 0, 0,
93 0, 0, 0, 0, 0, 0, 0, 0,
94 0, 0, 0, 0, 0, 0, 0, 0,
95 0, 0, 0, 0, 0, 0, 0, 0,
96 0, 0, 0, 0, 0, 0, 0, 0,
97 0, 0, 0, 0, 0, 0, 0, 0,
98 0, 0, 0, 0, 0, 0, 0, 0
101 sal_uInt16 nKeyCode = 0;
102 if( aCode < SAL_N_ELEMENTS( aKeyCodeMap) )
103 nKeyCode = aKeyCodeMap[ aCode ];
104 else if( aCode >= 0xf700 && aCode < 0xf780 )
105 nKeyCode = aFunctionKeyCodeMap[ aCode - 0xf700 ];
109 static sal_uInt16 ImplMapKeyCode(sal_uInt16 nKeyCode)
112 http://stackoverflow.com/questions/2080312/where-can-i-find-a-list-of-key-codes-for-use-with-cocoas-nsevent-class/2080324#2080324
113 /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h
116 static sal_uInt16 aKeyCodeMap[ 0x80 ] =
118 KEY_A, KEY_S, KEY_D, KEY_F, KEY_H, KEY_G, KEY_Z, KEY_X,
119 KEY_C, KEY_V, 0, KEY_B, KEY_Q, KEY_W, KEY_E, KEY_R,
120 KEY_Y, KEY_T, KEY_1, KEY_2, KEY_3, KEY_4, KEY_6, KEY_5,
121 KEY_EQUAL, KEY_9, KEY_7, KEY_SUBTRACT, KEY_8, KEY_0, KEY_BRACKETRIGHT, KEY_0,
122 KEY_U, KEY_BRACKETLEFT, KEY_I, KEY_P, KEY_RETURN, KEY_L, KEY_J, KEY_QUOTERIGHT,
123 KEY_K, KEY_SEMICOLON, 0, KEY_COMMA, KEY_DIVIDE, KEY_N, KEY_M, KEY_POINT,
124 KEY_TAB, KEY_SPACE, KEY_QUOTELEFT, KEY_DELETE, 0, KEY_ESCAPE, 0, 0,
125 0, KEY_CAPSLOCK, 0, 0, 0, 0, 0, 0,
126 KEY_F17, KEY_DECIMAL, 0, KEY_MULTIPLY, 0, KEY_ADD, 0, 0,
127 0, 0, 0, KEY_DIVIDE, KEY_RETURN, 0, KEY_SUBTRACT, KEY_F18,
128 KEY_F19, KEY_EQUAL, 0, 0, 0, 0, 0, 0,
129 0, 0, KEY_F20, 0, 0, 0, 0, 0,
130 KEY_F5, KEY_F6, KEY_F7, KEY_F3, KEY_F8, KEY_F9, 0, KEY_F11,
131 0, KEY_F13, KEY_F16, KEY_F14, 0, KEY_F10, 0, KEY_F12,
132 0, KEY_F15, KEY_HELP, KEY_HOME, KEY_PAGEUP, KEY_DELETE, KEY_F4, KEY_END,
133 KEY_F2, KEY_PAGEDOWN, KEY_F1, KEY_LEFT, KEY_RIGHT, KEY_DOWN, KEY_UP, 0
136 if (nKeyCode < SAL_N_ELEMENTS(aKeyCodeMap))
137 return aKeyCodeMap[nKeyCode];
141 // store the frame the mouse last entered
142 static AquaSalFrame* s_pMouseFrame = NULL;
143 // store the last pressed button for enter/exit events
144 // which lack that information
145 static sal_uInt16 s_nLastButton = 0;
147 // combinations of keys we need to handle ourselves
148 static const struct ExceptionalKey
150 const sal_uInt16 nKeyCode;
151 const unsigned int nModifierMask;
152 } aExceptionalKeys[] =
154 { KEY_D, NSControlKeyMask | NSShiftKeyMask | NSAlternateKeyMask },
155 { KEY_D, NSCommandKeyMask | NSShiftKeyMask | NSAlternateKeyMask }
158 static AquaSalFrame* getMouseContainerFrame()
160 AquaSalFrame* pDispatchFrame = NULL;
161 NSArray* aWindows = [NSWindow windowNumbersWithOptions:0];
162 for(NSUInteger i = 0; i < [aWindows count] && ! pDispatchFrame; i++ )
164 NSWindow* pWin = [NSApp windowWithWindowNumber:[[aWindows objectAtIndex:i] integerValue]];
165 if( pWin && [pWin isMemberOfClass: [SalFrameWindow class]] && [(SalFrameWindow*)pWin containsMouse] )
166 pDispatchFrame = [(SalFrameWindow*)pWin getSalFrame];
168 return pDispatchFrame;
171 @implementation SalFrameWindow
172 -(id)initWithSalFrame: (AquaSalFrame*)pFrame
174 mDraggingDestinationHandler = nil;
176 NSRect aRect = { { static_cast<CGFloat>(pFrame->maGeometry.nX), static_cast<CGFloat>(pFrame->maGeometry.nY) },
177 { static_cast<CGFloat>(pFrame->maGeometry.nWidth), static_cast<CGFloat>(pFrame->maGeometry.nHeight) } };
178 pFrame->VCLToCocoa( aRect );
179 NSWindow* pNSWindow = [super initWithContentRect: aRect styleMask: mpFrame->getStyleMask() backing: NSBackingStoreBuffered defer: NO ];
180 #if MACOSX_SDK_VERSION < 101000
181 [pNSWindow useOptimizedDrawing: YES]; // OSX recommendation when there are no overlapping subviews within the receiver
184 // enable OSX>=10.7 fullscreen options if available and useful
185 bool bAllowFullScreen = (0 == (mpFrame->mnStyle & (SAL_FRAME_STYLE_DIALOG | SAL_FRAME_STYLE_TOOLTIP | SAL_FRAME_STYLE_SYSTEMCHILD | SAL_FRAME_STYLE_FLOAT | SAL_FRAME_STYLE_TOOLWINDOW | SAL_FRAME_STYLE_INTRO)));
186 bAllowFullScreen &= (0 == (~mpFrame->mnStyle & (SAL_FRAME_STYLE_SIZEABLE)));
187 bAllowFullScreen &= (mpFrame->mpParent == NULL);
188 const SEL setCollectionBehavior = @selector(setCollectionBehavior:);
189 if( bAllowFullScreen && [pNSWindow respondsToSelector: setCollectionBehavior])
191 const int bMode= (bAllowFullScreen ? NSWindowCollectionBehaviorFullScreenPrimary : NSWindowCollectionBehaviorFullScreenAuxiliary);
192 [pNSWindow performSelector:setCollectionBehavior withObject:reinterpret_cast<id>(static_cast<intptr_t>(bMode))];
195 // disable OSX>=10.7 window restoration until we support it directly
196 const SEL setRestorable = @selector(setRestorable:);
197 if( [pNSWindow respondsToSelector: setRestorable]) {
198 [pNSWindow performSelector:setRestorable withObject:reinterpret_cast<id>(NO)];
201 return (SalFrameWindow *)pNSWindow;
204 -(AquaSalFrame*)getSalFrame
209 -(void)displayIfNeeded
211 if( GetSalData() && GetSalData()->mpFirstInstance )
213 comphelper::SolarMutex* pMutex = GetSalData()->mpFirstInstance->GetYieldMutex();
217 [super displayIfNeeded];
225 // is this event actually inside that NSWindow ?
226 NSPoint aPt = [NSEvent mouseLocation];
227 NSRect aFrameRect = [self frame];
228 BOOL bInRect = NSPointInRect( aPt, aFrameRect );
232 -(BOOL)canBecomeKeyWindow
234 if( (mpFrame->mnStyle &
235 ( SAL_FRAME_STYLE_FLOAT |
236 SAL_FRAME_STYLE_TOOLTIP |
237 SAL_FRAME_STYLE_INTRO
240 if( (mpFrame->mnStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) != 0 )
242 if( mpFrame->mbFullScreen )
244 if( (mpFrame->mnStyle & SAL_FRAME_STYLE_FLOAT_FOCUSABLE) )
246 return [super canBecomeKeyWindow];
249 -(void)windowDidBecomeKey: (NSNotification*)pNotification
254 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
256 static const sal_uLong nGuessDocument = SAL_FRAME_STYLE_MOVEABLE|
257 SAL_FRAME_STYLE_SIZEABLE|
258 SAL_FRAME_STYLE_CLOSEABLE;
260 if( mpFrame->mpMenu )
261 mpFrame->mpMenu->setMainMenu();
262 else if( ! mpFrame->mpParent &&
263 ( (mpFrame->mnStyle & nGuessDocument) == nGuessDocument || // set default menu for e.g. help
264 mpFrame->mbFullScreen ) ) // ser default menu for e.g. presentation
266 AquaSalMenu::setDefaultMenu();
269 // FIXME: we should disable menus while in modal mode
270 // however from down here there is currently no reliable way to
271 // find out when to do this
272 if( (mpFrame->mpParent && mpFrame->mpParent->GetWindow()->IsInModalMode()) )
273 AquaSalMenu::enableMainMenu( false );
275 mpFrame->CallCallback( SALEVENT_GETFOCUS, 0 );
276 mpFrame->SendPaintEvent(); // repaint controls as active
280 -(void)windowDidResignKey: (NSNotification*)pNotification
285 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
287 mpFrame->CallCallback(SALEVENT_LOSEFOCUS, 0);
288 mpFrame->SendPaintEvent(); // repaint controls as inactive
292 -(void)windowDidChangeScreen: (NSNotification*)pNotification
297 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
298 mpFrame->screenParametersChanged();
301 -(void)windowDidMove: (NSNotification*)pNotification
306 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
308 mpFrame->UpdateFrameGeometry();
309 mpFrame->CallCallback( SALEVENT_MOVE, 0 );
313 -(void)windowDidResize: (NSNotification*)pNotification
318 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
320 mpFrame->UpdateFrameGeometry();
321 mpFrame->CallCallback( SALEVENT_RESIZE, 0 );
322 mpFrame->SendPaintEvent();
326 -(void)windowDidMiniaturize: (NSNotification*)pNotification
331 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
333 mpFrame->mbShown = false;
334 mpFrame->UpdateFrameGeometry();
335 mpFrame->CallCallback( SALEVENT_RESIZE, 0 );
339 -(void)windowDidDeminiaturize: (NSNotification*)pNotification
344 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
346 mpFrame->mbShown = true;
347 mpFrame->UpdateFrameGeometry();
348 mpFrame->CallCallback( SALEVENT_RESIZE, 0 );
352 -(BOOL)windowShouldClose: (NSNotification*)pNotification
358 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
360 // #i84461# end possible input
361 mpFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, 0 );
362 if( AquaSalFrame::isAlive( mpFrame ) )
364 mpFrame->CallCallback( SALEVENT_CLOSE, 0 );
365 bRet = NO; // application will close the window or not, AppKit shouldn't
372 -(void)windowDidEnterFullScreen: (NSNotification*)pNotification
376 if( !mpFrame || !AquaSalFrame::isAlive( mpFrame))
378 mpFrame->mbFullScreen = true;
382 -(void)windowDidExitFullScreen: (NSNotification*)pNotification
386 if( !mpFrame || !AquaSalFrame::isAlive( mpFrame))
388 mpFrame->mbFullScreen = false;
392 -(void)dockMenuItemTriggered: (id)sender
397 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
398 mpFrame->ToTop( SAL_FRAME_TOTOP_RESTOREWHENMIN | SAL_FRAME_TOTOP_GRABFOCUS );
401 -(::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >)accessibleContext
403 return mpFrame -> GetWindow() -> GetAccessible() -> getAccessibleContext();
406 -(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
408 return [mDraggingDestinationHandler draggingEntered: sender];
411 -(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
413 return [mDraggingDestinationHandler draggingUpdated: sender];
416 -(void)draggingExited:(id <NSDraggingInfo>)sender
418 [mDraggingDestinationHandler draggingExited: sender];
421 -(BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
423 return [mDraggingDestinationHandler prepareForDragOperation: sender];
426 -(BOOL)performDragOperation:(id <NSDraggingInfo>)sender
428 return [mDraggingDestinationHandler performDragOperation: sender];
431 -(void)concludeDragOperation:(id <NSDraggingInfo>)sender
433 [mDraggingDestinationHandler concludeDragOperation: sender];
436 -(void)registerDraggingDestinationHandler:(id)theHandler
438 mDraggingDestinationHandler = theHandler;
441 -(void)unregisterDraggingDestinationHandler:(id)theHandler
444 mDraggingDestinationHandler = nil;
449 @implementation SalFrameView
450 +(void)unsetMouseFrame: (AquaSalFrame*)pFrame
452 if( pFrame == s_pMouseFrame )
453 s_pMouseFrame = NULL;
456 -(id)initWithSalFrame: (AquaSalFrame*)pFrame
458 if ((self = [super initWithFrame: [NSWindow contentRectForFrameRect: [pFrame->getNSWindow() frame] styleMask: pFrame->mnStyleMask]]) != nil)
460 mDraggingDestinationHandler = nil;
462 mMarkedRange = NSMakeRange(NSNotFound, 0);
463 mSelectedRange = NSMakeRange(NSNotFound, 0);
464 mpReferenceWrapper = nil;
465 mpMouseEventListener = nil;
466 mpLastSuperEvent = nil;
469 mfLastMagnifyTime = 0.0;
473 -(AquaSalFrame*)getSalFrame
478 -(void)resetCursorRects
480 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
482 // FIXME: does this leak the returned NSCursor of getCurrentCursor ?
483 const NSRect aRect = { NSZeroPoint, NSMakeSize( mpFrame->maGeometry.nWidth, mpFrame->maGeometry.nHeight) };
484 [self addCursorRect: aRect cursor: mpFrame->getCurrentCursor()];
488 -(BOOL)acceptsFirstResponder
493 -(BOOL)acceptsFirstMouse: (NSEvent*)pEvent
503 if( !AquaSalFrame::isAlive( mpFrame))
505 if( !mpFrame->getClipPath())
510 // helper class similar to a osl::Guard< comphelper::SolarMutex > for the
511 // SalYieldMutex; the difference is that it only does tryToAcquire instead of
512 // acquire so dreaded deadlocks like #i93512# are prevented
516 TryGuard() { mbGuarded = ImplSalYieldMutexTryToAcquire(); }
517 ~TryGuard() { if( mbGuarded ) ImplSalYieldMutexRelease(); }
518 bool IsGuarded() { return mbGuarded; }
523 -(void)drawRect: (NSRect)aRect
525 // HOTFIX: #i93512# prevent deadlocks if any other thread already has the SalYieldMutex
527 if( !aTryGuard.IsGuarded() )
529 // NOTE: the mpFrame access below is not guarded yet!
530 // TODO: mpFrame et al need to be guarded by an independent mutex
531 AquaSalGraphics* pGraphics = (mpFrame && AquaSalFrame::isAlive(mpFrame)) ? mpFrame->mpGraphics : NULL;
534 // we did not get the mutex so we cannot draw now => request to redraw later
535 // convert the NSRect to a CGRect for Refreshrect()
536 const CGRect aCGRect = {{aRect.origin.x,aRect.origin.y},{aRect.size.width,aRect.size.height}};
537 pGraphics->RefreshRect( aCGRect );
542 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
544 if( mpFrame->mpGraphics )
546 mpFrame->mpGraphics->UpdateWindow( aRect );
547 if( mpFrame->getClipPath() )
548 [mpFrame->getNSWindow() invalidateShadow];
553 -(void)sendMouseEventToFrame: (NSEvent*)pEvent button:(sal_uInt16)nButton eventtype:(sal_uInt16)nEvent
557 AquaSalFrame* pDispatchFrame = AquaSalFrame::GetCaptureFrame();
558 bool bIsCaptured = false;
562 if( nEvent == SALEVENT_MOUSELEAVE ) // no leave events if mouse is captured
563 nEvent = SALEVENT_MOUSEMOVE;
565 else if( s_pMouseFrame )
566 pDispatchFrame = s_pMouseFrame;
568 pDispatchFrame = mpFrame;
570 /* #i81645# Cocoa reports mouse events while a button is pressed
571 to the window in which it was first pressed. This is reasonable and fine and
572 gets one around most cases where on other platforms one uses CaptureMouse or XGrabPointer,
573 however vcl expects mouse events to occur in the window the mouse is over, unless the
574 mouse is explicitly captured. So we need to find the window the mouse is actually
575 over for conformance with other platforms.
577 if( ! bIsCaptured && nButton && pDispatchFrame && AquaSalFrame::isAlive( pDispatchFrame ) )
579 // is this event actually inside that NSWindow ?
580 NSPoint aPt = [NSEvent mouseLocation];
581 NSRect aFrameRect = [pDispatchFrame->getNSWindow() frame];
583 if ( ! NSPointInRect( aPt, aFrameRect ) )
586 // now we need to find the one it may be in
587 /* #i93756# we ant to get enumerate the application windows in z-order
588 to check if any contains the mouse. This could be elegantly done with this
591 // use NSApp to check windows in ZOrder whether they contain the mouse pointer
592 NSWindow* pWindow = [NSApp makeWindowsPerform: @selector(containsMouse) inOrder: YES];
593 if( pWindow && [pWindow isMemberOfClass: [SalFrameWindow class]] )
594 pDispatchFrame = [(SalFrameWindow*)pWindow getSalFrame];
596 However if a non SalFrameWindow is on screen (like e.g. the file dialog)
597 it can be hit with the containsMouse selector, which it doesn't support.
598 Sadly NSApplication:makeWindowsPerform does not check (for performance reasons
599 I assume) whether a window supports a selector before sending it.
601 AquaSalFrame* pMouseFrame = getMouseContainerFrame();
603 pDispatchFrame = pMouseFrame;
607 if( pDispatchFrame && AquaSalFrame::isAlive( pDispatchFrame ) )
609 pDispatchFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
610 pDispatchFrame->mnLastModifierFlags = [pEvent modifierFlags];
612 NSPoint aPt = [NSEvent mouseLocation];
613 pDispatchFrame->CocoaToVCL( aPt );
615 sal_uInt16 nModMask = ImplGetModifierMask( [pEvent modifierFlags] );
616 // #i82284# emulate ctrl left
617 if( nModMask == KEY_MOD3 && nButton == MOUSE_LEFT )
620 nButton = MOUSE_RIGHT;
623 SalMouseEvent aEvent;
624 aEvent.mnTime = pDispatchFrame->mnLastEventTime;
625 aEvent.mnX = static_cast<long>(aPt.x) - pDispatchFrame->maGeometry.nX;
626 aEvent.mnY = static_cast<long>(aPt.y) - pDispatchFrame->maGeometry.nY;
627 aEvent.mnButton = nButton;
628 aEvent.mnCode = aEvent.mnButton | nModMask;
630 // --- RTL --- (mirror mouse pos)
631 if( AllSettings::GetLayoutRTL() )
632 aEvent.mnX = pDispatchFrame->maGeometry.nWidth-1-aEvent.mnX;
634 pDispatchFrame->CallCallback( nEvent, &aEvent );
638 -(void)mouseDown: (NSEvent*)pEvent
640 if ( mpMouseEventListener != nil &&
641 [mpMouseEventListener respondsToSelector: @selector(mouseDown:)])
643 [mpMouseEventListener mouseDown: [pEvent copyWithZone: NULL]];
646 s_nLastButton = MOUSE_LEFT;
647 [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SALEVENT_MOUSEBUTTONDOWN];
650 -(void)mouseDragged: (NSEvent*)pEvent
652 if ( mpMouseEventListener != nil &&
653 [mpMouseEventListener respondsToSelector: @selector(mouseDragged:)])
655 [mpMouseEventListener mouseDragged: [pEvent copyWithZone: NULL]];
657 s_nLastButton = MOUSE_LEFT;
658 [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SALEVENT_MOUSEMOVE];
661 -(void)mouseUp: (NSEvent*)pEvent
664 [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SALEVENT_MOUSEBUTTONUP];
667 -(void)mouseMoved: (NSEvent*)pEvent
670 [self sendMouseEventToFrame:pEvent button:0 eventtype:SALEVENT_MOUSEMOVE];
673 -(void)mouseEntered: (NSEvent*)pEvent
675 s_pMouseFrame = mpFrame;
677 // #i107215# the only mouse events we get when inactive are enter/exit
678 // actually we would like to have all of them, but better none than some
679 if( [NSApp isActive] )
680 [self sendMouseEventToFrame:pEvent button:s_nLastButton eventtype:SALEVENT_MOUSEMOVE];
683 -(void)mouseExited: (NSEvent*)pEvent
685 if( s_pMouseFrame == mpFrame )
686 s_pMouseFrame = NULL;
688 // #i107215# the only mouse events we get when inactive are enter/exit
689 // actually we would like to have all of them, but better none than some
690 if( [NSApp isActive] )
691 [self sendMouseEventToFrame:pEvent button:s_nLastButton eventtype:SALEVENT_MOUSELEAVE];
694 -(void)rightMouseDown: (NSEvent*)pEvent
696 s_nLastButton = MOUSE_RIGHT;
697 [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SALEVENT_MOUSEBUTTONDOWN];
700 -(void)rightMouseDragged: (NSEvent*)pEvent
702 s_nLastButton = MOUSE_RIGHT;
703 [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SALEVENT_MOUSEMOVE];
706 -(void)rightMouseUp: (NSEvent*)pEvent
709 [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SALEVENT_MOUSEBUTTONUP];
712 -(void)otherMouseDown: (NSEvent*)pEvent
714 if( [pEvent buttonNumber] == 2 )
716 s_nLastButton = MOUSE_MIDDLE;
717 [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SALEVENT_MOUSEBUTTONDOWN];
723 -(void)otherMouseDragged: (NSEvent*)pEvent
725 if( [pEvent buttonNumber] == 2 )
727 s_nLastButton = MOUSE_MIDDLE;
728 [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SALEVENT_MOUSEMOVE];
734 -(void)otherMouseUp: (NSEvent*)pEvent
737 if( [pEvent buttonNumber] == 2 )
738 [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SALEVENT_MOUSEBUTTONUP];
741 - (void)magnifyWithEvent: (NSEvent*)pEvent
745 // TODO: ?? -(float)magnification;
746 if( AquaSalFrame::isAlive( mpFrame ) )
748 const NSTimeInterval fMagnifyTime = [pEvent timestamp];
749 mpFrame->mnLastEventTime = static_cast<sal_uInt64>( fMagnifyTime * 1000.0 );
750 mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
752 // check if this is a new series of magnify events
753 static const NSTimeInterval fMaxDiffTime = 0.3;
754 const bool bNewSeries = (fMagnifyTime - mfLastMagnifyTime > fMaxDiffTime);
757 mfMagnifyDeltaSum = 0.0;
758 mfMagnifyDeltaSum += [pEvent magnification];
760 mfLastMagnifyTime = [pEvent timestamp];
761 // TODO: change to 0.1 when CommandWheelMode::ZOOM handlers allow finer zooming control
762 static const float fMagnifyFactor = 0.25*500; // steps are 500 times smaller for -magnification
763 static const float fMinMagnifyStep = 15.0 / fMagnifyFactor;
764 if( fabs(mfMagnifyDeltaSum) <= fMinMagnifyStep )
767 // adapt NSEvent-sensitivity to application expectations
768 // TODO: rather make CommandWheelMode::ZOOM handlers smarter
769 const float fDeltaZ = mfMagnifyDeltaSum * fMagnifyFactor;
770 int nDeltaZ = FRound( fDeltaZ );
773 // handle new series immediately
776 nDeltaZ = (fDeltaZ >= 0.0) ? +1 : -1;
778 // eventually give credit for delta sum
779 mfMagnifyDeltaSum -= nDeltaZ / fMagnifyFactor;
781 NSPoint aPt = [NSEvent mouseLocation];
782 mpFrame->CocoaToVCL( aPt );
784 SalWheelMouseEvent aEvent;
785 aEvent.mnTime = mpFrame->mnLastEventTime;
786 aEvent.mnX = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX;
787 aEvent.mnY = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY;
788 aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
789 aEvent.mnCode |= KEY_MOD1; // we want zooming, no scrolling
790 aEvent.mbDeltaIsPixel = TRUE;
792 // --- RTL --- (mirror mouse pos)
793 if( AllSettings::GetLayoutRTL() )
794 aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
796 aEvent.mnDelta = nDeltaZ;
797 aEvent.mnNotchDelta = (nDeltaZ >= 0) ? +1 : -1;
798 if( aEvent.mnDelta == 0 )
799 aEvent.mnDelta = aEvent.mnNotchDelta;
800 aEvent.mbHorz = FALSE;
801 aEvent.mnScrollLines = nDeltaZ;
802 if( aEvent.mnScrollLines == 0 )
803 aEvent.mnScrollLines = 1;
804 mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
808 - (void)rotateWithEvent: (NSEvent*)pEvent
810 //Rotation : -(float)rotation;
811 // TODO: create new CommandType so rotation is available to the applications
815 - (void)swipeWithEvent: (NSEvent*)pEvent
819 if( AquaSalFrame::isAlive( mpFrame ) )
821 mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
822 mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
824 // merge pending scroll wheel events
829 dX += [pEvent deltaX];
830 dY += [pEvent deltaY];
831 NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask
832 untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ];
838 NSPoint aPt = [NSEvent mouseLocation];
839 mpFrame->CocoaToVCL( aPt );
841 SalWheelMouseEvent aEvent;
842 aEvent.mnTime = mpFrame->mnLastEventTime;
843 aEvent.mnX = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX;
844 aEvent.mnY = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY;
845 aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
846 aEvent.mbDeltaIsPixel = TRUE;
848 // --- RTL --- (mirror mouse pos)
849 if( AllSettings::GetLayoutRTL() )
850 aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
854 aEvent.mnDelta = static_cast<long>(floor(dX));
855 aEvent.mnNotchDelta = (dX < 0) ? -1 : +1;
856 if( aEvent.mnDelta == 0 )
857 aEvent.mnDelta = aEvent.mnNotchDelta;
858 aEvent.mbHorz = TRUE;
859 aEvent.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
860 mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
862 if( dY != 0.0 && AquaSalFrame::isAlive( mpFrame ))
864 aEvent.mnDelta = static_cast<long>(floor(dY));
865 aEvent.mnNotchDelta = (dY < 0) ? -1 : +1;
866 if( aEvent.mnDelta == 0 )
867 aEvent.mnDelta = aEvent.mnNotchDelta;
868 aEvent.mbHorz = FALSE;
869 aEvent.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
870 mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
875 -(void)scrollWheel: (NSEvent*)pEvent
879 if( AquaSalFrame::isAlive( mpFrame ) )
881 mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
882 mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
884 // merge pending scroll wheel events
889 dX += [pEvent deltaX];
890 dY += [pEvent deltaY];
891 NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask
892 untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ];
898 NSPoint aPt = [NSEvent mouseLocation];
899 mpFrame->CocoaToVCL( aPt );
901 SalWheelMouseEvent aEvent;
902 aEvent.mnTime = mpFrame->mnLastEventTime;
903 aEvent.mnX = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX;
904 aEvent.mnY = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY;
905 aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
906 aEvent.mbDeltaIsPixel = FALSE;
908 // --- RTL --- (mirror mouse pos)
909 if( AllSettings::GetLayoutRTL() )
910 aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
914 aEvent.mnDelta = static_cast<long>(floor(dX));
915 aEvent.mnNotchDelta = (dX < 0) ? -1 : +1;
916 if( aEvent.mnDelta == 0 )
917 aEvent.mnDelta = aEvent.mnNotchDelta;
918 aEvent.mbHorz = TRUE;
919 aEvent.mnScrollLines = fabs(dX) / WHEEL_EVENT_FACTOR;
920 if( aEvent.mnScrollLines == 0 )
921 aEvent.mnScrollLines = 1;
923 mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
925 if( dY != 0.0 && AquaSalFrame::isAlive( mpFrame ) )
927 aEvent.mnDelta = static_cast<long>(floor(dY));
928 aEvent.mnNotchDelta = (dY < 0) ? -1 : +1;
929 if( aEvent.mnDelta == 0 )
930 aEvent.mnDelta = aEvent.mnNotchDelta;
931 aEvent.mbHorz = FALSE;
932 aEvent.mnScrollLines = fabs(dY) / WHEEL_EVENT_FACTOR;
933 if( aEvent.mnScrollLines == 0 )
934 aEvent.mnScrollLines = 1;
936 mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
942 -(void)keyDown: (NSEvent*)pEvent
946 if( AquaSalFrame::isAlive( mpFrame ) )
948 mpLastEvent = pEvent;
950 mbNeedSpecialKeyHandle = false;
951 mbKeyHandled = false;
953 mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
954 mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
956 if( ! [self handleKeyDownException: pEvent] )
958 NSArray* pArray = [NSArray arrayWithObject: pEvent];
959 [self interpretKeyEvents: pArray];
962 mbInKeyInput = false;
966 -(BOOL)handleKeyDownException:(NSEvent*)pEvent
968 // check for a very special set of modified characters
969 NSString* pUnmodifiedString = [pEvent charactersIgnoringModifiers];
971 if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
973 /* #i103102# key events with command and alternate don't make it through
974 interpretKeyEvents (why?). Try to dispatch them here first,
975 if not successful continue normally
977 if( (mpFrame->mnLastModifierFlags & (NSAlternateKeyMask | NSCommandKeyMask))
978 == (NSAlternateKeyMask | NSCommandKeyMask) )
980 if( [self sendSingleCharacter: mpLastEvent] )
983 unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
984 sal_uInt16 nKeyCode = ImplMapCharCode( keyChar );
986 // Caution: should the table grow to more than 5 or 6 entries,
987 // we must consider moving it to a kind of hash map
988 const unsigned int nExceptions = SAL_N_ELEMENTS( aExceptionalKeys );
989 for( unsigned int i = 0; i < nExceptions; i++ )
991 if( nKeyCode == aExceptionalKeys[i].nKeyCode &&
992 (mpFrame->mnLastModifierFlags & aExceptionalKeys[i].nModifierMask)
993 == aExceptionalKeys[i].nModifierMask )
995 [self sendKeyInputAndReleaseToFrame: nKeyCode character: 0];
1004 -(void)flagsChanged: (NSEvent*)pEvent
1008 if( AquaSalFrame::isAlive( mpFrame ) )
1010 mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
1011 mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
1015 -(void)insertText:(id)aString replacementRange:(NSRange)replacementRange
1017 (void) replacementRange; // FIXME: surely it must be used
1021 if( AquaSalFrame::isAlive( mpFrame ) )
1023 NSString* pInsert = nil;
1024 if( [aString isMemberOfClass: [NSAttributedString class]] )
1025 pInsert = [aString string];
1030 if( pInsert && ( nLen = [pInsert length] ) > 0 )
1032 OUString aInsertString( GetOUString( pInsert ) );
1033 // aCharCode initializer is safe since aInsertString will at least contain '\0'
1034 sal_Unicode aCharCode = *aInsertString.getStr();
1039 ! [self hasMarkedText ]
1042 sal_uInt16 nKeyCode = ImplMapCharCode( aCharCode );
1043 unsigned int nLastModifiers = mpFrame->mnLastModifierFlags;
1046 // find out the unmodified key code
1049 if( mpLastEvent && ( [mpLastEvent type] == NSKeyDown || [mpLastEvent type] == NSKeyUp ) )
1051 // get unmodified string
1052 NSString* pUnmodifiedString = [mpLastEvent charactersIgnoringModifiers];
1053 if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
1055 // map the unmodified key code
1056 unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
1057 nKeyCode = ImplMapCharCode( keyChar );
1059 nLastModifiers = [mpLastEvent modifierFlags];
1063 // applications and vcl's edit fields ignore key events with ALT
1064 // however we're at a place where we know text should be inserted
1065 // so it seems we need to strip the Alt modifier here
1066 if( (nLastModifiers & (NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask))
1067 == NSAlternateKeyMask )
1071 [self sendKeyInputAndReleaseToFrame: nKeyCode character: aCharCode modifiers: nLastModifiers];
1075 SalExtTextInputEvent aEvent;
1076 aEvent.mnTime = mpFrame->mnLastEventTime;
1077 aEvent.maText = aInsertString;
1078 aEvent.mpTextAttr = NULL;
1079 aEvent.mnCursorPos = aInsertString.getLength();
1080 aEvent.mnCursorFlags = 0;
1081 aEvent.mbOnlyCursor = FALSE;
1082 mpFrame->CallCallback( SALEVENT_EXTTEXTINPUT, &aEvent );
1083 if( AquaSalFrame::isAlive( mpFrame ) )
1084 mpFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, 0 );
1089 SalExtTextInputEvent aEvent;
1090 aEvent.mnTime = mpFrame->mnLastEventTime;
1091 aEvent.maText.clear();
1092 aEvent.mpTextAttr = NULL;
1093 aEvent.mnCursorPos = 0;
1094 aEvent.mnCursorFlags = 0;
1095 aEvent.mbOnlyCursor = FALSE;
1096 mpFrame->CallCallback( SALEVENT_EXTTEXTINPUT, &aEvent );
1097 if( AquaSalFrame::isAlive( mpFrame ) )
1098 mpFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, 0 );
1101 mbKeyHandled = true;
1106 -(void)insertTab: (id)aSender
1109 [self sendKeyInputAndReleaseToFrame: KEY_TAB character: '\t' modifiers: 0];
1112 -(void)insertBacktab: (id)aSender
1115 [self sendKeyInputAndReleaseToFrame: (KEY_TAB | KEY_SHIFT) character: '\t' modifiers: 0];
1118 -(void)moveLeft: (id)aSender
1121 [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: 0];
1124 -(void)moveLeftAndModifySelection: (id)aSender
1127 [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: NSShiftKeyMask];
1130 -(void)moveBackwardAndModifySelection: (id)aSender
1133 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_BACKWARD character: 0 modifiers: 0];
1136 -(void)moveRight: (id)aSender
1139 [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: 0];
1142 -(void)moveRightAndModifySelection: (id)aSender
1145 [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: NSShiftKeyMask];
1148 -(void)moveForwardAndModifySelection: (id)aSender
1151 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_FORWARD character: 0 modifiers: 0];
1154 -(void)moveWordLeft: (id)aSender
1157 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_WORD_BACKWARD character: 0 modifiers: 0];
1160 -(void)moveWordBackward: (id)aSender
1163 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_WORD_BACKWARD character: 0 modifiers: 0];
1166 -(void)moveWordBackwardAndModifySelection: (id)aSender
1169 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD_BACKWARD character: 0 modifiers: 0];
1172 -(void)moveWordLeftAndModifySelection: (id)aSender
1175 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD_BACKWARD character: 0 modifiers: 0];
1178 -(void)moveWordRight: (id)aSender
1181 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_WORD_FORWARD character: 0 modifiers: 0];
1184 -(void)moveWordForward: (id)aSender
1187 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_WORD_FORWARD character: 0 modifiers: 0];
1190 -(void)moveWordForwardAndModifySelection: (id)aSender
1193 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD_FORWARD character: 0 modifiers: 0];
1196 -(void)moveWordRightAndModifySelection: (id)aSender
1199 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD_FORWARD character: 0 modifiers: 0];
1202 -(void)moveToEndOfLine: (id)aSender
1205 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_LINE character: 0 modifiers: 0];
1208 -(void)moveToRightEndOfLine: (id)aSender
1211 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_LINE character: 0 modifiers: 0];
1214 -(void)moveToEndOfLineAndModifySelection: (id)aSender
1217 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_LINE character: 0 modifiers: 0];
1220 -(void)moveToRightEndOfLineAndModifySelection: (id)aSender
1223 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_LINE character: 0 modifiers: 0];
1226 -(void)moveToBeginningOfLine: (id)aSender
1229 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
1232 -(void)moveToLeftEndOfLine: (id)aSender
1235 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
1238 -(void)moveToBeginningOfLineAndModifySelection: (id)aSender
1241 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
1244 -(void)moveToLeftEndOfLineAndModifySelection: (id)aSender
1247 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
1250 -(void)moveToEndOfParagraph: (id)aSender
1253 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
1256 -(void)moveToEndOfParagraphAndModifySelection: (id)aSender
1259 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
1262 -(void)moveParagraphForward: (id)aSender
1265 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
1268 -(void)moveParagraphForwardAndModifySelection: (id)aSender
1271 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
1274 -(void)moveToBeginningOfParagraph: (id)aSender
1277 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
1280 -(void)moveParagraphBackward: (id)aSender
1283 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
1286 -(void)moveToBeginningOfParagraphAndModifySelection: (id)aSender
1289 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
1292 -(void)moveParagraphBackwardAndModifySelection: (id)aSender
1295 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
1298 -(void)moveToEndOfDocument: (id)aSender
1301 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT character: 0 modifiers: 0];
1304 -(void)scrollToEndOfDocument: (id)aSender
1307 // this is not exactly what we should do, but it makes "End" and "Shift-End" behave consistent
1308 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT character: 0 modifiers: 0];
1311 -(void)moveToEndOfDocumentAndModifySelection: (id)aSender
1314 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT character: 0 modifiers: 0];
1317 -(void)moveToBeginningOfDocument: (id)aSender
1320 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0];
1323 -(void)scrollToBeginningOfDocument: (id)aSender
1326 // this is not exactly what we should do, but it makes "Home" and "Shift-Home" behave consistent
1327 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0];
1330 -(void)moveToBeginningOfDocumentAndModifySelection: (id)aSender
1333 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0];
1336 -(void)moveUp: (id)aSender
1339 [self sendKeyInputAndReleaseToFrame: KEY_UP character: 0 modifiers: 0];
1342 -(void)moveDown: (id)aSender
1345 [self sendKeyInputAndReleaseToFrame: KEY_DOWN character: 0 modifiers: 0];
1348 -(void)insertNewline: (id)aSender
1351 // #i91267# make enter and shift-enter work by evaluating the modifiers
1352 [self sendKeyInputAndReleaseToFrame: KEY_RETURN character: '\n' modifiers: mpFrame->mnLastModifierFlags];
1355 -(void)deleteBackward: (id)aSender
1358 [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0];
1361 -(void)deleteForward: (id)aSender
1364 [self sendKeyInputAndReleaseToFrame: KEY_DELETE character: 0x7f modifiers: 0];
1367 -(void)deleteBackwardByDecomposingPreviousCharacter: (id)aSender
1370 [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0];
1373 -(void)deleteWordBackward: (id)aSender
1376 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_WORD_BACKWARD character: 0 modifiers: 0];
1379 -(void)deleteWordForward: (id)aSender
1382 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_WORD_FORWARD character: 0 modifiers: 0];
1385 -(void)deleteToBeginningOfLine: (id)aSender
1388 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
1391 -(void)deleteToEndOfLine: (id)aSender
1394 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_TO_END_OF_LINE character: 0 modifiers: 0];
1397 -(void)deleteToBeginningOfParagraph: (id)aSender
1400 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
1403 -(void)deleteToEndOfParagraph: (id)aSender
1406 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
1409 -(void)insertLineBreak: (id)aSender
1412 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::INSERT_LINEBREAK character: 0 modifiers: 0];
1415 -(void)insertParagraphSeparator: (id)aSender
1418 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::INSERT_PARAGRAPH character: 0 modifiers: 0];
1421 -(void)selectWord: (id)aSender
1424 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD character: 0 modifiers: 0];
1427 -(void)selectLine: (id)aSender
1430 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_LINE character: 0 modifiers: 0];
1433 -(void)selectParagraph: (id)aSender
1436 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_PARAGRAPH character: 0 modifiers: 0];
1439 -(void)selectAll: (id)aSender
1442 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_ALL character: 0 modifiers: 0];
1445 -(void)cancelOperation: (id)aSender
1448 [self sendKeyInputAndReleaseToFrame: KEY_ESCAPE character: 0x1b modifiers: 0];
1451 -(void)noop: (id)aSender
1454 if( ! mbKeyHandled )
1456 if( ! [self sendSingleCharacter:mpLastEvent] )
1458 /* prevent recursion */
1459 if( mpLastEvent != mpLastSuperEvent && [NSApp respondsToSelector: @selector(sendSuperEvent:)] )
1461 id pLastSuperEvent = mpLastSuperEvent;
1462 mpLastSuperEvent = mpLastEvent;
1463 [NSApp performSelector:@selector(sendSuperEvent:) withObject: mpLastEvent];
1464 mpLastSuperEvent = pLastSuperEvent;
1466 std::map< NSEvent*, bool >::iterator it = GetSalData()->maKeyEventAnswer.find( mpLastEvent );
1467 if( it != GetSalData()->maKeyEventAnswer.end() )
1474 -(BOOL)sendKeyInputAndReleaseToFrame: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar
1476 return [self sendKeyInputAndReleaseToFrame: nKeyCode character: aChar modifiers: mpFrame->mnLastModifierFlags];
1479 -(BOOL)sendKeyInputAndReleaseToFrame: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod
1481 return [self sendKeyToFrameDirect: nKeyCode character: aChar modifiers: nMod] ||
1482 [self sendSingleCharacter: mpLastEvent];
1485 -(BOOL)sendKeyToFrameDirect: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod
1490 if( AquaSalFrame::isAlive( mpFrame ) )
1493 aEvent.mnTime = mpFrame->mnLastEventTime;
1494 aEvent.mnCode = nKeyCode | ImplGetModifierMask( nMod );
1495 aEvent.mnCharCode = aChar;
1496 aEvent.mnRepeat = FALSE;
1497 nRet = mpFrame->CallCallback( SALEVENT_KEYINPUT, &aEvent );
1498 std::map< NSEvent*, bool >::iterator it = GetSalData()->maKeyEventAnswer.find( mpLastEvent );
1499 if( it != GetSalData()->maKeyEventAnswer.end() )
1500 it->second = nRet != 0;
1501 if( AquaSalFrame::isAlive( mpFrame ) )
1502 mpFrame->CallCallback( SALEVENT_KEYUP, &aEvent );
1504 return nRet ? YES : NO;
1508 -(BOOL)sendSingleCharacter: (NSEvent *)pEvent
1510 NSString* pUnmodifiedString = [pEvent charactersIgnoringModifiers];
1512 if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
1514 unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
1515 sal_uInt16 nKeyCode = ImplMapCharCode( keyChar );
1518 sal_uInt16 nOtherKeyCode = [pEvent keyCode];
1519 nKeyCode = ImplMapKeyCode(nOtherKeyCode);
1523 // don't send unicodes in the private use area
1524 if( keyChar >= 0xf700 && keyChar < 0xf780 )
1526 BOOL bRet = [self sendKeyToFrameDirect: nKeyCode character: keyChar modifiers: mpFrame->mnLastModifierFlags];
1527 mbInKeyInput = false;
1536 // NSTextInput/NSTextInputClient protocol
1537 - (NSArray *)validAttributesForMarkedText
1539 return [NSArray arrayWithObjects:NSUnderlineStyleAttributeName, nil];
1542 - (BOOL)hasMarkedText
1544 BOOL bHasMarkedText;
1546 bHasMarkedText = ( mMarkedRange.location != NSNotFound ) &&
1547 ( mMarkedRange.length != 0 );
1548 // hack to check keys like "Control-j"
1551 mbNeedSpecialKeyHandle = true;
1556 // if we come here outside of mbInKeyInput, this is likely to be because
1557 // of the keyboard viewer. For unknown reasons having no marked range
1558 // in this case causes a crash. So we say we have a marked range anyway
1559 // This is a hack, since it is not understood what a) causes that crash
1560 // and b) why we should have a marked range at this point.
1561 if( ! mbInKeyInput )
1562 bHasMarkedText = YES;
1564 return bHasMarkedText;
1567 - (NSRange)markedRange
1571 // if we come here outside of mbInKeyInput, this is likely to be because
1572 // of the keyboard viewer. For unknown reasons having no marked range
1573 // in this case causes a crash. So we say we have a marked range anyway
1574 // This is a hack, since it is not understood what a) causes that crash
1575 // and b) why we should have a marked range at this point.
1576 if( ! mbInKeyInput )
1577 return NSMakeRange( 0, 0 );
1579 return [self hasMarkedText] ? mMarkedRange : NSMakeRange( NSNotFound, 0 );
1582 - (NSRange)selectedRange
1584 return mSelectedRange;
1587 - (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange replacementRange:(NSRange)replacementRange
1589 (void) replacementRange; // FIXME - use it!
1593 if( ![aString isKindOfClass:[NSAttributedString class]] )
1594 aString = [[[NSAttributedString alloc] initWithString:aString] autorelease];
1595 NSRange rangeToReplace = [self hasMarkedText] ? [self markedRange] : [self selectedRange];
1596 if( rangeToReplace.location == NSNotFound )
1598 mMarkedRange = NSMakeRange( selRange.location, [aString length] );
1599 mSelectedRange = NSMakeRange( selRange.location, selRange.length );
1603 mMarkedRange = NSMakeRange( rangeToReplace.location, [aString length] );
1604 mSelectedRange = NSMakeRange( rangeToReplace.location + selRange.location, selRange.length );
1607 int len = [aString length];
1608 SalExtTextInputEvent aInputEvent;
1609 aInputEvent.mnTime = mpFrame->mnLastEventTime;
1610 aInputEvent.mbOnlyCursor = FALSE;
1612 NSString *pString = [aString string];
1613 OUString aInsertString( GetOUString( pString ) );
1614 std::vector<sal_uInt16> aInputFlags = std::vector<sal_uInt16>( std::max( 1, len ), 0 );
1615 for ( int i = 0; i < len; i++ )
1617 unsigned int nUnderlineValue;
1618 NSRange effectiveRange;
1620 effectiveRange = NSMakeRange(i, 1);
1621 nUnderlineValue = [[aString attribute:NSUnderlineStyleAttributeName atIndex:i effectiveRange:&effectiveRange] unsignedIntValue];
1623 switch (nUnderlineValue & 0xff) {
1624 case NSUnderlineStyleSingle:
1625 aInputFlags[i] = EXTTEXTINPUT_ATTR_UNDERLINE;
1627 case NSUnderlineStyleThick:
1628 aInputFlags[i] = EXTTEXTINPUT_ATTR_UNDERLINE | EXTTEXTINPUT_ATTR_HIGHLIGHT;
1630 case NSUnderlineStyleDouble:
1631 aInputFlags[i] = EXTTEXTINPUT_ATTR_BOLDUNDERLINE;
1634 aInputFlags[i] = EXTTEXTINPUT_ATTR_HIGHLIGHT;
1639 aInputEvent.maText = aInsertString;
1640 aInputEvent.mnCursorPos = selRange.location;
1641 aInputEvent.mpTextAttr = &aInputFlags[0];
1642 mpFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void *)&aInputEvent );
1644 aInputEvent.maText.clear();
1645 aInputEvent.mnCursorPos = 0;
1646 aInputEvent.mnCursorFlags = 0;
1647 aInputEvent.mpTextAttr = 0;
1648 mpFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void *)&aInputEvent );
1649 mpFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, 0 );
1656 mSelectedRange = mMarkedRange = NSMakeRange(NSNotFound, 0);
1659 - (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
1664 // FIXME - Implement
1668 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
1675 - (NSInteger)conversationIdentifier
1677 return reinterpret_cast<long>(self);
1680 - (void)doCommandBySelector:(SEL)aSelector
1682 if( AquaSalFrame::isAlive( mpFrame ) )
1684 #if OSL_DEBUG_LEVEL > 1
1685 // fprintf( stderr, "SalFrameView: doCommandBySelector %s\n", (char*)aSelector );
1687 if( (mpFrame->mnICOptions & InputContextFlags::Text) &&
1688 aSelector != NULL && [self respondsToSelector: aSelector] )
1690 [self performSelector: aSelector];
1694 [self sendSingleCharacter:mpLastEvent];
1698 mbKeyHandled = true;
1701 -(void)clearLastEvent
1706 - (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
1708 // FIXME - These should probably be used?
1714 SalExtTextInputPosEvent aPosEvent;
1715 mpFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void *)&aPosEvent );
1719 rect.origin.x = aPosEvent.mnX + mpFrame->maGeometry.nX;
1720 rect.origin.y = aPosEvent.mnY + mpFrame->maGeometry.nY + 4; // add some space for underlines
1721 rect.size.width = aPosEvent.mnWidth;
1722 rect.size.height = aPosEvent.mnHeight;
1724 mpFrame->VCLToCocoa( rect );
1728 -(id)parentAttribute {
1729 return reinterpret_cast<NSView*>(mpFrame->getNSWindow());
1730 //TODO: odd cast really needed for fdo#74121?
1733 -(::com::sun::star::accessibility::XAccessibleContext *)accessibleContext
1735 if ( !mpReferenceWrapper ) {
1736 // some frames never become visible ..
1737 vcl::Window *pWindow = mpFrame -> GetWindow();
1741 mpReferenceWrapper = new ReferenceWrapper;
1742 mpReferenceWrapper -> rAccessibleContext = pWindow -> /*GetAccessibleChildWindow( 0 ) ->*/ GetAccessible() -> getAccessibleContext();
1743 [ AquaA11yFactory insertIntoWrapperRepository: self forAccessibleContext: mpReferenceWrapper -> rAccessibleContext ];
1745 return [ super accessibleContext ];
1748 -(NSWindow*)windowForParent
1750 return mpFrame->getNSWindow();
1753 -(void)registerMouseEventListener: (id)theListener
1755 mpMouseEventListener = theListener;
1758 -(void)unregisterMouseEventListener: (id)theListener
1761 mpMouseEventListener = nil;
1764 -(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
1766 return [mDraggingDestinationHandler draggingEntered: sender];
1769 -(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
1771 return [mDraggingDestinationHandler draggingUpdated: sender];
1774 -(void)draggingExited:(id <NSDraggingInfo>)sender
1776 [mDraggingDestinationHandler draggingExited: sender];
1779 -(BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
1781 return [mDraggingDestinationHandler prepareForDragOperation: sender];
1784 -(BOOL)performDragOperation:(id <NSDraggingInfo>)sender
1786 return [mDraggingDestinationHandler performDragOperation: sender];
1789 -(void)concludeDragOperation:(id <NSDraggingInfo>)sender
1791 [mDraggingDestinationHandler concludeDragOperation: sender];
1794 -(void)registerDraggingDestinationHandler:(id)theHandler
1796 mDraggingDestinationHandler = theHandler;
1799 -(void)unregisterDraggingDestinationHandler:(id)theHandler
1802 mDraggingDestinationHandler = nil;
1807 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */