1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2/* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20#include <sal/config.h> 21 22#include <sal/macros.h> 23#include <tools/helpers.hxx> 24 25#include <vcl/event.hxx> 26#include <vcl/inputctx.hxx> 27#include <vcl/settings.hxx> 28#include <vcl/svapp.hxx> 29#include <vcl/window.hxx> 30#include <vcl/commandevent.hxx> 31 32#include <osx/a11yfactory.h> 33#include <osx/salframe.h> 34#include <osx/salframeview.h> 35#include <osx/salinst.h> 36#include <quartz/salgdi.h> 37#include <quartz/utils.h> 38 39#define WHEEL_EVENT_FACTOR 1.5 40 41static sal_uInt16 ImplGetModifierMask( unsigned int nMask ) 42{ 43 sal_uInt16 nRet = 0; 44SAL_WNODEPRECATED_DECLARATIONS_PUSH 45 // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12 46 // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12 47 // 'NSControlKeyMask' is deprecated: first deprecated in macOS 10.12 48 // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12 49 if( (nMask & NSShiftKeyMask) != 0 ) 50 nRet |= KEY_SHIFT; 51 if( (nMask & NSControlKeyMask) != 0 ) 52 nRet |= KEY_MOD3; 53 if( (nMask & NSAlternateKeyMask) != 0 ) 54 nRet |= KEY_MOD2; 55 if( (nMask & NSCommandKeyMask) != 0 ) 56 nRet |= KEY_MOD1; 57SAL_WNODEPRECATED_DECLARATIONS_POP 58 return nRet; 59} 60 61static sal_uInt16 ImplMapCharCode( sal_Unicode aCode ) 62{ 63 static sal_uInt16 aKeyCodeMap[ 128 ] = 64 { 65 0, 0, 0, 0, 0, 0, 0, 0, 66 KEY_BACKSPACE, KEY_TAB, KEY_RETURN, 0, 0, KEY_RETURN, 0, 0, 67 0, 0, 0, 0, 0, 0, 0, 0, 68 0, KEY_TAB, 0, KEY_ESCAPE, 0, 0, 0, 0, 69 KEY_SPACE, 0, 0, 0, 0, 0, 0, 0, 70 0, 0, KEY_MULTIPLY, KEY_ADD, KEY_COMMA, KEY_SUBTRACT, KEY_POINT, KEY_DIVIDE, 71 KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, 72 KEY_8, KEY_9, 0, 0, KEY_LESS, KEY_EQUAL, KEY_GREATER, 0, 73 0, KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, 74 KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, 75 KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W, 76 KEY_X, KEY_Y, KEY_Z, 0, 0, 0, 0, 0, 77 KEY_QUOTELEFT, KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, 78 KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, 79 KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W, 80 KEY_X, KEY_Y, KEY_Z, 0, 0, 0, KEY_TILDE, KEY_BACKSPACE 81 }; 82 83 // Note: the mapping 0x7f should by rights be KEY_DELETE 84 // however if you press "backspace" 0x7f is reported 85 // whereas for "delete" 0xf728 gets reported 86 87 // Note: the mapping of 0x19 to KEY_TAB is because for unknown reasons 88 // tab alone is reported as 0x09 (as expected) but shift-tab is 89 // reported as 0x19 (end of medium) 90 91 static sal_uInt16 aFunctionKeyCodeMap[ 128 ] = 92 { 93 KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_F1, KEY_F2, KEY_F3, KEY_F4, 94 KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, 95 KEY_F13, KEY_F14, KEY_F15, KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20, 96 KEY_F21, KEY_F22, KEY_F23, KEY_F24, KEY_F25, KEY_F26, 0, 0, 97 0, 0, 0, 0, 0, 0, 0, KEY_INSERT, 98 KEY_DELETE, KEY_HOME, 0, KEY_END, KEY_PAGEUP, KEY_PAGEDOWN, 0, 0, 99 0, 0, 0, 0, 0, KEY_MENU, 0, 0, 100 0, 0, 0, 0, 0, 0, 0, 0, 101 0, 0, 0, KEY_UNDO, KEY_REPEAT, KEY_FIND, KEY_HELP, 0, 102 0, 0, 0, 0, 0, 0, 0, 0, 103 0, 0, 0, 0, 0, 0, 0, 0, 104 0, 0, 0, 0, 0, 0, 0, 0, 105 0, 0, 0, 0, 0, 0, 0, 0, 106 0, 0, 0, 0, 0, 0, 0, 0, 107 0, 0, 0, 0, 0, 0, 0, 0, 108 0, 0, 0, 0, 0, 0, 0, 0 109 }; 110 111 sal_uInt16 nKeyCode = 0; 112 if( aCode < SAL_N_ELEMENTS( aKeyCodeMap) ) 113 nKeyCode = aKeyCodeMap[ aCode ]; 114 else if( aCode >= 0xf700 && aCode < 0xf780 ) 115 nKeyCode = aFunctionKeyCodeMap[ aCode - 0xf700 ]; 116 return nKeyCode; 117} 118 119static sal_uInt16 ImplMapKeyCode(sal_uInt16 nKeyCode) 120{ 121 /* 122 http://stackoverflow.com/questions/2080312/where-can-i-find-a-list-of-key-codes-for-use-with-cocoas-nsevent-class/2080324#2080324 123 /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h 124 */ 125 126 static sal_uInt16 aKeyCodeMap[ 0x80 ] = 127 { 128 KEY_A, KEY_S, KEY_D, KEY_F, KEY_H, KEY_G, KEY_Z, KEY_X, 129 KEY_C, KEY_V, 0, KEY_B, KEY_Q, KEY_W, KEY_E, KEY_R, 130 KEY_Y, KEY_T, KEY_1, KEY_2, KEY_3, KEY_4, KEY_6, KEY_5, 131 KEY_EQUAL, KEY_9, KEY_7, KEY_SUBTRACT, KEY_8, KEY_0, KEY_BRACKETRIGHT, KEY_0, 132 KEY_U, KEY_BRACKETLEFT, KEY_I, KEY_P, KEY_RETURN, KEY_L, KEY_J, KEY_QUOTERIGHT, 133 KEY_K, KEY_SEMICOLON, 0, KEY_COMMA, KEY_DIVIDE, KEY_N, KEY_M, KEY_POINT, 134 KEY_TAB, KEY_SPACE, KEY_QUOTELEFT, KEY_DELETE, 0, KEY_ESCAPE, 0, 0, 135 0, KEY_CAPSLOCK, 0, 0, 0, 0, 0, 0, 136 KEY_F17, KEY_DECIMAL, 0, KEY_MULTIPLY, 0, KEY_ADD, 0, 0, 137 0, 0, 0, KEY_DIVIDE, KEY_RETURN, 0, KEY_SUBTRACT, KEY_F18, 138 KEY_F19, KEY_EQUAL, 0, 0, 0, 0, 0, 0, 139 0, 0, KEY_F20, 0, 0, 0, 0, 0, 140 KEY_F5, KEY_F6, KEY_F7, KEY_F3, KEY_F8, KEY_F9, 0, KEY_F11, 141 0, KEY_F13, KEY_F16, KEY_F14, 0, KEY_F10, 0, KEY_F12, 142 0, KEY_F15, KEY_HELP, KEY_HOME, KEY_PAGEUP, KEY_DELETE, KEY_F4, KEY_END, 143 KEY_F2, KEY_PAGEDOWN, KEY_F1, KEY_LEFT, KEY_RIGHT, KEY_DOWN, KEY_UP, 0 144 }; 145 146 if (nKeyCode < SAL_N_ELEMENTS(aKeyCodeMap)) 147 return aKeyCodeMap[nKeyCode]; 148 return 0; 149} 150 151// store the frame the mouse last entered 152static AquaSalFrame* s_pMouseFrame = nullptr; 153// store the last pressed button for enter/exit events 154// which lack that information 155static sal_uInt16 s_nLastButton = 0; 156 157static AquaSalFrame* getMouseContainerFrame() 158{ 159 AquaSalFrame* pDispatchFrame = nullptr; 160 NSArray* aWindows = [NSWindow windowNumbersWithOptions:0]; 161 for(NSUInteger i = 0; i < [aWindows count] && ! pDispatchFrame; i++ ) 162 { 163 NSWindow* pWin = [NSApp windowWithWindowNumber:[[aWindows objectAtIndex:i] integerValue]]; 164 if( pWin && [pWin isMemberOfClass: [SalFrameWindow class]] && [static_cast<SalFrameWindow*>(pWin) containsMouse] ) 165 pDispatchFrame = [static_cast<SalFrameWindow*>(pWin) getSalFrame]; 166 } 167 return pDispatchFrame; 168} 169 170@implementation SalFrameWindow 171-(id)initWithSalFrame: (AquaSalFrame*)pFrame 172{ 173 mDraggingDestinationHandler = nil; 174 mpFrame = pFrame; 175 NSRect aRect = { { static_cast<CGFloat>(pFrame->maGeometry.nX), static_cast<CGFloat>(pFrame->maGeometry.nY) }, 176 { static_cast<CGFloat>(pFrame->maGeometry.nWidth), static_cast<CGFloat>(pFrame->maGeometry.nHeight) } }; 177 pFrame->VCLToCocoa( aRect ); 178 NSWindow* pNSWindow = [super initWithContentRect: aRect 179 styleMask: mpFrame->getStyleMask() 180 backing: NSBackingStoreBuffered 181 defer: Application::IsHeadlessModeEnabled()]; 182 183 // Disallow full-screen mode on macOS >= 10.11 where it is enabled by default. We don't want it 184 // for now as it will just be confused with LibreOffice's home-grown full-screen concept, with 185 // which it has nothing to do, and one can get into all kinds of weird states by using them 186 // intermixedly. 187 188 // Ideally we should use the system full-screen mode and adapt the code for the home-grown thing 189 // to be in sync with that instead. (And we would then not need the button to get out of 190 // full-screen mode, as the normal way to get out of it is to either click on the green bubble 191 // again, or invoke the keyboard command again.) 192 193 // (Confusingly, at the moment the home-grown full-screen mode is bound to Cmd+Shift+F, which is 194 // the keyboard command normally used in apps to get in and out of the system full-screen mode.) 195 196 // Disabling system full-screen mode makes the green button on the title bar (on macOS >= 10.11) 197 // show a plus sign instead, and clicking it becomes identical to double-clicking the title bar, 198 // i.e. it maximizes / unmaximises the window. Sure, that state can also be confused with LO's 199 // home-grown full-screen mode. Oh well. 200 201 [pNSWindow setCollectionBehavior: NSWindowCollectionBehaviorFullScreenNone]; 202 203 // Disable window restoration until we support it directly 204 [pNSWindow setRestorable: NO]; 205 206 return static_cast<SalFrameWindow *>(pNSWindow); 207} 208 209-(AquaSalFrame*)getSalFrame 210{ 211 return mpFrame; 212} 213 214-(void)displayIfNeeded 215{ 216 if( GetSalData() && GetSalData()->mpInstance ) 217 { 218 SolarMutexGuard aGuard; 219 [super displayIfNeeded]; 220 } 221} 222 223-(BOOL)containsMouse 224{ 225 // is this event actually inside that NSWindow ? 226 NSPoint aPt = [NSEvent mouseLocation]; 227 NSRect aFrameRect = [self frame]; 228 BOOL bInRect = NSPointInRect( aPt, aFrameRect ); 229 return bInRect; 230} 231 232-(BOOL)canBecomeKeyWindow 233{ 234 if( (mpFrame->mnStyle & 235 ( SalFrameStyleFlags::FLOAT | 236 SalFrameStyleFlags::TOOLTIP | 237 SalFrameStyleFlags::INTRO 238 )) == SalFrameStyleFlags::NONE ) 239 return YES; 240 if( mpFrame->mnStyle & SalFrameStyleFlags::OWNERDRAWDECORATION ) 241 return YES; 242 if( mpFrame->mbFullScreen ) 243 return YES; 244 return [super canBecomeKeyWindow]; 245} 246 247-(void)windowDidBecomeKey: (NSNotification*)pNotification 248{ 249 (void)pNotification; 250 SolarMutexGuard aGuard; 251 252 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) 253 { 254 static const SalFrameStyleFlags nGuessDocument = SalFrameStyleFlags::MOVEABLE| 255 SalFrameStyleFlags::SIZEABLE| 256 SalFrameStyleFlags::CLOSEABLE; 257 258 if( mpFrame->mpMenu ) 259 mpFrame->mpMenu->setMainMenu(); 260 else if( ! mpFrame->mpParent && 261 ( (mpFrame->mnStyle & nGuessDocument) == nGuessDocument || // set default menu for e.g. help 262 mpFrame->mbFullScreen ) ) // set default menu for e.g. presentation 263 { 264 AquaSalMenu::setDefaultMenu(); 265 } 266 #if 0 267 // FIXME: we should disable menus while in modal mode 268 // however from down here there is currently no reliable way to 269 // find out when to do this 270 if( (mpFrame->mpParent && mpFrame->mpParent->GetWindow()->IsInModalMode()) ) 271 AquaSalMenu::enableMainMenu( false ); 272 #endif 273 mpFrame->CallCallback( SalEvent::GetFocus, nullptr ); 274 mpFrame->SendPaintEvent(); // repaint controls as active 275 } 276} 277 278-(void)windowDidResignKey: (NSNotification*)pNotification 279{ 280 (void)pNotification; 281 SolarMutexGuard aGuard; 282 283 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) 284 { 285 mpFrame->CallCallback(SalEvent::LoseFocus, nullptr); 286 mpFrame->SendPaintEvent(); // repaint controls as inactive 287 } 288} 289 290-(void)windowDidChangeScreen: (NSNotification*)pNotification 291{ 292 (void)pNotification; 293 SolarMutexGuard aGuard; 294 295 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) 296 mpFrame->screenParametersChanged(); 297} 298 299-(void)windowDidMove: (NSNotification*)pNotification 300{ 301 (void)pNotification; 302 SolarMutexGuard aGuard; 303 304 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) 305 { 306 mpFrame->UpdateFrameGeometry(); 307 mpFrame->CallCallback( SalEvent::Move, nullptr ); 308 } 309} 310 311-(void)windowDidResize: (NSNotification*)pNotification 312{ 313 (void)pNotification; 314 SolarMutexGuard aGuard; 315 316 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) 317 { 318 mpFrame->UpdateFrameGeometry(); 319 mpFrame->CallCallback( SalEvent::Resize, nullptr ); 320 mpFrame->SendPaintEvent(); 321 } 322} 323 324-(void)windowDidMiniaturize: (NSNotification*)pNotification 325{ 326 (void)pNotification; 327 SolarMutexGuard aGuard; 328 329 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) 330 { 331 mpFrame->mbShown = false; 332 mpFrame->UpdateFrameGeometry(); 333 mpFrame->CallCallback( SalEvent::Resize, nullptr ); 334 } 335} 336 337-(void)windowDidDeminiaturize: (NSNotification*)pNotification 338{ 339 (void)pNotification; 340 SolarMutexGuard aGuard; 341 342 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) 343 { 344 mpFrame->mbShown = true; 345 mpFrame->UpdateFrameGeometry(); 346 mpFrame->CallCallback( SalEvent::Resize, nullptr ); 347 } 348} 349 350-(BOOL)windowShouldClose: (NSNotification*)pNotification 351{ 352 (void)pNotification; 353 SolarMutexGuard aGuard; 354 355 BOOL bRet = YES; 356 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) 357 { 358 // #i84461# end possible input 359 mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr ); 360 if( AquaSalFrame::isAlive( mpFrame ) ) 361 { 362 mpFrame->CallCallback( SalEvent::Close, nullptr ); 363 bRet = NO; // application will close the window or not, AppKit shouldn't 364 AquaSalTimer *pTimer = static_cast<AquaSalTimer*>( ImplGetSVData()->maSchedCtx.mpSalTimer ); 365 assert( pTimer ); 366 pTimer->handleWindowShouldClose(); 367 } 368 } 369 370 return bRet; 371} 372 373-(void)windowDidEnterFullScreen: (NSNotification*)pNotification 374{ 375 SolarMutexGuard aGuard; 376 377 if( !mpFrame || !AquaSalFrame::isAlive( mpFrame)) 378 return; 379 mpFrame->mbFullScreen = true; 380 (void)pNotification; 381} 382 383-(void)windowDidExitFullScreen: (NSNotification*)pNotification 384{ 385 SolarMutexGuard aGuard; 386 387 if( !mpFrame || !AquaSalFrame::isAlive( mpFrame)) 388 return; 389 mpFrame->mbFullScreen = false; 390 (void)pNotification; 391} 392 393-(void)dockMenuItemTriggered: (id)sender 394{ 395 (void)sender; 396 SolarMutexGuard aGuard; 397 398 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) 399 mpFrame->ToTop( SalFrameToTop::RestoreWhenMin | SalFrameToTop::GrabFocus ); 400} 401 402-(css::uno::Reference < css::accessibility::XAccessibleContext >)accessibleContext 403{ 404 return mpFrame -> GetWindow() -> GetAccessible() -> getAccessibleContext(); 405} 406 407-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender 408{ 409 return [mDraggingDestinationHandler draggingEntered: sender]; 410} 411 412-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender 413{ 414 return [mDraggingDestinationHandler draggingUpdated: sender]; 415} 416 417-(void)draggingExited:(id <NSDraggingInfo>)sender 418{ 419 [mDraggingDestinationHandler draggingExited: sender]; 420} 421 422-(BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender 423{ 424 return [mDraggingDestinationHandler prepareForDragOperation: sender]; 425} 426 427-(BOOL)performDragOperation:(id <NSDraggingInfo>)sender 428{ 429 return [mDraggingDestinationHandler performDragOperation: sender]; 430} 431 432-(void)concludeDragOperation:(id <NSDraggingInfo>)sender 433{ 434 [mDraggingDestinationHandler concludeDragOperation: sender]; 435} 436 437-(void)registerDraggingDestinationHandler:(id)theHandler 438{ 439 mDraggingDestinationHandler = theHandler; 440} 441 442-(void)unregisterDraggingDestinationHandler:(id)theHandler 443{ 444 (void)theHandler; 445 mDraggingDestinationHandler = nil; 446} 447 448@end 449 450@implementation SalFrameView 451+(void)unsetMouseFrame: (AquaSalFrame*)pFrame 452{ 453 if( pFrame == s_pMouseFrame ) 454 s_pMouseFrame = nullptr; 455} 456 457-(id)initWithSalFrame: (AquaSalFrame*)pFrame 458{ 459 if ((self = [super initWithFrame: [NSWindow contentRectForFrameRect: [pFrame->getNSWindow() frame] styleMask: pFrame->mnStyleMask]]) != nil) 460 { 461 mDraggingDestinationHandler = nil; 462 mpFrame = pFrame; 463 mMarkedRange = NSMakeRange(NSNotFound, 0); 464 mSelectedRange = NSMakeRange(NSNotFound, 0); 465 mpReferenceWrapper = nil; 466 mpMouseEventListener = nil; 467 mpLastSuperEvent = nil; 468 } 469 470 mfLastMagnifyTime = 0.0; 471 return self; 472} 473 474-(AquaSalFrame*)getSalFrame 475{ 476 return mpFrame; 477} 478 479-(void)resetCursorRects 480{ 481 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) 482 { 483 // FIXME: does this leak the returned NSCursor of getCurrentCursor ? 484 const NSRect aRect = { NSZeroPoint, NSMakeSize( mpFrame->maGeometry.nWidth, mpFrame->maGeometry.nHeight) }; 485 [self addCursorRect: aRect cursor: mpFrame->getCurrentCursor()]; 486 } 487} 488 489-(BOOL)acceptsFirstResponder 490{ 491 return YES; 492} 493 494-(BOOL)acceptsFirstMouse: (NSEvent*)pEvent 495{ 496 (void)pEvent; 497 return YES; 498} 499 500-(BOOL)isOpaque 501{ 502 if( !mpFrame) 503 return YES; 504 if( !AquaSalFrame::isAlive( mpFrame)) 505 return YES; 506 if( !mpFrame->getClipPath()) 507 return YES; 508 return NO; 509} 510 511-(void)drawRect: (NSRect)aRect 512{ 513 AquaSalInstance *pInstance = GetSalData()->mpInstance; 514 assert(pInstance); 515 if (!pInstance) 516 return; 517 518 SolarMutexGuard aGuard; 519 if (!mpFrame || !AquaSalFrame::isAlive(mpFrame)) 520 return; 521 522 const bool bIsLiveResize = [self inLiveResize]; 523 const bool bWasLiveResize = pInstance->mbIsLiveResize; 524 if (bWasLiveResize != bIsLiveResize) 525 { 526 pInstance->mbIsLiveResize = bIsLiveResize; 527 Scheduler::ProcessTaskScheduling(); 528 } 529 530 AquaSalGraphics* pGraphics = mpFrame->mpGraphics; 531 if (pGraphics) 532 { 533 pGraphics->UpdateWindow(aRect); 534 if (mpFrame->getClipPath()) 535 [mpFrame->getNSWindow() invalidateShadow]; 536 } 537} 538 539-(void)sendMouseEventToFrame: (NSEvent*)pEvent button:(sal_uInt16)nButton eventtype:(SalEvent)nEvent 540{ 541 SolarMutexGuard aGuard; 542 543 AquaSalFrame* pDispatchFrame = AquaSalFrame::GetCaptureFrame(); 544 bool bIsCaptured = false; 545 if( pDispatchFrame ) 546 { 547 bIsCaptured = true; 548 if( nEvent == SalEvent::MouseLeave ) // no leave events if mouse is captured 549 nEvent = SalEvent::MouseMove; 550 } 551 else if( s_pMouseFrame ) 552 pDispatchFrame = s_pMouseFrame; 553 else 554 pDispatchFrame = mpFrame; 555 556 /* #i81645# Cocoa reports mouse events while a button is pressed 557 to the window in which it was first pressed. This is reasonable and fine and 558 gets one around most cases where on other platforms one uses CaptureMouse or XGrabPointer, 559 however vcl expects mouse events to occur in the window the mouse is over, unless the 560 mouse is explicitly captured. So we need to find the window the mouse is actually 561 over for conformance with other platforms. 562 */ 563 if( ! bIsCaptured && nButton && pDispatchFrame && AquaSalFrame::isAlive( pDispatchFrame ) ) 564 { 565 // is this event actually inside that NSWindow ? 566 NSPoint aPt = [NSEvent mouseLocation]; 567 NSRect aFrameRect = [pDispatchFrame->getNSWindow() frame]; 568 569 if ( ! NSPointInRect( aPt, aFrameRect ) ) 570 { 571 // no, it is not 572 // now we need to find the one it may be in 573 /* #i93756# we ant to get enumerate the application windows in z-order 574 to check if any contains the mouse. This could be elegantly done with this 575 code: 576 577 // use NSApp to check windows in ZOrder whether they contain the mouse pointer 578 NSWindow* pWindow = [NSApp makeWindowsPerform: @selector(containsMouse) inOrder: YES]; 579 if( pWindow && [pWindow isMemberOfClass: [SalFrameWindow class]] ) 580 pDispatchFrame = [(SalFrameWindow*)pWindow getSalFrame]; 581 582 However if a non SalFrameWindow is on screen (like e.g. the file dialog) 583 it can be hit with the containsMouse selector, which it doesn't support. 584 Sadly NSApplication:makeWindowsPerform does not check (for performance reasons 585 I assume) whether a window supports a selector before sending it. 586 */ 587 AquaSalFrame* pMouseFrame = getMouseContainerFrame(); 588 if( pMouseFrame ) 589 pDispatchFrame = pMouseFrame; 590 } 591 } 592 593 if( pDispatchFrame && AquaSalFrame::isAlive( pDispatchFrame ) ) 594 { 595 pDispatchFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 ); 596 pDispatchFrame->mnLastModifierFlags = [pEvent modifierFlags]; 597 598 NSPoint aPt = [NSEvent mouseLocation]; 599 pDispatchFrame->CocoaToVCL( aPt ); 600 601 sal_uInt16 nModMask = ImplGetModifierMask( [pEvent modifierFlags] ); 602 // #i82284# emulate ctrl left 603 if( nModMask == KEY_MOD3 && nButton == MOUSE_LEFT ) 604 { 605 nModMask = 0; 606 nButton = MOUSE_RIGHT; 607 } 608 609 SalMouseEvent aEvent; 610 aEvent.mnTime = pDispatchFrame->mnLastEventTime; 611 aEvent.mnX = static_cast<long>(aPt.x) - pDispatchFrame->maGeometry.nX; 612 aEvent.mnY = static_cast<long>(aPt.y) - pDispatchFrame->maGeometry.nY; 613 aEvent.mnButton = nButton; 614 aEvent.mnCode = aEvent.mnButton | nModMask; 615 616 if( AllSettings::GetLayoutRTL() ) 617 aEvent.mnX = pDispatchFrame->maGeometry.nWidth-1-aEvent.mnX; 618 619 pDispatchFrame->CallCallback( nEvent, &aEvent ); 620 } 621} 622 623-(void)mouseDown: (NSEvent*)pEvent 624{ 625 if ( mpMouseEventListener != nil && 626 [mpMouseEventListener respondsToSelector: @selector(mouseDown:)]) 627 { 628 [mpMouseEventListener mouseDown: [pEvent copyWithZone: nullptr]]; 629 } 630 631 s_nLastButton = MOUSE_LEFT; 632 [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SalEvent::MouseButtonDown]; 633} 634 635-(void)mouseDragged: (NSEvent*)pEvent 636{ 637 if ( mpMouseEventListener != nil && 638 [mpMouseEventListener respondsToSelector: @selector(mouseDragged:)]) 639 { 640 [mpMouseEventListener mouseDragged: [pEvent copyWithZone: nullptr]]; 641 } 642 s_nLastButton = MOUSE_LEFT; 643 [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SalEvent::MouseMove]; 644} 645 646-(void)mouseUp: (NSEvent*)pEvent 647{ 648 s_nLastButton = 0; 649 [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SalEvent::MouseButtonUp]; 650} 651 652-(void)mouseMoved: (NSEvent*)pEvent 653{ 654 s_nLastButton = 0; 655 [self sendMouseEventToFrame:pEvent button:0 eventtype:SalEvent::MouseMove]; 656} 657 658-(void)mouseEntered: (NSEvent*)pEvent 659{ 660 s_pMouseFrame = mpFrame; 661 662 // #i107215# the only mouse events we get when inactive are enter/exit 663 // actually we would like to have all of them, but better none than some 664 if( [NSApp isActive] ) 665 [self sendMouseEventToFrame:pEvent button:s_nLastButton eventtype:SalEvent::MouseMove]; 666} 667 668-(void)mouseExited: (NSEvent*)pEvent 669{ 670 if( s_pMouseFrame == mpFrame ) 671 s_pMouseFrame = nullptr; 672 673 // #i107215# the only mouse events we get when inactive are enter/exit 674 // actually we would like to have all of them, but better none than some 675 if( [NSApp isActive] ) 676 [self sendMouseEventToFrame:pEvent button:s_nLastButton eventtype:SalEvent::MouseLeave]; 677} 678 679-(void)rightMouseDown: (NSEvent*)pEvent 680{ 681 s_nLastButton = MOUSE_RIGHT; 682 [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SalEvent::MouseButtonDown]; 683} 684 685-(void)rightMouseDragged: (NSEvent*)pEvent 686{ 687 s_nLastButton = MOUSE_RIGHT; 688 [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SalEvent::MouseMove]; 689} 690 691-(void)rightMouseUp: (NSEvent*)pEvent 692{ 693 s_nLastButton = 0; 694 [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SalEvent::MouseButtonUp]; 695} 696 697-(void)otherMouseDown: (NSEvent*)pEvent 698{ 699 if( [pEvent buttonNumber] == 2 ) 700 { 701 s_nLastButton = MOUSE_MIDDLE; 702 [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SalEvent::MouseButtonDown]; 703 } 704 else 705 s_nLastButton = 0; 706} 707 708-(void)otherMouseDragged: (NSEvent*)pEvent 709{ 710 if( [pEvent buttonNumber] == 2 ) 711 { 712 s_nLastButton = MOUSE_MIDDLE; 713 [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SalEvent::MouseMove]; 714 } 715 else 716 s_nLastButton = 0; 717} 718 719-(void)otherMouseUp: (NSEvent*)pEvent 720{ 721 s_nLastButton = 0; 722 if( [pEvent buttonNumber] == 2 ) 723 [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SalEvent::MouseButtonUp]; 724} 725 726- (void)magnifyWithEvent: (NSEvent*)pEvent 727{ 728 SolarMutexGuard aGuard; 729 730 // TODO: ?? -(float)magnification; 731 if( AquaSalFrame::isAlive( mpFrame ) ) 732 { 733 const NSTimeInterval fMagnifyTime = [pEvent timestamp]; 734 mpFrame->mnLastEventTime = static_cast<sal_uInt64>( fMagnifyTime * 1000.0 ); 735 mpFrame->mnLastModifierFlags = [pEvent modifierFlags]; 736 737 // check if this is a new series of magnify events 738 static const NSTimeInterval fMaxDiffTime = 0.3; 739 const bool bNewSeries = (fMagnifyTime - mfLastMagnifyTime > fMaxDiffTime); 740 741 if( bNewSeries ) 742 mfMagnifyDeltaSum = 0.0; 743 mfMagnifyDeltaSum += [pEvent magnification]; 744 745 mfLastMagnifyTime = [pEvent timestamp]; 746// TODO: change to 0.1 when CommandWheelMode::ZOOM handlers allow finer zooming control 747 static const float fMagnifyFactor = 0.25*500; // steps are 500 times smaller for -magnification 748 static const float fMinMagnifyStep = 15.0 / fMagnifyFactor; 749 if( fabs(mfMagnifyDeltaSum) <= fMinMagnifyStep ) 750 return; 751 752 // adapt NSEvent-sensitivity to application expectations 753 // TODO: rather make CommandWheelMode::ZOOM handlers smarter 754 const float fDeltaZ = mfMagnifyDeltaSum * fMagnifyFactor; 755 int nDeltaZ = FRound( fDeltaZ ); 756 if( !nDeltaZ ) 757 { 758 // handle new series immediately 759 if( !bNewSeries ) 760 return; 761 nDeltaZ = (fDeltaZ >= 0.0) ? +1 : -1; 762 } 763 // eventually give credit for delta sum 764 mfMagnifyDeltaSum -= nDeltaZ / fMagnifyFactor; 765 766 NSPoint aPt = [NSEvent mouseLocation]; 767 mpFrame->CocoaToVCL( aPt ); 768 769 SalWheelMouseEvent aEvent; 770 aEvent.mnTime = mpFrame->mnLastEventTime; 771 aEvent.mnX = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX; 772 aEvent.mnY = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY; 773 aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags ); 774 aEvent.mnCode |= KEY_MOD1; // we want zooming, no scrolling 775 aEvent.mbDeltaIsPixel = TRUE; 776 777 if( AllSettings::GetLayoutRTL() ) 778 aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX; 779 780 aEvent.mnDelta = nDeltaZ; 781 aEvent.mnNotchDelta = (nDeltaZ >= 0) ? +1 : -1; 782 if( aEvent.mnDelta == 0 ) 783 aEvent.mnDelta = aEvent.mnNotchDelta; 784 aEvent.mbHorz = FALSE; 785 sal_uInt32 nScrollLines = nDeltaZ; 786 if (nScrollLines == 0) 787 nScrollLines = 1; 788 aEvent.mnScrollLines = nScrollLines; 789 mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent ); 790 } 791} 792 793- (void)rotateWithEvent: (NSEvent*)pEvent 794{ 795 //Rotation : -(float)rotation; 796 // TODO: create new CommandType so rotation is available to the applications 797 (void)pEvent; 798} 799 800- (void)swipeWithEvent: (NSEvent*)pEvent 801{ 802 SolarMutexGuard aGuard; 803 804 if( AquaSalFrame::isAlive( mpFrame ) ) 805 { 806 mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 ); 807 mpFrame->mnLastModifierFlags = [pEvent modifierFlags]; 808 809 // merge pending scroll wheel events 810 CGFloat dX = 0.0; 811 CGFloat dY = 0.0; 812 for(;;) 813 { 814 dX += [pEvent deltaX]; 815 dY += [pEvent deltaY]; 816SAL_WNODEPRECATED_DECLARATIONS_PUSH 817 // 'NSScrollWheelMask' is deprecated: first deprecated in macOS 10.12 818 NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask 819SAL_WNODEPRECATED_DECLARATIONS_POP 820 untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ]; 821 if( !pNextEvent ) 822 break; 823 pEvent = pNextEvent; 824 } 825 826 NSPoint aPt = [NSEvent mouseLocation]; 827 mpFrame->CocoaToVCL( aPt ); 828 829 SalWheelMouseEvent aEvent; 830 aEvent.mnTime = mpFrame->mnLastEventTime; 831 aEvent.mnX = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX; 832 aEvent.mnY = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY; 833 aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags ); 834 aEvent.mbDeltaIsPixel = TRUE; 835 836 if( AllSettings::GetLayoutRTL() ) 837 aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX; 838 839 if( dX != 0.0 ) 840 { 841 aEvent.mnDelta = static_cast<long>(floor(dX)); 842 aEvent.mnNotchDelta = (dX < 0) ? -1 : +1; 843 if( aEvent.mnDelta == 0 ) 844 aEvent.mnDelta = aEvent.mnNotchDelta; 845 aEvent.mbHorz = TRUE; 846 aEvent.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL; 847 mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent ); 848 } 849 if( dY != 0.0 && AquaSalFrame::isAlive( mpFrame )) 850 { 851 aEvent.mnDelta = static_cast<long>(floor(dY)); 852 aEvent.mnNotchDelta = (dY < 0) ? -1 : +1; 853 if( aEvent.mnDelta == 0 ) 854 aEvent.mnDelta = aEvent.mnNotchDelta; 855 aEvent.mbHorz = FALSE; 856 aEvent.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL; 857 mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent ); 858 } 859 } 860} 861 862-(void)scrollWheel: (NSEvent*)pEvent 863{ 864 SolarMutexGuard aGuard; 865 866 if( AquaSalFrame::isAlive( mpFrame ) ) 867 { 868 mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 ); 869 mpFrame->mnLastModifierFlags = [pEvent modifierFlags]; 870 871 // merge pending scroll wheel events 872 CGFloat dX = 0.0; 873 CGFloat dY = 0.0; 874 for(;;) 875 { 876 dX += [pEvent deltaX]; 877 dY += [pEvent deltaY]; 878SAL_WNODEPRECATED_DECLARATIONS_PUSH 879 // 'NSScrollWheelMask' is deprecated: first deprecated in macOS 10.12 880 NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask 881SAL_WNODEPRECATED_DECLARATIONS_POP 882 untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ]; 883 if( !pNextEvent ) 884 break; 885 pEvent = pNextEvent; 886 } 887 888 NSPoint aPt = [NSEvent mouseLocation]; 889 mpFrame->CocoaToVCL( aPt ); 890 891 SalWheelMouseEvent aEvent; 892 aEvent.mnTime = mpFrame->mnLastEventTime; 893 aEvent.mnX = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX; 894 aEvent.mnY = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY; 895 aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags ); 896 aEvent.mbDeltaIsPixel = FALSE; 897 898 if( AllSettings::GetLayoutRTL() ) 899 aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX; 900 901 if( dX != 0.0 ) 902 { 903 aEvent.mnDelta = static_cast<long>(floor(dX)); 904 aEvent.mnNotchDelta = (dX < 0) ? -1 : +1; 905 if( aEvent.mnDelta == 0 ) 906 aEvent.mnDelta = aEvent.mnNotchDelta; 907 aEvent.mbHorz = TRUE; 908 sal_uInt32 nScrollLines = fabs(dX) / WHEEL_EVENT_FACTOR; 909 if (nScrollLines == 0) 910 nScrollLines = 1; 911 aEvent.mnScrollLines = nScrollLines; 912 913 mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent ); 914 } 915 if( dY != 0.0 && AquaSalFrame::isAlive( mpFrame ) ) 916 { 917 aEvent.mnDelta = static_cast<long>(floor(dY)); 918 aEvent.mnNotchDelta = (dY < 0) ? -1 : +1; 919 if( aEvent.mnDelta == 0 ) 920 aEvent.mnDelta = aEvent.mnNotchDelta; 921 aEvent.mbHorz = FALSE; 922 sal_uInt32 nScrollLines = fabs(dY) / WHEEL_EVENT_FACTOR; 923 if (nScrollLines == 0) 924 nScrollLines = 1; 925 aEvent.mnScrollLines = nScrollLines; 926 927 mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent ); 928 } 929 } 930} 931 932 933-(void)keyDown: (NSEvent*)pEvent 934{ 935 SolarMutexGuard aGuard; 936 937 if( AquaSalFrame::isAlive( mpFrame ) ) 938 { 939 mpLastEvent = pEvent; 940 mbInKeyInput = true; 941 mbNeedSpecialKeyHandle = false; 942 mbKeyHandled = false; 943 944 mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 ); 945 mpFrame->mnLastModifierFlags = [pEvent modifierFlags]; 946 947 if( ! [self handleKeyDownException: pEvent] ) 948 { 949 NSArray* pArray = [NSArray arrayWithObject: pEvent]; 950 [self interpretKeyEvents: pArray]; 951 } 952 953 mbInKeyInput = false; 954 } 955} 956 957-(BOOL)handleKeyDownException:(NSEvent*)pEvent 958{ 959 // check for a very special set of modified characters 960 NSString* pUnmodifiedString = [pEvent charactersIgnoringModifiers]; 961 962 if( pUnmodifiedString && [pUnmodifiedString length] == 1 ) 963 { 964 /* #i103102# key events with command and alternate don't make it through 965 interpretKeyEvents (why?). Try to dispatch them here first, 966 if not successful continue normally 967 */ 968SAL_WNODEPRECATED_DECLARATIONS_PUSH 969 // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12 970 // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12 971 if( (mpFrame->mnLastModifierFlags & (NSAlternateKeyMask | NSCommandKeyMask)) 972 == (NSAlternateKeyMask | NSCommandKeyMask) ) 973SAL_WNODEPRECATED_DECLARATIONS_POP 974 { 975 if( [self sendSingleCharacter: mpLastEvent] ) 976 return YES; 977 } 978 } 979 return NO; 980} 981 982-(void)flagsChanged: (NSEvent*)pEvent 983{ 984 SolarMutexGuard aGuard; 985 986 if( AquaSalFrame::isAlive( mpFrame ) ) 987 { 988 mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 ); 989 mpFrame->mnLastModifierFlags = [pEvent modifierFlags]; 990 } 991} 992 993-(void)insertText:(id)aString replacementRange:(NSRange)replacementRange 994{ 995 (void) replacementRange; // FIXME: surely it must be used 996 997 SolarMutexGuard aGuard; 998 999 if( AquaSalFrame::isAlive( mpFrame ) ) 1000 { 1001 NSString* pInsert = nil; 1002 if( [aString isMemberOfClass: [NSAttributedString class]] ) 1003 pInsert = [aString string]; 1004 else 1005 pInsert = aString; 1006 1007 int nLen = 0; 1008 if( pInsert && ( nLen = [pInsert length] ) > 0 ) 1009 { 1010 OUString aInsertString( GetOUString( pInsert ) ); 1011 // aCharCode initializer is safe since aInsertString will at least contain '\0' 1012 sal_Unicode aCharCode = *aInsertString.getStr(); 1013 1014 if( nLen == 1 && 1015 aCharCode < 0x80 && 1016 aCharCode > 0x1f && 1017 ! [self hasMarkedText ] 1018 ) 1019 { 1020 sal_uInt16 nKeyCode = ImplMapCharCode( aCharCode ); 1021 unsigned int nLastModifiers = mpFrame->mnLastModifierFlags; 1022 1023 // #i99567# 1024 // find out the unmodified key code 1025 1026SAL_WNODEPRECATED_DECLARATIONS_PUSH 1027 // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12 1028 // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12 1029 // 'NSControlKeyMask' is deprecated: first deprecated in macOS 10.12 1030 // 'NSKeyDown' is deprecated: first deprecated in macOS 10.12 1031 // 'NSKeyUp' is deprecated: first deprecated in macOS 10.12 1032 // sanity check 1033 if( mpLastEvent && ( [mpLastEvent type] == NSKeyDown || [mpLastEvent type] == NSKeyUp ) ) 1034 { 1035 // get unmodified string 1036 NSString* pUnmodifiedString = [mpLastEvent charactersIgnoringModifiers]; 1037 if( pUnmodifiedString && [pUnmodifiedString length] == 1 ) 1038 { 1039 // map the unmodified key code 1040 unichar keyChar = [pUnmodifiedString characterAtIndex: 0]; 1041 nKeyCode = ImplMapCharCode( keyChar ); 1042 } 1043 nLastModifiers = [mpLastEvent modifierFlags]; 1044 1045 } 1046 // #i99567# 1047 // applications and vcl's edit fields ignore key events with ALT 1048 // however we're at a place where we know text should be inserted 1049 // so it seems we need to strip the Alt modifier here 1050 if( (nLastModifiers & (NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask)) 1051 == NSAlternateKeyMask ) 1052 { 1053 nLastModifiers = 0; 1054 } 1055SAL_WNODEPRECATED_DECLARATIONS_POP 1056 [self sendKeyInputAndReleaseToFrame: nKeyCode character: aCharCode modifiers: nLastModifiers]; 1057 } 1058 else 1059 { 1060 SalExtTextInputEvent aEvent; 1061 aEvent.maText = aInsertString; 1062 aEvent.mpTextAttr = nullptr; 1063 aEvent.mnCursorPos = aInsertString.getLength(); 1064 aEvent.mnCursorFlags = 0; 1065 mpFrame->CallCallback( SalEvent::ExtTextInput, &aEvent ); 1066 if( AquaSalFrame::isAlive( mpFrame ) ) 1067 mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr ); 1068 } 1069 } 1070 else 1071 { 1072 SalExtTextInputEvent aEvent; 1073 aEvent.maText.clear(); 1074 aEvent.mpTextAttr = nullptr; 1075 aEvent.mnCursorPos = 0; 1076 aEvent.mnCursorFlags = 0; 1077 mpFrame->CallCallback( SalEvent::ExtTextInput, &aEvent ); 1078 if( AquaSalFrame::isAlive( mpFrame ) ) 1079 mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr ); 1080 1081 } 1082 mbKeyHandled = true; 1083 [self unmarkText]; 1084 } 1085} 1086 1087-(void)insertTab: (id)aSender 1088{ 1089 (void)aSender; 1090 [self sendKeyInputAndReleaseToFrame: KEY_TAB character: '\t' modifiers: 0]; 1091} 1092 1093-(void)insertBacktab: (id)aSender 1094{ 1095 (void)aSender; 1096 [self sendKeyInputAndReleaseToFrame: (KEY_TAB | KEY_SHIFT) character: '\t' modifiers: 0]; 1097} 1098 1099-(void)moveLeft: (id)aSender 1100{ 1101 (void)aSender; 1102 [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: 0]; 1103} 1104 1105-(void)moveLeftAndModifySelection: (id)aSender 1106{ 1107 (void)aSender; 1108SAL_WNODEPRECATED_DECLARATIONS_PUSH 1109 // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12 1110 [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: NSShiftKeyMask]; 1111SAL_WNODEPRECATED_DECLARATIONS_POP 1112} 1113 1114-(void)moveBackwardAndModifySelection: (id)aSender 1115{ 1116 (void)aSender; 1117 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_BACKWARD character: 0 modifiers: 0]; 1118} 1119 1120-(void)moveRight: (id)aSender 1121{ 1122 (void)aSender; 1123 [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: 0]; 1124} 1125 1126-(void)moveRightAndModifySelection: (id)aSender 1127{ 1128 (void)aSender; 1129SAL_WNODEPRECATED_DECLARATIONS_PUSH 1130 // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12 1131 [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: NSShiftKeyMask]; 1132SAL_WNODEPRECATED_DECLARATIONS_POP 1133} 1134 1135-(void)moveForwardAndModifySelection: (id)aSender 1136{ 1137 (void)aSender; 1138 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_FORWARD character: 0 modifiers: 0]; 1139} 1140 1141-(void)moveWordLeft: (id)aSender 1142{ 1143 (void)aSender; 1144 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_BACKWARD character: 0 modifiers: 0]; 1145} 1146 1147-(void)moveWordBackward: (id)aSender 1148{ 1149 (void)aSender; 1150 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_BACKWARD character: 0 modifiers: 0]; 1151} 1152 1153-(void)moveWordBackwardAndModifySelection: (id)aSender 1154{ 1155 (void)aSender; 1156 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_BACKWARD character: 0 modifiers: 0]; 1157} 1158 1159-(void)moveWordLeftAndModifySelection: (id)aSender 1160{ 1161 (void)aSender; 1162 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_BACKWARD character: 0 modifiers: 0]; 1163} 1164 1165-(void)moveWordRight: (id)aSender 1166{ 1167 (void)aSender; 1168 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_FORWARD character: 0 modifiers: 0]; 1169} 1170 1171-(void)moveWordForward: (id)aSender 1172{ 1173 (void)aSender; 1174 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_FORWARD character: 0 modifiers: 0]; 1175} 1176 1177-(void)moveWordForwardAndModifySelection: (id)aSender 1178{ 1179 (void)aSender; 1180 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_FORWARD character: 0 modifiers: 0]; 1181} 1182 1183-(void)moveWordRightAndModifySelection: (id)aSender 1184{ 1185 (void)aSender; 1186 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_FORWARD character: 0 modifiers: 0]; 1187} 1188 1189-(void)moveToEndOfLine: (id)aSender 1190{ 1191 (void)aSender; 1192 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_LINE character: 0 modifiers: 0]; 1193} 1194 1195-(void)moveToRightEndOfLine: (id)aSender 1196{ 1197 (void)aSender; 1198 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_LINE character: 0 modifiers: 0]; 1199} 1200 1201-(void)moveToEndOfLineAndModifySelection: (id)aSender 1202{ 1203 (void)aSender; 1204 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_LINE character: 0 modifiers: 0]; 1205} 1206 1207-(void)moveToRightEndOfLineAndModifySelection: (id)aSender 1208{ 1209 (void)aSender; 1210 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_LINE character: 0 modifiers: 0]; 1211} 1212 1213-(void)moveToBeginningOfLine: (id)aSender 1214{ 1215 (void)aSender; 1216 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0 modifiers: 0]; 1217} 1218 1219-(void)moveToLeftEndOfLine: (id)aSender 1220{ 1221 (void)aSender; 1222 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0 modifiers: 0]; 1223} 1224 1225-(void)moveToBeginningOfLineAndModifySelection: (id)aSender 1226{ 1227 (void)aSender; 1228 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0 modifiers: 0]; 1229} 1230 1231-(void)moveToLeftEndOfLineAndModifySelection: (id)aSender 1232{ 1233 (void)aSender; 1234 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0 modifiers: 0]; 1235} 1236 1237-(void)moveToEndOfParagraph: (id)aSender 1238{ 1239 (void)aSender; 1240 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0]; 1241} 1242 1243-(void)moveToEndOfParagraphAndModifySelection: (id)aSender 1244{ 1245 (void)aSender; 1246 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0 modifiers: 0]; 1247} 1248 1249-(void)moveParagraphForward: (id)aSender 1250{ 1251 (void)aSender; 1252 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0]; 1253} 1254 1255-(void)moveParagraphForwardAndModifySelection: (id)aSender 1256{ 1257 (void)aSender; 1258 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0 modifiers: 0]; 1259} 1260 1261-(void)moveToBeginningOfParagraph: (id)aSender 1262{ 1263 (void)aSender; 1264 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0]; 1265} 1266 1267-(void)moveParagraphBackward: (id)aSender 1268{ 1269 (void)aSender; 1270 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0]; 1271} 1272 1273-(void)moveToBeginningOfParagraphAndModifySelection: (id)aSender 1274{ 1275 (void)aSender; 1276 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0]; 1277} 1278 1279-(void)moveParagraphBackwardAndModifySelection: (id)aSender 1280{ 1281 (void)aSender; 1282 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0]; 1283} 1284 1285-(void)moveToEndOfDocument: (id)aSender 1286{ 1287 (void)aSender; 1288 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_DOCUMENT character: 0 modifiers: 0]; 1289} 1290 1291-(void)scrollToEndOfDocument: (id)aSender 1292{ 1293 (void)aSender; 1294 // this is not exactly what we should do, but it makes "End" and "Shift-End" behave consistent 1295 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_DOCUMENT character: 0 modifiers: 0]; 1296} 1297 1298-(void)moveToEndOfDocumentAndModifySelection: (id)aSender 1299{ 1300 (void)aSender; 1301 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_DOCUMENT character: 0 modifiers: 0]; 1302} 1303 1304-(void)moveToBeginningOfDocument: (id)aSender 1305{ 1306 (void)aSender; 1307 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0]; 1308} 1309 1310-(void)scrollToBeginningOfDocument: (id)aSender 1311{ 1312 (void)aSender; 1313 // this is not exactly what we should do, but it makes "Home" and "Shift-Home" behave consistent 1314 [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0]; 1315} 1316 1317-(void)moveToBeginningOfDocumentAndModifySelection: (id)aSender 1318{ 1319 (void)aSender; 1320 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0]; 1321} 1322 1323-(void)moveUp: (id)aSender 1324{ 1325 (void)aSender; 1326 [self sendKeyInputAndReleaseToFrame: KEY_UP character: 0 modifiers: 0]; 1327} 1328 1329-(void)moveDown: (id)aSender 1330{ 1331 (void)aSender; 1332 [self sendKeyInputAndReleaseToFrame: KEY_DOWN character: 0 modifiers: 0]; 1333} 1334 1335-(void)insertNewline: (id)aSender 1336{ 1337 (void)aSender; 1338 // #i91267# make enter and shift-enter work by evaluating the modifiers 1339 [self sendKeyInputAndReleaseToFrame: KEY_RETURN character: '\n' modifiers: mpFrame->mnLastModifierFlags]; 1340} 1341 1342-(void)deleteBackward: (id)aSender 1343{ 1344 (void)aSender; 1345 [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0]; 1346} 1347 1348-(void)deleteForward: (id)aSender 1349{ 1350 (void)aSender; 1351 [self sendKeyInputAndReleaseToFrame: KEY_DELETE character: 0x7f modifiers: 0]; 1352} 1353 1354-(void)deleteBackwardByDecomposingPreviousCharacter: (id)aSender 1355{ 1356 (void)aSender; 1357 [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0]; 1358} 1359 1360-(void)deleteWordBackward: (id)aSender 1361{ 1362 (void)aSender; 1363 [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_WORD_BACKWARD character: 0 modifiers: 0]; 1364} 1365 1366-(void)deleteWordForward: (id)aSender 1367{ 1368 (void)aSender; 1369 [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_WORD_FORWARD character: 0 modifiers: 0]; 1370} 1371 1372-(void)deleteToBeginningOfLine: (id)aSender 1373{ 1374 (void)aSender; 1375 [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_BEGIN_OF_LINE character: 0 modifiers: 0]; 1376} 1377 1378-(void)deleteToEndOfLine: (id)aSender 1379{ 1380 (void)aSender; 1381 [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_END_OF_LINE character: 0 modifiers: 0]; 1382} 1383 1384-(void)deleteToBeginningOfParagraph: (id)aSender 1385{ 1386 (void)aSender; 1387 [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0]; 1388} 1389 1390-(void)deleteToEndOfParagraph: (id)aSender 1391{ 1392 (void)aSender; 1393 [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0]; 1394} 1395 1396-(void)insertLineBreak: (id)aSender 1397{ 1398 (void)aSender; 1399 [self sendKeyInputAndReleaseToFrame: css::awt::Key::INSERT_LINEBREAK character: 0 modifiers: 0]; 1400} 1401 1402-(void)insertParagraphSeparator: (id)aSender 1403{ 1404 (void)aSender; 1405 [self sendKeyInputAndReleaseToFrame: css::awt::Key::INSERT_PARAGRAPH character: 0 modifiers: 0]; 1406} 1407 1408-(void)selectWord: (id)aSender 1409{ 1410 (void)aSender; 1411 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD character: 0 modifiers: 0]; 1412} 1413 1414-(void)selectLine: (id)aSender 1415{ 1416 (void)aSender; 1417 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_LINE character: 0 modifiers: 0]; 1418} 1419 1420-(void)selectParagraph: (id)aSender 1421{ 1422 (void)aSender; 1423 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_PARAGRAPH character: 0 modifiers: 0]; 1424} 1425 1426-(void)selectAll: (id)aSender 1427{ 1428 (void)aSender; 1429 [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_ALL character: 0 modifiers: 0]; 1430} 1431 1432-(void)cancelOperation: (id)aSender 1433{ 1434 (void)aSender; 1435 [self sendKeyInputAndReleaseToFrame: KEY_ESCAPE character: 0x1b modifiers: 0]; 1436} 1437 1438-(void)noop: (id)aSender 1439{ 1440 (void)aSender; 1441 if( ! mbKeyHandled ) 1442 { 1443 if( ! [self sendSingleCharacter:mpLastEvent] ) 1444 { 1445 /* prevent recursion */ 1446 if( mpLastEvent != mpLastSuperEvent && [NSApp respondsToSelector: @selector(sendSuperEvent:)] ) 1447 { 1448 id pLastSuperEvent = mpLastSuperEvent; 1449 mpLastSuperEvent = mpLastEvent; 1450 [NSApp performSelector:@selector(sendSuperEvent:) withObject: mpLastEvent]; 1451 mpLastSuperEvent = pLastSuperEvent; 1452 1453 std::map< NSEvent*, bool >::iterator it = GetSalData()->maKeyEventAnswer.find( mpLastEvent ); 1454 if( it != GetSalData()->maKeyEventAnswer.end() ) 1455 it->second = true; 1456 } 1457 } 1458 } 1459} 1460 1461-(BOOL)sendKeyInputAndReleaseToFrame: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar 1462{ 1463 return [self sendKeyInputAndReleaseToFrame: nKeyCode character: aChar modifiers: mpFrame->mnLastModifierFlags]; 1464} 1465 1466-(BOOL)sendKeyInputAndReleaseToFrame: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod 1467{ 1468 return [self sendKeyToFrameDirect: nKeyCode character: aChar modifiers: nMod] || 1469 [self sendSingleCharacter: mpLastEvent]; 1470} 1471 1472-(BOOL)sendKeyToFrameDirect: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod 1473{ 1474 SolarMutexGuard aGuard; 1475 1476 bool nRet = false; 1477 if( AquaSalFrame::isAlive( mpFrame ) ) 1478 { 1479 SalKeyEvent aEvent; 1480 aEvent.mnCode = nKeyCode | ImplGetModifierMask( nMod ); 1481 aEvent.mnCharCode = aChar; 1482 aEvent.mnRepeat = FALSE; 1483 nRet = mpFrame->CallCallback( SalEvent::KeyInput, &aEvent ); 1484 std::map< NSEvent*, bool >::iterator it = GetSalData()->maKeyEventAnswer.find( mpLastEvent ); 1485 if( it != GetSalData()->maKeyEventAnswer.end() ) 1486 it->second = nRet; 1487 if( AquaSalFrame::isAlive( mpFrame ) ) 1488 mpFrame->CallCallback( SalEvent::KeyUp, &aEvent ); 1489 } 1490 return nRet; 1491} 1492 1493 1494-(BOOL)sendSingleCharacter: (NSEvent *)pEvent 1495{ 1496 NSString* pUnmodifiedString = [pEvent charactersIgnoringModifiers]; 1497 1498 if( pUnmodifiedString && [pUnmodifiedString length] == 1 ) 1499 { 1500 unichar keyChar = [pUnmodifiedString characterAtIndex: 0]; 1501 sal_uInt16 nKeyCode = ImplMapCharCode( keyChar ); 1502 if (nKeyCode == 0) 1503 { 1504 sal_uInt16 nOtherKeyCode = [pEvent keyCode]; 1505 nKeyCode = ImplMapKeyCode(nOtherKeyCode); 1506 } 1507 if( nKeyCode != 0 ) 1508 { 1509 // don't send code points in the private use area 1510 if( keyChar >= 0xf700 && keyChar < 0xf780 ) 1511 keyChar = 0; 1512 BOOL bRet = [self sendKeyToFrameDirect: nKeyCode character: keyChar modifiers: mpFrame->mnLastModifierFlags]; 1513 mbInKeyInput = false; 1514 1515 return bRet; 1516 } 1517 } 1518 return NO; 1519} 1520 1521 1522// NSTextInput/NSTextInputClient protocol 1523- (NSArray *)validAttributesForMarkedText 1524{ 1525 return [NSArray arrayWithObjects:NSUnderlineStyleAttributeName, nil]; 1526} 1527 1528- (BOOL)hasMarkedText 1529{ 1530 BOOL bHasMarkedText; 1531 1532 bHasMarkedText = ( mMarkedRange.location != NSNotFound ) && 1533 ( mMarkedRange.length != 0 ); 1534 // hack to check keys like "Control-j" 1535 if( mbInKeyInput ) 1536 { 1537 mbNeedSpecialKeyHandle = true; 1538 } 1539 1540 // FIXME: 1541 // #i106901# 1542 // if we come here outside of mbInKeyInput, this is likely to be because 1543 // of the keyboard viewer. For unknown reasons having no marked range 1544 // in this case causes a crash. So we say we have a marked range anyway 1545 // This is a hack, since it is not understood what a) causes that crash 1546 // and b) why we should have a marked range at this point. 1547 if( ! mbInKeyInput ) 1548 bHasMarkedText = YES; 1549 1550 return bHasMarkedText; 1551} 1552 1553- (NSRange)markedRange 1554{ 1555 // FIXME: 1556 // #i106901# 1557 // if we come here outside of mbInKeyInput, this is likely to be because 1558 // of the keyboard viewer. For unknown reasons having no marked range 1559 // in this case causes a crash. So we say we have a marked range anyway 1560 // This is a hack, since it is not understood what a) causes that crash 1561 // and b) why we should have a marked range at this point. 1562 if( ! mbInKeyInput ) 1563 return NSMakeRange( 0, 0 ); 1564 1565 return [self hasMarkedText] ? mMarkedRange : NSMakeRange( NSNotFound, 0 ); 1566} 1567 1568- (NSRange)selectedRange 1569{ 1570 return mSelectedRange; 1571} 1572 1573- (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange replacementRange:(NSRange)replacementRange 1574{ 1575 (void) replacementRange; // FIXME - use it! 1576 1577 SolarMutexGuard aGuard; 1578 1579 if( ![aString isKindOfClass:[NSAttributedString class]] ) 1580 aString = [[[NSAttributedString alloc] initWithString:aString] autorelease]; 1581 NSRange rangeToReplace = [self hasMarkedText] ? [self markedRange] : [self selectedRange]; 1582 if( rangeToReplace.location == NSNotFound ) 1583 { 1584 mMarkedRange = NSMakeRange( selRange.location, [aString length] ); 1585 mSelectedRange = NSMakeRange( selRange.location, selRange.length ); 1586 } 1587 else 1588 { 1589 mMarkedRange = NSMakeRange( rangeToReplace.location, [aString length] ); 1590 mSelectedRange = NSMakeRange( rangeToReplace.location + selRange.location, selRange.length ); 1591 } 1592 1593 int len = [aString length]; 1594 SalExtTextInputEvent aInputEvent; 1595 if( len > 0 ) { 1596 NSString *pString = [aString string]; 1597 OUString aInsertString( GetOUString( pString ) ); 1598 std::vector<ExtTextInputAttr> aInputFlags( std::max( 1, len ), ExtTextInputAttr::NONE ); 1599 for ( int i = 0; i < len; i++ ) 1600 { 1601 unsigned int nUnderlineValue; 1602 NSRange effectiveRange; 1603 1604 effectiveRange = NSMakeRange(i, 1); 1605 nUnderlineValue = [[aString attribute:NSUnderlineStyleAttributeName atIndex:i effectiveRange:&effectiveRange] unsignedIntValue]; 1606 1607 switch (nUnderlineValue & 0xff) { 1608 case NSUnderlineStyleSingle: 1609 aInputFlags[i] = ExtTextInputAttr::Underline; 1610 break; 1611 case NSUnderlineStyleThick: 1612 aInputFlags[i] = ExtTextInputAttr::Underline | ExtTextInputAttr::Highlight; 1613 break; 1614 case NSUnderlineStyleDouble: 1615 aInputFlags[i] = ExtTextInputAttr::BoldUnderline; 1616 break; 1617 default: 1618 aInputFlags[i] = ExtTextInputAttr::Highlight; 1619 break; 1620 } 1621 } 1622 1623 aInputEvent.maText = aInsertString; 1624 aInputEvent.mnCursorPos = selRange.location; 1625 aInputEvent.mpTextAttr = aInputFlags.data(); 1626 mpFrame->CallCallback( SalEvent::ExtTextInput, static_cast<void *>(&aInputEvent) ); 1627 } else { 1628 aInputEvent.maText.clear(); 1629 aInputEvent.mnCursorPos = 0; 1630 aInputEvent.mnCursorFlags = 0; 1631 aInputEvent.mpTextAttr = nullptr; 1632 mpFrame->CallCallback( SalEvent::ExtTextInput, static_cast<void *>(&aInputEvent) ); 1633 mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr ); 1634 } 1635 mbKeyHandled= true; 1636} 1637 1638- (void)unmarkText 1639{ 1640 mSelectedRange = mMarkedRange = NSMakeRange(NSNotFound, 0); 1641} 1642 1643- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange 1644{ 1645 (void) aRange; 1646 (void) actualRange; 1647 1648 // FIXME - Implement 1649 return nil; 1650} 1651 1652- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint 1653{ 1654 (void)thePoint; 1655 // FIXME 1656 return 0; 1657} 1658 1659- (NSInteger)conversationIdentifier 1660{ 1661 return reinterpret_cast<long>(self); 1662} 1663 1664- (void)doCommandBySelector:(SEL)aSelector 1665{ 1666 if( AquaSalFrame::isAlive( mpFrame ) ) 1667 { 1668 if( (mpFrame->mnICOptions & InputContextFlags::Text) && 1669 aSelector != nullptr && [self respondsToSelector: aSelector] ) 1670 { 1671 [self performSelector: aSelector]; 1672 } 1673 else 1674 { 1675 [self sendSingleCharacter:mpLastEvent]; 1676 } 1677 } 1678 1679 mbKeyHandled = true; 1680} 1681 1682-(void)clearLastEvent 1683{ 1684 mpLastEvent = nil; 1685} 1686 1687- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange 1688{ 1689 // FIXME - These should probably be used? 1690 (void) aRange; 1691 (void) actualRange; 1692 1693 SolarMutexGuard aGuard; 1694 1695 SalExtTextInputPosEvent aPosEvent; 1696 mpFrame->CallCallback( SalEvent::ExtTextInputPos, static_cast<void *>(&aPosEvent) ); 1697 1698 NSRect rect; 1699 1700 rect.origin.x = aPosEvent.mnX + mpFrame->maGeometry.nX; 1701 rect.origin.y = aPosEvent.mnY + mpFrame->maGeometry.nY + 4; // add some space for underlines 1702 rect.size.width = aPosEvent.mnWidth; 1703 rect.size.height = aPosEvent.mnHeight; 1704 1705 mpFrame->VCLToCocoa( rect ); 1706 return rect; 1707} 1708 1709-(id)parentAttribute { 1710 return reinterpret_cast<NSView*>(mpFrame->getNSWindow()); 1711 //TODO: odd cast really needed for fdo#74121? 1712} 1713 1714-(css::accessibility::XAccessibleContext *)accessibleContext 1715{ 1716 if ( !mpReferenceWrapper ) { 1717 // some frames never become visible .. 1718 vcl::Window *pWindow = mpFrame -> GetWindow(); 1719 if ( ! pWindow ) 1720 return nil; 1721 1722 mpReferenceWrapper = new ReferenceWrapper; 1723 mpReferenceWrapper -> rAccessibleContext = pWindow -> /*GetAccessibleChildWindow( 0 ) ->*/ GetAccessible() -> getAccessibleContext(); 1724 [ AquaA11yFactory insertIntoWrapperRepository: self forAccessibleContext: mpReferenceWrapper -> rAccessibleContext ]; 1725 } 1726 return [ super accessibleContext ]; 1727} 1728 1729-(NSWindow*)windowForParent 1730{ 1731 return mpFrame->getNSWindow(); 1732} 1733 1734-(void)registerMouseEventListener: (id)theListener 1735{ 1736 mpMouseEventListener = theListener; 1737} 1738 1739-(void)unregisterMouseEventListener: (id)theListener 1740{ 1741 (void)theListener; 1742 mpMouseEventListener = nil; 1743} 1744 1745-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender 1746{ 1747 return [mDraggingDestinationHandler draggingEntered: sender]; 1748} 1749 1750-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender 1751{ 1752 return [mDraggingDestinationHandler draggingUpdated: sender]; 1753} 1754 1755-(void)draggingExited:(id <NSDraggingInfo>)sender 1756{ 1757 [mDraggingDestinationHandler draggingExited: sender]; 1758} 1759 1760-(BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender 1761{ 1762 return [mDraggingDestinationHandler prepareForDragOperation: sender]; 1763} 1764 1765-(BOOL)performDragOperation:(id <NSDraggingInfo>)sender 1766{ 1767 return [mDraggingDestinationHandler performDragOperation: sender]; 1768} 1769 1770-(void)concludeDragOperation:(id <NSDraggingInfo>)sender 1771{ 1772 [mDraggingDestinationHandler concludeDragOperation: sender]; 1773} 1774 1775-(void)registerDraggingDestinationHandler:(id)theHandler 1776{ 1777 mDraggingDestinationHandler = theHandler; 1778} 1779 1780-(void)unregisterDraggingDestinationHandler:(id)theHandler 1781{ 1782 (void)theHandler; 1783 mDraggingDestinationHandler = nil; 1784} 1785 1786@end 1787 1788/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 1789