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