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"
27 #include "aqua/salinst.h"
28 #include "aqua/salgdi.h"
29 #include "aqua/salframe.h"
30 #include "aqua/salframeview.h"
31 #include "aqua/aqua11yfactory.h"
32 #include "quartz/utils.h"
34 #define WHEEL_EVENT_FACTOR 1.5
36 // for allowing fullscreen support on deployment targets < OSX 10.7
37 #if !defined(MAC_OS_X_VERSION_10_7)
38 #define NSWindowCollectionBehaviorFullScreenPrimary (1 << 7)
39 #define NSWindowCollectionBehaviorFullScreenAuxiliary (1 << 8)
40 // #define NSFullScreenWindowMask (1 << 14)
44 static sal_uInt16 ImplGetModifierMask( unsigned int nMask )
47 if( (nMask & NSShiftKeyMask) != 0 )
49 if( (nMask & NSControlKeyMask) != 0 )
51 if( (nMask & NSAlternateKeyMask) != 0 )
53 if( (nMask & NSCommandKeyMask) != 0 )
58 static sal_uInt16 ImplMapCharCode( sal_Unicode aCode )
60 static sal_uInt16 aKeyCodeMap[ 128 ] =
62 0, 0, 0, 0, 0, 0, 0, 0,
63 KEY_BACKSPACE, KEY_TAB, KEY_RETURN, 0, 0, KEY_RETURN, 0, 0,
64 0, 0, 0, 0, 0, 0, 0, 0,
65 0, KEY_TAB, 0, KEY_ESCAPE, 0, 0, 0, 0,
66 KEY_SPACE, 0, 0, 0, 0, 0, 0, 0,
67 0, 0, KEY_MULTIPLY, KEY_ADD, KEY_COMMA, KEY_SUBTRACT, KEY_POINT, KEY_DIVIDE,
68 KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7,
69 KEY_8, KEY_9, 0, 0, KEY_LESS, KEY_EQUAL, KEY_GREATER, 0,
70 0, KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G,
71 KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O,
72 KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W,
73 KEY_X, KEY_Y, KEY_Z, 0, 0, 0, 0, 0,
74 KEY_QUOTELEFT, KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G,
75 KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O,
76 KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W,
77 KEY_X, KEY_Y, KEY_Z, 0, 0, 0, KEY_TILDE, KEY_BACKSPACE
80 // Note: the mapping 0x7f should by rights be KEY_DELETE
81 // however if you press "backspace" 0x7f is reported
82 // whereas for "delete" 0xf728 gets reported
84 // Note: the mapping of 0x19 to KEY_TAB is because for unknown reasons
85 // tab alone is reported as 0x09 (as expected) but shift-tab is
86 // reported as 0x19 (end of medium)
88 static sal_uInt16 aFunctionKeyCodeMap[ 128 ] =
90 KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_F1, KEY_F2, KEY_F3, KEY_F4,
91 KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12,
92 KEY_F13, KEY_F14, KEY_F15, KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20,
93 KEY_F21, KEY_F22, KEY_F23, KEY_F24, KEY_F25, KEY_F26, 0, 0,
94 0, 0, 0, 0, 0, 0, 0, KEY_INSERT,
95 KEY_DELETE, KEY_HOME, 0, KEY_END, KEY_PAGEUP, KEY_PAGEDOWN, 0, 0,
96 0, 0, 0, 0, 0, KEY_MENU, 0, 0,
97 0, 0, 0, 0, 0, 0, 0, 0,
98 0, 0, 0, KEY_UNDO, KEY_REPEAT, KEY_FIND, KEY_HELP, 0,
99 0, 0, 0, 0, 0, 0, 0, 0,
100 0, 0, 0, 0, 0, 0, 0, 0,
101 0, 0, 0, 0, 0, 0, 0, 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
108 sal_uInt16 nKeyCode = 0;
109 if( aCode < SAL_N_ELEMENTS( aKeyCodeMap) )
110 nKeyCode = aKeyCodeMap[ aCode ];
111 else if( aCode >= 0xf700 && aCode < 0xf780 )
112 nKeyCode = aFunctionKeyCodeMap[ aCode - 0xf700 ];
116 static sal_uInt16 ImplMapKeyCode(sal_uInt16 nKeyCode)
119 http://stackoverflow.com/questions/2080312/where-can-i-find-a-list-of-key-codes-for-use-with-cocoas-nsevent-class/2080324#2080324
120 /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h
123 static sal_uInt16 aKeyCodeMap[ 0x80 ] =
125 KEY_A, KEY_S, KEY_D, KEY_F, KEY_H, KEY_G, KEY_Z, KEY_X,
126 KEY_C, KEY_V, 0, KEY_B, KEY_Q, KEY_W, KEY_E, KEY_R,
127 KEY_Y, KEY_T, KEY_1, KEY_2, KEY_3, KEY_4, KEY_6, KEY_5,
128 KEY_EQUAL, KEY_9, KEY_7, KEY_SUBTRACT, KEY_8, KEY_0, KEY_BRACKETRIGHT, KEY_0,
129 KEY_U, KEY_BRACKETLEFT, KEY_I, KEY_P, KEY_RETURN, KEY_L, KEY_J, KEY_QUOTELEFT,
130 KEY_K, KEY_SEMICOLON, 0, KEY_COMMA, KEY_DIVIDE, KEY_N, KEY_M, KEY_POINT,
131 KEY_TAB, KEY_SPACE, KEY_TILDE, KEY_DELETE, 0, KEY_ESCAPE, 0, 0,
132 0, KEY_CAPSLOCK, 0, 0, 0, 0, 0, 0,
133 KEY_F17, KEY_DECIMAL, 0, KEY_MULTIPLY, 0, KEY_ADD, 0, 0,
134 0, 0, 0, KEY_DIVIDE, KEY_RETURN, 0, KEY_SUBTRACT, KEY_F18,
135 KEY_F19, KEY_EQUAL, 0, 0, 0, 0, 0, 0,
136 0, 0, KEY_F20, 0, 0, 0, 0, 0,
137 KEY_F5, KEY_F6, KEY_F7, KEY_F3, KEY_F8, KEY_F9, 0, KEY_F11,
138 0, KEY_F13, KEY_F16, KEY_F14, 0, KEY_F10, 0, KEY_F12,
139 0, KEY_F15, KEY_HELP, KEY_HOME, KEY_PAGEUP, KEY_DELETE, KEY_F4, KEY_END,
140 KEY_F2, KEY_PAGEDOWN, KEY_F1, KEY_LEFT, KEY_RIGHT, KEY_DOWN, KEY_UP, 0
143 if (nKeyCode < SAL_N_ELEMENTS(aKeyCodeMap))
144 return aKeyCodeMap[nKeyCode];
148 // store the frame the mouse last entered
149 static AquaSalFrame* s_pMouseFrame = NULL;
150 // store the last pressed button for enter/exit events
151 // which lack that information
152 static sal_uInt16 s_nLastButton = 0;
154 // combinations of keys we need to handle ourselves
155 static const struct ExceptionalKey
157 const sal_uInt16 nKeyCode;
158 const unsigned int nModifierMask;
159 } aExceptionalKeys[] =
161 { KEY_D, NSControlKeyMask | NSShiftKeyMask | NSAlternateKeyMask },
162 { KEY_D, NSCommandKeyMask | NSShiftKeyMask | NSAlternateKeyMask }
165 static AquaSalFrame* getMouseContainerFrame()
167 NSInteger nWindows = 0;
168 NSCountWindows( &nWindows );
169 NSInteger* pWindows = (NSInteger*)alloca( nWindows * sizeof(NSInteger) );
170 // note: NSWindowList is supposed to be in z-order front to back
171 NSWindowList( nWindows, pWindows );
172 AquaSalFrame* pDispatchFrame = NULL;
173 for(int i = 0; i < nWindows && ! pDispatchFrame; i++ )
175 NSWindow* pWin = [NSApp windowWithWindowNumber: pWindows[i]];
176 if( pWin && [pWin isMemberOfClass: [SalFrameWindow class]] && [(SalFrameWindow*)pWin containsMouse] )
177 pDispatchFrame = [(SalFrameWindow*)pWin getSalFrame];
179 return pDispatchFrame;
182 @implementation SalFrameWindow
183 -(id)initWithSalFrame: (AquaSalFrame*)pFrame
185 mDraggingDestinationHandler = nil;
187 NSRect aRect = { { static_cast<CGFloat>(pFrame->maGeometry.nX), static_cast<CGFloat>(pFrame->maGeometry.nY) },
188 { static_cast<CGFloat>(pFrame->maGeometry.nWidth), static_cast<CGFloat>(pFrame->maGeometry.nHeight) } };
189 pFrame->VCLToCocoa( aRect );
190 NSWindow* pNSWindow = [super initWithContentRect: aRect styleMask: mpFrame->getStyleMask() backing: NSBackingStoreBuffered defer: NO ];
191 [pNSWindow useOptimizedDrawing: YES]; // OSX recommendation when there are no overlapping subviews within the receiver
193 // enable OSX>=10.7 fullscreen options if available and useful
194 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)));
195 bAllowFullScreen &= (0 == (~mpFrame->mnStyle & (SAL_FRAME_STYLE_SIZEABLE)));
196 bAllowFullScreen &= (mpFrame->mpParent == NULL);
197 const SEL setCollectionBehavior = @selector(setCollectionBehavior:);
198 if( bAllowFullScreen && [pNSWindow respondsToSelector: setCollectionBehavior])
200 const int bMode= (bAllowFullScreen ? NSWindowCollectionBehaviorFullScreenPrimary : NSWindowCollectionBehaviorFullScreenAuxiliary);
201 [pNSWindow performSelector:setCollectionBehavior withObject:(id)(intptr_t)bMode];
204 // disable OSX>=10.7 window restoration until we support it directly
205 const SEL setRestorable = @selector(setRestorable:);
206 if( [pNSWindow respondsToSelector: setRestorable]) {
207 [pNSWindow performSelector:setRestorable withObject:(id)NO];
210 return (SalFrameWindow *) pNSWindow;
213 -(AquaSalFrame*)getSalFrame
218 -(void)displayIfNeeded
220 if( GetSalData() && GetSalData()->mpFirstInstance )
222 comphelper::SolarMutex* pMutex = GetSalData()->mpFirstInstance->GetYieldMutex();
226 [super displayIfNeeded];
234 // is this event actually inside that NSWindow ?
235 NSPoint aPt = [NSEvent mouseLocation];
236 NSRect aFrameRect = [self frame];
237 BOOL bInRect = NSPointInRect( aPt, aFrameRect );
241 -(BOOL)canBecomeKeyWindow
243 if( (mpFrame->mnStyle &
244 ( SAL_FRAME_STYLE_FLOAT |
245 SAL_FRAME_STYLE_TOOLTIP |
246 SAL_FRAME_STYLE_INTRO
249 if( (mpFrame->mnStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) != 0 )
251 if( mpFrame->mbFullScreen )
253 if( (mpFrame->mnStyle & SAL_FRAME_STYLE_FLOAT_FOCUSABLE) )
255 return [super canBecomeKeyWindow];
258 -(void)windowDidBecomeKey: (NSNotification*)pNotification
263 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
265 static const sal_uLong nGuessDocument = SAL_FRAME_STYLE_MOVEABLE|
266 SAL_FRAME_STYLE_SIZEABLE|
267 SAL_FRAME_STYLE_CLOSEABLE;
269 if( mpFrame->mpMenu )
270 mpFrame->mpMenu->setMainMenu();
271 else if( ! mpFrame->mpParent &&
272 ( (mpFrame->mnStyle & nGuessDocument) == nGuessDocument || // set default menu for e.g. help
273 mpFrame->mbFullScreen ) ) // ser default menu for e.g. presentation
275 AquaSalMenu::setDefaultMenu();
278 // FIXME: we should disable menus while in modal mode
279 // however from down here there is currently no reliable way to
280 // find out when to do this
281 if( (mpFrame->mpParent && mpFrame->mpParent->GetWindow()->IsInModalMode()) )
282 AquaSalMenu::enableMainMenu( false );
284 mpFrame->CallCallback( SALEVENT_GETFOCUS, 0 );
285 mpFrame->SendPaintEvent(); // repaint controls as active
289 -(void)windowDidResignKey: (NSNotification*)pNotification
294 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
296 mpFrame->CallCallback(SALEVENT_LOSEFOCUS, 0);
297 mpFrame->SendPaintEvent(); // repaint controls as inactive
301 -(void)windowDidChangeScreen: (NSNotification*)pNotification
306 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
307 mpFrame->screenParametersChanged();
310 -(void)windowDidMove: (NSNotification*)pNotification
315 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
317 mpFrame->UpdateFrameGeometry();
318 mpFrame->CallCallback( SALEVENT_MOVE, 0 );
322 -(void)windowDidResize: (NSNotification*)pNotification
327 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
329 mpFrame->UpdateFrameGeometry();
330 mpFrame->CallCallback( SALEVENT_RESIZE, 0 );
331 mpFrame->SendPaintEvent();
335 -(void)windowDidMiniaturize: (NSNotification*)pNotification
340 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
342 mpFrame->mbShown = false;
343 mpFrame->UpdateFrameGeometry();
344 mpFrame->CallCallback( SALEVENT_RESIZE, 0 );
348 -(void)windowDidDeminiaturize: (NSNotification*)pNotification
353 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
355 mpFrame->mbShown = true;
356 mpFrame->UpdateFrameGeometry();
357 mpFrame->CallCallback( SALEVENT_RESIZE, 0 );
361 -(BOOL)windowShouldClose: (NSNotification*)pNotification
367 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
369 // #i84461# end possible input
370 mpFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, 0 );
371 if( AquaSalFrame::isAlive( mpFrame ) )
373 mpFrame->CallCallback( SALEVENT_CLOSE, 0 );
374 bRet = NO; // application will close the window or not, AppKit shouldn't
381 -(void)windowDidEnterFullScreen: (NSNotification*)pNotification
385 if( !mpFrame || !AquaSalFrame::isAlive( mpFrame))
387 mpFrame->mbFullScreen = true;
391 -(void)windowDidExitFullScreen: (NSNotification*)pNotification
395 if( !mpFrame || !AquaSalFrame::isAlive( mpFrame))
397 mpFrame->mbFullScreen = false;
401 -(void)dockMenuItemTriggered: (id)sender
406 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
407 mpFrame->ToTop( SAL_FRAME_TOTOP_RESTOREWHENMIN | SAL_FRAME_TOTOP_GRABFOCUS );
410 -(::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >)accessibleContext
412 return mpFrame -> GetWindow() -> GetAccessible() -> getAccessibleContext();
415 -(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
417 return [mDraggingDestinationHandler draggingEntered: sender];
420 -(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
422 return [mDraggingDestinationHandler draggingUpdated: sender];
425 -(void)draggingExited:(id <NSDraggingInfo>)sender
427 [mDraggingDestinationHandler draggingExited: sender];
430 -(BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
432 return [mDraggingDestinationHandler prepareForDragOperation: sender];
435 -(BOOL)performDragOperation:(id <NSDraggingInfo>)sender
437 return [mDraggingDestinationHandler performDragOperation: sender];
440 -(void)concludeDragOperation:(id <NSDraggingInfo>)sender
442 [mDraggingDestinationHandler concludeDragOperation: sender];
445 -(void)registerDraggingDestinationHandler:(id)theHandler
447 mDraggingDestinationHandler = theHandler;
450 -(void)unregisterDraggingDestinationHandler:(id)theHandler
453 mDraggingDestinationHandler = nil;
458 @implementation SalFrameView
459 +(void)unsetMouseFrame: (AquaSalFrame*)pFrame
461 if( pFrame == s_pMouseFrame )
462 s_pMouseFrame = NULL;
465 -(id)initWithSalFrame: (AquaSalFrame*)pFrame
467 if ((self = [super initWithFrame: [NSWindow contentRectForFrameRect: [pFrame->getWindow() frame] styleMask: pFrame->mnStyleMask]]) != nil)
469 mDraggingDestinationHandler = nil;
471 mMarkedRange = NSMakeRange(NSNotFound, 0);
472 mSelectedRange = NSMakeRange(NSNotFound, 0);
473 mpReferenceWrapper = nil;
474 mpMouseEventListener = nil;
475 mpLastSuperEvent = nil;
478 mfLastMagnifyTime = 0.0;
482 -(AquaSalFrame*)getSalFrame
487 -(void)resetCursorRects
489 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
491 // FIXME: does this leak the returned NSCursor of getCurrentCursor ?
492 NSRect aRect = { { 0, 0 }, { static_cast<CGFloat>(mpFrame->maGeometry.nWidth), static_cast<CGFloat>(mpFrame->maGeometry.nHeight) } };
493 [self addCursorRect: aRect cursor: mpFrame->getCurrentCursor()];
497 -(BOOL)acceptsFirstResponder
502 -(BOOL)acceptsFirstMouse: (NSEvent*)pEvent
512 if( !AquaSalFrame::isAlive( mpFrame))
514 if( !mpFrame->getClipPath())
519 // helper class similar to a osl::Guard< comphelper::SolarMutex > for the
520 // SalYieldMutex; the difference is that it only does tryToAcquire instead of
521 // acquire so dreaded deadlocks like #i93512# are prevented
525 TryGuard() { mbGuarded = ImplSalYieldMutexTryToAcquire(); }
526 ~TryGuard() { if( mbGuarded ) ImplSalYieldMutexRelease(); }
527 bool IsGuarded() { return mbGuarded; }
532 -(void)drawRect: (NSRect)aRect
534 // HOTFIX: #i93512# prevent deadlocks if any other thread already has the SalYieldMutex
536 if( !aTryGuard.IsGuarded() )
538 // NOTE: the mpFrame access below is not guarded yet!
539 // TODO: mpFrame et al need to be guarded by an independent mutex
540 AquaSalGraphics* pGraphics = (mpFrame && AquaSalFrame::isAlive(mpFrame)) ? mpFrame->mpGraphics : NULL;
543 // we did not get the mutex so we cannot draw now => request to redraw later
544 // convert the NSRect to a CGRect for Refreshrect()
545 const CGRect aCGRect = {{aRect.origin.x,aRect.origin.y},{aRect.size.width,aRect.size.height}};
546 pGraphics->RefreshRect( aCGRect );
551 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
553 if( mpFrame->mpGraphics )
555 mpFrame->mpGraphics->UpdateWindow( aRect );
556 if( mpFrame->getClipPath() )
557 [mpFrame->getWindow() invalidateShadow];
562 -(void)sendMouseEventToFrame: (NSEvent*)pEvent button:(sal_uInt16)nButton eventtype:(sal_uInt16)nEvent
566 AquaSalFrame* pDispatchFrame = AquaSalFrame::GetCaptureFrame();
567 bool bIsCaptured = false;
571 if( nEvent == SALEVENT_MOUSELEAVE ) // no leave events if mouse is captured
572 nEvent = SALEVENT_MOUSEMOVE;
574 else if( s_pMouseFrame )
575 pDispatchFrame = s_pMouseFrame;
577 pDispatchFrame = mpFrame;
579 /* #i81645# Cocoa reports mouse events while a button is pressed
580 to the window in which it was first pressed. This is reasonable and fine and
581 gets one around most cases where on other platforms one uses CaptureMouse or XGrabPointer,
582 however vcl expects mouse events to occur in the window the mouse is over, unless the
583 mouse is explicitly captured. So we need to find the window the mouse is actually
584 over for conformance with other platforms.
586 if( ! bIsCaptured && nButton && pDispatchFrame && AquaSalFrame::isAlive( pDispatchFrame ) )
588 // is this event actually inside that NSWindow ?
589 NSPoint aPt = [NSEvent mouseLocation];
590 NSRect aFrameRect = [pDispatchFrame->getWindow() frame];
592 if ( ! NSPointInRect( aPt, aFrameRect ) )
595 // now we need to find the one it may be in
596 /* #i93756# we ant to get enumerate the application windows in z-order
597 to check if any contains the mouse. This could be elegantly done with this
600 // use NSApp to check windows in ZOrder whether they contain the mouse pointer
601 NSWindow* pWindow = [NSApp makeWindowsPerform: @selector(containsMouse) inOrder: YES];
602 if( pWindow && [pWindow isMemberOfClass: [SalFrameWindow class]] )
603 pDispatchFrame = [(SalFrameWindow*)pWindow getSalFrame];
605 However if a non SalFrameWindow is on screen (like e.g. the file dialog)
606 it can be hit with the containsMouse selector, which it doesn't support.
607 Sadly NSApplication:makeWindowsPerform does not check (for performance reasons
608 I assume) whether a window supports a selector before sending it.
610 AquaSalFrame* pMouseFrame = getMouseContainerFrame();
612 pDispatchFrame = pMouseFrame;
616 if( pDispatchFrame && AquaSalFrame::isAlive( pDispatchFrame ) )
618 pDispatchFrame->mnLastEventTime = static_cast<sal_uLong>( [pEvent timestamp] * 1000.0 );
619 pDispatchFrame->mnLastModifierFlags = [pEvent modifierFlags];
621 NSPoint aPt = [NSEvent mouseLocation];
622 pDispatchFrame->CocoaToVCL( aPt );
624 sal_uInt16 nModMask = ImplGetModifierMask( [pEvent modifierFlags] );
625 // #i82284# emulate ctrl left
626 if( nModMask == KEY_MOD3 && nButton == MOUSE_LEFT )
629 nButton = MOUSE_RIGHT;
632 SalMouseEvent aEvent;
633 aEvent.mnTime = pDispatchFrame->mnLastEventTime;
634 aEvent.mnX = static_cast<long>(aPt.x) - pDispatchFrame->maGeometry.nX;
635 aEvent.mnY = static_cast<long>(aPt.y) - pDispatchFrame->maGeometry.nY;
636 aEvent.mnButton = nButton;
637 aEvent.mnCode = aEvent.mnButton | nModMask;
639 // --- RTL --- (mirror mouse pos)
640 if( Application::GetSettings().GetLayoutRTL() )
641 aEvent.mnX = pDispatchFrame->maGeometry.nWidth-1-aEvent.mnX;
643 pDispatchFrame->CallCallback( nEvent, &aEvent );
647 -(void)mouseDown: (NSEvent*)pEvent
649 if ( mpMouseEventListener != nil &&
650 [mpMouseEventListener respondsToSelector: @selector(mouseDown:)])
652 [mpMouseEventListener mouseDown: [pEvent copyWithZone: NULL]];
655 s_nLastButton = MOUSE_LEFT;
656 [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SALEVENT_MOUSEBUTTONDOWN];
659 -(void)mouseDragged: (NSEvent*)pEvent
661 if ( mpMouseEventListener != nil &&
662 [mpMouseEventListener respondsToSelector: @selector(mouseDragged:)])
664 [mpMouseEventListener mouseDragged: [pEvent copyWithZone: NULL]];
666 s_nLastButton = MOUSE_LEFT;
667 [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SALEVENT_MOUSEMOVE];
670 -(void)mouseUp: (NSEvent*)pEvent
673 [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SALEVENT_MOUSEBUTTONUP];
676 -(void)mouseMoved: (NSEvent*)pEvent
679 [self sendMouseEventToFrame:pEvent button:0 eventtype:SALEVENT_MOUSEMOVE];
682 -(void)mouseEntered: (NSEvent*)pEvent
684 s_pMouseFrame = mpFrame;
686 // #i107215# the only mouse events we get when inactive are enter/exit
687 // actually we would like to have all of them, but better none than some
688 if( [NSApp isActive] )
689 [self sendMouseEventToFrame:pEvent button:s_nLastButton eventtype:SALEVENT_MOUSEMOVE];
692 -(void)mouseExited: (NSEvent*)pEvent
694 if( s_pMouseFrame == mpFrame )
695 s_pMouseFrame = NULL;
697 // #i107215# the only mouse events we get when inactive are enter/exit
698 // actually we would like to have all of them, but better none than some
699 if( [NSApp isActive] )
700 [self sendMouseEventToFrame:pEvent button:s_nLastButton eventtype:SALEVENT_MOUSELEAVE];
703 -(void)rightMouseDown: (NSEvent*)pEvent
705 s_nLastButton = MOUSE_RIGHT;
706 [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SALEVENT_MOUSEBUTTONDOWN];
709 -(void)rightMouseDragged: (NSEvent*)pEvent
711 s_nLastButton = MOUSE_RIGHT;
712 [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SALEVENT_MOUSEMOVE];
715 -(void)rightMouseUp: (NSEvent*)pEvent
718 [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SALEVENT_MOUSEBUTTONUP];
721 -(void)otherMouseDown: (NSEvent*)pEvent
723 if( [pEvent buttonNumber] == 2 )
725 s_nLastButton = MOUSE_MIDDLE;
726 [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SALEVENT_MOUSEBUTTONDOWN];
732 -(void)otherMouseDragged: (NSEvent*)pEvent
734 if( [pEvent buttonNumber] == 2 )
736 s_nLastButton = MOUSE_MIDDLE;
737 [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SALEVENT_MOUSEMOVE];
743 -(void)otherMouseUp: (NSEvent*)pEvent
746 if( [pEvent buttonNumber] == 2 )
747 [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SALEVENT_MOUSEBUTTONUP];
750 - (void)magnifyWithEvent: (NSEvent*)pEvent
754 // TODO: ?? -(float)magnification;
755 if( AquaSalFrame::isAlive( mpFrame ) )
757 const NSTimeInterval fMagnifyTime = [pEvent timestamp];
758 mpFrame->mnLastEventTime = static_cast<sal_uLong>( fMagnifyTime * 1000.0 );
759 mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
761 // check if this is a new series of magnify events
762 static const NSTimeInterval fMaxDiffTime = 0.3;
763 const bool bNewSeries = (fMagnifyTime - mfLastMagnifyTime > fMaxDiffTime);
766 mfMagnifyDeltaSum = 0.0;
767 mfMagnifyDeltaSum += [pEvent deltaZ];
769 mfLastMagnifyTime = [pEvent timestamp];
770 // TODO: change to 0.1 when COMMAND_WHEEL_ZOOM handlers allow finer zooming control
771 static const float fMagnifyFactor = 0.25;
772 static const float fMinMagnifyStep = 15.0 / fMagnifyFactor;
773 if( fabs(mfMagnifyDeltaSum) <= fMinMagnifyStep )
776 // adapt NSEvent-sensitivity to application expectations
777 // TODO: rather make COMMAND_WHEEL_ZOOM handlers smarter
778 const float fDeltaZ = mfMagnifyDeltaSum * fMagnifyFactor;
779 int nDeltaZ = FRound( fDeltaZ );
782 // handle new series immediately
785 nDeltaZ = (fDeltaZ >= 0.0) ? +1 : -1;
787 // eventually give credit for delta sum
788 mfMagnifyDeltaSum -= nDeltaZ / fMagnifyFactor;
790 NSPoint aPt = [NSEvent mouseLocation];
791 mpFrame->CocoaToVCL( aPt );
793 SalWheelMouseEvent aEvent;
794 aEvent.mnTime = mpFrame->mnLastEventTime;
795 aEvent.mnX = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX;
796 aEvent.mnY = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY;
797 aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
798 aEvent.mnCode |= KEY_MOD1; // we want zooming, no scrolling
799 aEvent.mbDeltaIsPixel = TRUE;
801 // --- RTL --- (mirror mouse pos)
802 if( Application::GetSettings().GetLayoutRTL() )
803 aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
805 aEvent.mnDelta = nDeltaZ;
806 aEvent.mnNotchDelta = (nDeltaZ >= 0) ? +1 : -1;
807 if( aEvent.mnDelta == 0 )
808 aEvent.mnDelta = aEvent.mnNotchDelta;
809 aEvent.mbHorz = FALSE;
810 aEvent.mnScrollLines = nDeltaZ;
811 if( aEvent.mnScrollLines == 0 )
812 aEvent.mnScrollLines = 1;
813 mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
817 - (void)rotateWithEvent: (NSEvent*)pEvent
819 //Rotation : -(float)rotation;
820 // TODO: create new CommandType so rotation is available to the applications
824 - (void)swipeWithEvent: (NSEvent*)pEvent
828 if( AquaSalFrame::isAlive( mpFrame ) )
830 mpFrame->mnLastEventTime = static_cast<sal_uLong>( [pEvent timestamp] * 1000.0 );
831 mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
833 // merge pending scroll wheel events
838 dX += [pEvent deltaX];
839 dY += [pEvent deltaY];
840 NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask
841 untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ];
847 NSPoint aPt = [NSEvent mouseLocation];
848 mpFrame->CocoaToVCL( aPt );
850 SalWheelMouseEvent aEvent;
851 aEvent.mnTime = mpFrame->mnLastEventTime;
852 aEvent.mnX = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX;
853 aEvent.mnY = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY;
854 aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
855 aEvent.mbDeltaIsPixel = TRUE;
857 // --- RTL --- (mirror mouse pos)
858 if( Application::GetSettings().GetLayoutRTL() )
859 aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
863 aEvent.mnDelta = static_cast<long>(floor(dX));
864 aEvent.mnNotchDelta = dX < 0 ? -1 : 1;
865 if( aEvent.mnDelta == 0 )
866 aEvent.mnDelta = aEvent.mnNotchDelta;
867 aEvent.mbHorz = TRUE;
868 aEvent.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
869 mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
871 if( dY != 0.0 && AquaSalFrame::isAlive( mpFrame ))
873 aEvent.mnDelta = static_cast<long>(floor(dY));
874 aEvent.mnNotchDelta = dY < 0 ? -1 : 1;
875 if( aEvent.mnDelta == 0 )
876 aEvent.mnDelta = aEvent.mnNotchDelta;
877 aEvent.mbHorz = FALSE;
878 aEvent.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
879 mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
884 -(void)scrollWheel: (NSEvent*)pEvent
888 if( AquaSalFrame::isAlive( mpFrame ) )
890 mpFrame->mnLastEventTime = static_cast<sal_uLong>( [pEvent timestamp] * 1000.0 );
891 mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
893 // merge pending scroll wheel events
898 dX += [pEvent deltaX];
899 dY += [pEvent deltaY];
900 NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask
901 untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ];
907 NSPoint aPt = [NSEvent mouseLocation];
908 mpFrame->CocoaToVCL( aPt );
910 SalWheelMouseEvent aEvent;
911 aEvent.mnTime = mpFrame->mnLastEventTime;
912 aEvent.mnX = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX;
913 aEvent.mnY = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY;
914 aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
915 aEvent.mbDeltaIsPixel = FALSE;
917 // --- RTL --- (mirror mouse pos)
918 if( Application::GetSettings().GetLayoutRTL() )
919 aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
923 aEvent.mnDelta = static_cast<long>(floor(dX));
924 aEvent.mnNotchDelta = dX < 0 ? -1 : 1;
925 if( aEvent.mnDelta == 0 )
926 aEvent.mnDelta = aEvent.mnNotchDelta;
927 aEvent.mbHorz = TRUE;
928 aEvent.mnScrollLines = dX > 0 ? dX/WHEEL_EVENT_FACTOR : -dX/WHEEL_EVENT_FACTOR;
929 if( aEvent.mnScrollLines == 0 )
930 aEvent.mnScrollLines = 1;
932 mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
934 if( dY != 0.0 && AquaSalFrame::isAlive( mpFrame ) )
936 aEvent.mnDelta = static_cast<long>(floor(dY));
937 aEvent.mnNotchDelta = dY < 0 ? -1 : 1;
938 if( aEvent.mnDelta == 0 )
939 aEvent.mnDelta = aEvent.mnNotchDelta;
940 aEvent.mbHorz = FALSE;
941 aEvent.mnScrollLines = dY > 0 ? dY/WHEEL_EVENT_FACTOR : -dY/WHEEL_EVENT_FACTOR;
942 if( aEvent.mnScrollLines < 1 )
943 aEvent.mnScrollLines = 1;
945 mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
951 -(void)keyDown: (NSEvent*)pEvent
955 if( AquaSalFrame::isAlive( mpFrame ) )
957 mpLastEvent = pEvent;
959 mbNeedSpecialKeyHandle = false;
960 mbKeyHandled = false;
962 mpFrame->mnLastEventTime = static_cast<sal_uLong>( [pEvent timestamp] * 1000.0 );
963 mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
965 if( ! [self handleKeyDownException: pEvent] )
967 NSArray* pArray = [NSArray arrayWithObject: pEvent];
968 [self interpretKeyEvents: pArray];
971 mbInKeyInput = false;
975 -(BOOL)handleKeyDownException:(NSEvent*)pEvent
977 // check for a very special set of modified characters
978 NSString* pUnmodifiedString = [pEvent charactersIgnoringModifiers];
980 if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
982 /* #i103102# key events with command and alternate don't make it through
983 interpretKeyEvents (why ?). Try to dispatch them here first,
984 if not successful continue normally
986 if( (mpFrame->mnLastModifierFlags & (NSAlternateKeyMask | NSCommandKeyMask))
987 == (NSAlternateKeyMask | NSCommandKeyMask) )
989 if( [self sendSingleCharacter: mpLastEvent] )
992 unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
993 sal_uInt16 nKeyCode = ImplMapCharCode( keyChar );
995 // Caution: should the table grow to more than 5 or 6 entries,
996 // we must consider moving it to a kind of hash map
997 const unsigned int nExceptions = SAL_N_ELEMENTS( aExceptionalKeys );
998 for( unsigned int i = 0; i < nExceptions; i++ )
1000 if( nKeyCode == aExceptionalKeys[i].nKeyCode &&
1001 (mpFrame->mnLastModifierFlags & aExceptionalKeys[i].nModifierMask)
1002 == aExceptionalKeys[i].nModifierMask )
1004 [self sendKeyInputAndReleaseToFrame: nKeyCode character: 0];
1013 -(void)flagsChanged: (NSEvent*)pEvent
1017 if( AquaSalFrame::isAlive( mpFrame ) )
1019 mpFrame->mnLastEventTime = static_cast<sal_uLong>( [pEvent timestamp] * 1000.0 );
1020 mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
1024 -(void)insertText:(id)aString
1028 if( AquaSalFrame::isAlive( mpFrame ) )
1030 NSString* pInsert = nil;
1031 if( [aString isMemberOfClass: [NSAttributedString class]] )
1032 pInsert = [aString string];
1037 if( pInsert && ( nLen = [pInsert length] ) > 0 )
1039 OUString aInsertString( GetOUString( pInsert ) );
1040 // aCharCode initializer is safe since aInsertString will at least contain '\0'
1041 sal_Unicode aCharCode = *aInsertString.getStr();
1046 ! [self hasMarkedText ]
1049 sal_uInt16 nKeyCode = ImplMapCharCode( aCharCode );
1050 unsigned int nLastModifiers = mpFrame->mnLastModifierFlags;
1053 // find out the unmodified key code
1056 if( mpLastEvent && ( [mpLastEvent type] == NSKeyDown || [mpLastEvent type] == NSKeyUp ) )
1058 // get unmodified string
1059 NSString* pUnmodifiedString = [mpLastEvent charactersIgnoringModifiers];
1060 if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
1062 // map the unmodified key code
1063 unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
1064 nKeyCode = ImplMapCharCode( keyChar );
1066 nLastModifiers = [mpLastEvent modifierFlags];
1070 // applications and vcl's edit fields ignore key events with ALT
1071 // however we're at a place where we know text should be inserted
1072 // so it seems we need to strip the Alt modifier here
1073 if( (nLastModifiers & (NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask))
1074 == NSAlternateKeyMask )
1078 [self sendKeyInputAndReleaseToFrame: nKeyCode character: aCharCode modifiers: nLastModifiers];
1082 SalExtTextInputEvent aEvent;
1083 aEvent.mnTime = mpFrame->mnLastEventTime;
1084 aEvent.maText = aInsertString;
1085 aEvent.mpTextAttr = NULL;
1086 aEvent.mnCursorPos = aInsertString.getLength();
1087 aEvent.mnDeltaStart = 0;
1088 aEvent.mnCursorFlags = 0;
1089 aEvent.mbOnlyCursor = FALSE;
1090 mpFrame->CallCallback( SALEVENT_EXTTEXTINPUT, &aEvent );
1091 if( AquaSalFrame::isAlive( mpFrame ) )
1092 mpFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, 0 );
1097 SalExtTextInputEvent aEvent;
1098 aEvent.mnTime = mpFrame->mnLastEventTime;
1099 aEvent.maText = OUString();
1100 aEvent.mpTextAttr = NULL;
1101 aEvent.mnCursorPos = 0;
1102 aEvent.mnDeltaStart = 0;
1103 aEvent.mnCursorFlags = 0;
1104 aEvent.mbOnlyCursor = FALSE;
1105 mpFrame->CallCallback( SALEVENT_EXTTEXTINPUT, &aEvent );
1106 if( AquaSalFrame::isAlive( mpFrame ) )
1107 mpFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, 0 );
1110 mbKeyHandled = true;
1115 -(void)insertTab: (id)aSender
1118 [self sendKeyInputAndReleaseToFrame: KEY_TAB character: '\t' modifiers: 0];
1121 -(void)insertBacktab: (id)aSender
1124 [self sendKeyInputAndReleaseToFrame: (KEY_TAB | KEY_SHIFT) character: '\t' modifiers: 0];
1127 -(void)moveLeft: (id)aSender
1130 [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: 0];
1133 -(void)moveLeftAndModifySelection: (id)aSender
1136 [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: NSShiftKeyMask];
1139 -(void)moveBackwardAndModifySelection: (id)aSender
1142 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_BACKWARD character: 0 modifiers: 0];
1145 -(void)moveRight: (id)aSender
1148 [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: 0];
1151 -(void)moveRightAndModifySelection: (id)aSender
1154 [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: NSShiftKeyMask];
1157 -(void)moveForwardAndModifySelection: (id)aSender
1160 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_FORWARD character: 0 modifiers: 0];
1163 -(void)moveWordLeft: (id)aSender
1166 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_WORD_BACKWARD character: 0 modifiers: 0];
1169 -(void)moveWordBackward: (id)aSender
1172 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_WORD_BACKWARD character: 0 modifiers: 0];
1175 -(void)moveWordBackwardAndModifySelection: (id)aSender
1178 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD_BACKWARD character: 0 modifiers: 0];
1181 -(void)moveWordLeftAndModifySelection: (id)aSender
1184 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD_BACKWARD character: 0 modifiers: 0];
1187 -(void)moveWordRight: (id)aSender
1190 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_WORD_FORWARD character: 0 modifiers: 0];
1193 -(void)moveWordForward: (id)aSender
1196 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_WORD_FORWARD character: 0 modifiers: 0];
1199 -(void)moveWordForwardAndModifySelection: (id)aSender
1202 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD_FORWARD character: 0 modifiers: 0];
1205 -(void)moveWordRightAndModifySelection: (id)aSender
1208 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD_FORWARD character: 0 modifiers: 0];
1211 -(void)moveToEndOfLine: (id)aSender
1214 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_LINE character: 0 modifiers: 0];
1217 -(void)moveToRightEndOfLine: (id)aSender
1220 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_LINE character: 0 modifiers: 0];
1223 -(void)moveToEndOfLineAndModifySelection: (id)aSender
1226 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_LINE character: 0 modifiers: 0];
1229 -(void)moveToRightEndOfLineAndModifySelection: (id)aSender
1232 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_LINE character: 0 modifiers: 0];
1235 -(void)moveToBeginningOfLine: (id)aSender
1238 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
1241 -(void)moveToLeftEndOfLine: (id)aSender
1244 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
1247 -(void)moveToBeginningOfLineAndModifySelection: (id)aSender
1250 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
1253 -(void)moveToLeftEndOfLineAndModifySelection: (id)aSender
1256 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
1259 -(void)moveToEndOfParagraph: (id)aSender
1262 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
1265 -(void)moveToEndOfParagraphAndModifySelection: (id)aSender
1268 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
1271 -(void)moveParagraphForward: (id)aSender
1274 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
1277 -(void)moveParagraphForwardAndModifySelection: (id)aSender
1280 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
1283 -(void)moveToBeginningOfParagraph: (id)aSender
1286 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
1289 -(void)moveParagraphBackward: (id)aSender
1292 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
1295 -(void)moveToBeginningOfParagraphAndModifySelection: (id)aSender
1298 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
1301 -(void)moveParagraphBackwardAndModifySelection: (id)aSender
1304 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
1307 -(void)moveToEndOfDocument: (id)aSender
1310 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT character: 0 modifiers: 0];
1313 -(void)scrollToEndOfDocument: (id)aSender
1316 // this is not exactly what we should do, but it makes "End" and "Shift-End" behave consistent
1317 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT character: 0 modifiers: 0];
1320 -(void)moveToEndOfDocumentAndModifySelection: (id)aSender
1323 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT character: 0 modifiers: 0];
1326 -(void)moveToBeginningOfDocument: (id)aSender
1329 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0];
1332 -(void)scrollToBeginningOfDocument: (id)aSender
1335 // this is not exactly what we should do, but it makes "Home" and "Shift-Home" behave consistent
1336 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0];
1339 -(void)moveToBeginningOfDocumentAndModifySelection: (id)aSender
1342 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0];
1345 -(void)moveUp: (id)aSender
1348 [self sendKeyInputAndReleaseToFrame: KEY_UP character: 0 modifiers: 0];
1351 -(void)moveDown: (id)aSender
1354 [self sendKeyInputAndReleaseToFrame: KEY_DOWN character: 0 modifiers: 0];
1357 -(void)insertNewline: (id)aSender
1360 // #i91267# make enter and shift-enter work by evaluating the modifiers
1361 [self sendKeyInputAndReleaseToFrame: KEY_RETURN character: '\n' modifiers: mpFrame->mnLastModifierFlags];
1364 -(void)deleteBackward: (id)aSender
1367 [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0];
1370 -(void)deleteForward: (id)aSender
1373 [self sendKeyInputAndReleaseToFrame: KEY_DELETE character: 0x7f modifiers: 0];
1376 -(void)deleteBackwardByDecomposingPreviousCharacter: (id)aSender
1379 [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0];
1382 -(void)deleteWordBackward: (id)aSender
1385 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_WORD_BACKWARD character: 0 modifiers: 0];
1388 -(void)deleteWordForward: (id)aSender
1391 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_WORD_FORWARD character: 0 modifiers: 0];
1394 -(void)deleteToBeginningOfLine: (id)aSender
1397 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
1400 -(void)deleteToEndOfLine: (id)aSender
1403 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_TO_END_OF_LINE character: 0 modifiers: 0];
1406 -(void)deleteToBeginningOfParagraph: (id)aSender
1409 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
1412 -(void)deleteToEndOfParagraph: (id)aSender
1415 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
1418 -(void)insertLineBreak: (id)aSender
1421 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::INSERT_LINEBREAK character: 0 modifiers: 0];
1424 -(void)insertParagraphSeparator: (id)aSender
1427 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::INSERT_PARAGRAPH character: 0 modifiers: 0];
1430 -(void)selectWord: (id)aSender
1433 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD character: 0 modifiers: 0];
1436 -(void)selectLine: (id)aSender
1439 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_LINE character: 0 modifiers: 0];
1442 -(void)selectParagraph: (id)aSender
1445 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_PARAGRAPH character: 0 modifiers: 0];
1448 -(void)selectAll: (id)aSender
1451 [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_ALL character: 0 modifiers: 0];
1454 -(void)cancelOperation: (id)aSender
1457 [self sendKeyInputAndReleaseToFrame: KEY_ESCAPE character: 0x1b modifiers: 0];
1460 -(void)noop: (id)aSender
1463 if( ! mbKeyHandled )
1465 if( ! [self sendSingleCharacter:mpLastEvent] )
1467 /* prevent recursion */
1468 if( mpLastEvent != mpLastSuperEvent && [NSApp respondsToSelector: @selector(sendSuperEvent:)] )
1470 id pLastSuperEvent = mpLastSuperEvent;
1471 mpLastSuperEvent = mpLastEvent;
1472 [NSApp performSelector:@selector(sendSuperEvent:) withObject: mpLastEvent];
1473 mpLastSuperEvent = pLastSuperEvent;
1475 std::map< NSEvent*, bool >::iterator it = GetSalData()->maKeyEventAnswer.find( mpLastEvent );
1476 if( it != GetSalData()->maKeyEventAnswer.end() )
1483 -(BOOL)sendKeyInputAndReleaseToFrame: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar
1485 return [self sendKeyInputAndReleaseToFrame: nKeyCode character: aChar modifiers: mpFrame->mnLastModifierFlags];
1488 -(BOOL)sendKeyInputAndReleaseToFrame: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod
1490 return [self sendKeyToFrameDirect: nKeyCode character: aChar modifiers: nMod] ||
1491 [self sendSingleCharacter: mpLastEvent];
1494 -(BOOL)sendKeyToFrameDirect: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod
1499 if( AquaSalFrame::isAlive( mpFrame ) )
1502 aEvent.mnTime = mpFrame->mnLastEventTime;
1503 aEvent.mnCode = nKeyCode | ImplGetModifierMask( nMod );
1504 aEvent.mnCharCode = aChar;
1505 aEvent.mnRepeat = FALSE;
1506 nRet = mpFrame->CallCallback( SALEVENT_KEYINPUT, &aEvent );
1507 std::map< NSEvent*, bool >::iterator it = GetSalData()->maKeyEventAnswer.find( mpLastEvent );
1508 if( it != GetSalData()->maKeyEventAnswer.end() )
1509 it->second = nRet ? true : false;
1510 if( AquaSalFrame::isAlive( mpFrame ) )
1511 mpFrame->CallCallback( SALEVENT_KEYUP, &aEvent );
1513 return nRet ? YES : NO;
1517 -(BOOL)sendSingleCharacter: (NSEvent *)pEvent
1519 NSString* pUnmodifiedString = [pEvent charactersIgnoringModifiers];
1521 if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
1523 unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
1524 sal_uInt16 nKeyCode = ImplMapCharCode( keyChar );
1527 sal_uInt16 nOtherKeyCode = [pEvent keyCode];
1528 nKeyCode = ImplMapKeyCode(nOtherKeyCode);
1532 // don't send unicodes in the private use area
1533 if( keyChar >= 0xf700 && keyChar < 0xf780 )
1535 BOOL bRet = [self sendKeyToFrameDirect: nKeyCode character: keyChar modifiers: mpFrame->mnLastModifierFlags];
1536 mbInKeyInput = false;
1545 // NSTextInput protocol
1546 - (NSArray *)validAttributesForMarkedText
1548 return [NSArray arrayWithObjects:NSUnderlineStyleAttributeName, nil];
1551 - (BOOL)hasMarkedText
1553 BOOL bHasMarkedText;
1555 bHasMarkedText = ( mMarkedRange.location != NSNotFound ) &&
1556 ( mMarkedRange.length != 0 );
1557 // hack to check keys like "Control-j"
1560 mbNeedSpecialKeyHandle = true;
1565 // if we come here outside of mbInKeyInput, this is likely to be because
1566 // of the keyboard viewer. For unknown reasons having no marked range
1567 // in this case causes a crash. So we say we have a marked range anyway
1568 // This is a hack, since it is not understood what a) causes that crash
1569 // and b) why we should have a marked range at this point.
1570 if( ! mbInKeyInput )
1571 bHasMarkedText = YES;
1573 return bHasMarkedText;
1576 - (NSRange)markedRange
1580 // if we come here outside of mbInKeyInput, this is likely to be because
1581 // of the keyboard viewer. For unknown reasons having no marked range
1582 // in this case causes a crash. So we say we have a marked range anyway
1583 // This is a hack, since it is not understood what a) causes that crash
1584 // and b) why we should have a marked range at this point.
1585 if( ! mbInKeyInput )
1586 return NSMakeRange( 0, 0 );
1588 return [self hasMarkedText] ? mMarkedRange : NSMakeRange( NSNotFound, 0 );
1591 - (NSRange)selectedRange
1593 return mSelectedRange;
1596 - (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange
1598 if( ![aString isKindOfClass:[NSAttributedString class]] )
1599 aString = [[[NSAttributedString alloc] initWithString:aString] autorelease];
1600 NSRange rangeToReplace = [self hasMarkedText] ? [self markedRange] : [self selectedRange];
1601 if( rangeToReplace.location == NSNotFound )
1603 mMarkedRange = NSMakeRange( selRange.location, [aString length] );
1604 mSelectedRange = NSMakeRange( selRange.location, selRange.length );
1608 mMarkedRange = NSMakeRange( rangeToReplace.location, [aString length] );
1609 mSelectedRange = NSMakeRange( rangeToReplace.location + selRange.location, selRange.length );
1612 int len = [aString length];
1613 SalExtTextInputEvent aInputEvent;
1614 aInputEvent.mnTime = mpFrame->mnLastEventTime;
1615 aInputEvent.mnDeltaStart = 0;
1616 aInputEvent.mbOnlyCursor = FALSE;
1618 NSString *pString = [aString string];
1619 OUString aInsertString( GetOUString( pString ) );
1620 std::vector<sal_uInt16> aInputFlags = std::vector<sal_uInt16>( std::max( 1, len ), 0 );
1621 for ( int i = 0; i < len; i++ )
1623 unsigned int nUnderlineValue;
1624 NSRange effectiveRange;
1626 effectiveRange = NSMakeRange(i, 1);
1627 nUnderlineValue = [[aString attribute:NSUnderlineStyleAttributeName atIndex:i effectiveRange:&effectiveRange] unsignedIntValue];
1629 switch (nUnderlineValue & 0xff) {
1630 case NSUnderlineStyleSingle:
1631 aInputFlags[i] = EXTTEXTINPUT_ATTR_UNDERLINE;
1633 case NSUnderlineStyleThick:
1634 aInputFlags[i] = EXTTEXTINPUT_ATTR_UNDERLINE | EXTTEXTINPUT_ATTR_HIGHLIGHT;
1636 case NSUnderlineStyleDouble:
1637 aInputFlags[i] = EXTTEXTINPUT_ATTR_BOLDUNDERLINE;
1640 aInputFlags[i] = EXTTEXTINPUT_ATTR_HIGHLIGHT;
1645 aInputEvent.maText = aInsertString;
1646 aInputEvent.mnCursorPos = selRange.location;
1647 aInputEvent.mpTextAttr = &aInputFlags[0];
1648 mpFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void *)&aInputEvent );
1650 aInputEvent.maText = OUString();
1651 aInputEvent.mnCursorPos = 0;
1652 aInputEvent.mnCursorFlags = 0;
1653 aInputEvent.mpTextAttr = 0;
1654 mpFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void *)&aInputEvent );
1655 mpFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, 0 );
1662 mSelectedRange = mMarkedRange = NSMakeRange(NSNotFound, 0);
1665 - (NSAttributedString *)attributedSubstringFromRange:(NSRange)theRange
1672 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
1679 - (NSInteger)conversationIdentifier
1684 - (void)doCommandBySelector:(SEL)aSelector
1686 if( AquaSalFrame::isAlive( mpFrame ) )
1688 #if OSL_DEBUG_LEVEL > 1
1689 // fprintf( stderr, "SalFrameView: doCommandBySelector %s\n", (char*)aSelector );
1691 if( (mpFrame->mnICOptions & SAL_INPUTCONTEXT_TEXT) != 0 &&
1692 aSelector != NULL && [self respondsToSelector: aSelector] )
1694 [self performSelector: aSelector];
1698 [self sendSingleCharacter:mpLastEvent];
1702 mbKeyHandled = true;
1705 -(void)clearLastEvent
1710 - (NSRect)firstRectForCharacterRange:(NSRange)theRange
1713 SalExtTextInputPosEvent aPosEvent;
1714 mpFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void *)&aPosEvent );
1718 rect.origin.x = aPosEvent.mnX + mpFrame->maGeometry.nX;
1719 rect.origin.y = aPosEvent.mnY + mpFrame->maGeometry.nY + 4; // add some space for underlines
1720 rect.size.width = aPosEvent.mnWidth;
1721 rect.size.height = aPosEvent.mnHeight;
1723 mpFrame->VCLToCocoa( rect );
1727 -(id)parentAttribute {
1728 return (NSView *) mpFrame -> mpWindow;
1731 -(::com::sun::star::accessibility::XAccessibleContext *)accessibleContext
1733 if ( mpReferenceWrapper == nil ) {
1734 // some frames never become visible ..
1735 Window *pWindow = mpFrame -> GetWindow();
1739 mpReferenceWrapper = new ReferenceWrapper;
1740 mpReferenceWrapper -> rAccessibleContext = pWindow -> /*GetAccessibleChildWindow( 0 ) ->*/ GetAccessible() -> getAccessibleContext();
1741 [ AquaA11yFactory insertIntoWrapperRepository: self forAccessibleContext: mpReferenceWrapper -> rAccessibleContext ];
1743 return [ super accessibleContext ];
1746 -(NSView *)viewElementForParent
1748 return (NSView *) mpFrame -> mpWindow;
1751 -(void)registerMouseEventListener: (id)theListener
1753 mpMouseEventListener = theListener;
1756 -(void)unregisterMouseEventListener: (id)theListener
1759 mpMouseEventListener = nil;
1762 -(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
1764 return [mDraggingDestinationHandler draggingEntered: sender];
1767 -(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
1769 return [mDraggingDestinationHandler draggingUpdated: sender];
1772 -(void)draggingExited:(id <NSDraggingInfo>)sender
1774 [mDraggingDestinationHandler draggingExited: sender];
1777 -(BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
1779 return [mDraggingDestinationHandler prepareForDragOperation: sender];
1782 -(BOOL)performDragOperation:(id <NSDraggingInfo>)sender
1784 return [mDraggingDestinationHandler performDragOperation: sender];
1787 -(void)concludeDragOperation:(id <NSDraggingInfo>)sender
1789 [mDraggingDestinationHandler concludeDragOperation: sender];
1792 -(void)registerDraggingDestinationHandler:(id)theHandler
1794 mDraggingDestinationHandler = theHandler;
1797 -(void)unregisterDraggingDestinationHandler:(id)theHandler
1800 mDraggingDestinationHandler = nil;
1805 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */