1/* 2 * Copyright (C) 2010 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#import "config.h" 27#import "WKTextInputWindowController.h" 28 29#if USE(APPKIT) 30 31#import <WebKitSystemInterface.h> 32 33@interface WKTextInputView : NSTextView { 34} 35@end 36 37@implementation WKTextInputView 38 39- (NSArray *)validAttributesForMarkedText 40{ 41 // Let TSM know that a bottom input window would be created for marked text. 42 NSArray *regularAttributes = [super validAttributesForMarkedText]; 43 NSMutableArray *floatingWindowAttributes = [NSMutableArray arrayWithArray:regularAttributes]; 44 [floatingWindowAttributes addObject:@"__NSUsesFloatingInputWindow"]; 45 return floatingWindowAttributes; 46} 47 48@end 49 50@interface WKTextInputPanel : NSPanel { 51 NSTextView *_inputTextView; 52} 53 54- (NSTextInputContext *)_inputContext; 55- (BOOL)_interpretKeyEvent:(NSEvent *)event usingLegacyCocoaTextInput:(BOOL)usingLegacyCocoaTextInput string:(NSString **)string; 56 57- (BOOL)_hasMarkedText; 58- (void)_unmarkText; 59 60@end 61 62#define inputWindowHeight 20 63 64@implementation WKTextInputPanel 65 66- (void)dealloc 67{ 68 [[NSNotificationCenter defaultCenter] removeObserver:self]; 69 70 [_inputTextView release]; 71 72 [super dealloc]; 73} 74 75- (id)init 76{ 77 self = [super initWithContentRect:NSZeroRect styleMask:WKGetInputPanelWindowStyle() backing:NSBackingStoreBuffered defer:YES]; 78 if (!self) 79 return nil; 80 81 // Set the frame size. 82 NSRect visibleFrame = [[NSScreen mainScreen] visibleFrame]; 83 NSRect frame = NSMakeRect(visibleFrame.origin.x, visibleFrame.origin.y, visibleFrame.size.width, inputWindowHeight); 84 85 [self setFrame:frame display:NO]; 86 87 _inputTextView = [[WKTextInputView alloc] initWithFrame:[(NSView *)self.contentView frame]]; 88 _inputTextView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable | NSViewMaxXMargin | NSViewMinXMargin | NSViewMaxYMargin | NSViewMinYMargin; 89 90 NSScrollView* scrollView = [[NSScrollView alloc] initWithFrame:[(NSView *)self.contentView frame]]; 91 scrollView.documentView = _inputTextView; 92 self.contentView = scrollView; 93 [scrollView release]; 94 95 [self setFloatingPanel:YES]; 96 97 return self; 98} 99 100- (void)_unmarkText 101{ 102 [_inputTextView setString:@""]; 103 [self orderOut:nil]; 104} 105 106- (BOOL)_interpretKeyEvent:(NSEvent *)event usingLegacyCocoaTextInput:(BOOL)usingLegacyCocoaTextInput string:(NSString **)string 107{ 108#pragma clang diagnostic push 109#pragma clang diagnostic ignored "-Wdeprecated-declarations" 110 BOOL hadMarkedText = [_inputTextView hasMarkedText]; 111#pragma clang diagnostic pop 112 113 *string = nil; 114 115 // Let TSM know that a bottom input window would be created for marked text. 116 // FIXME: Can be removed once we can rely on __NSUsesFloatingInputWindow (or a better API) being available everywhere. 117 EventRef carbonEvent = static_cast<EventRef>(const_cast<void*>([event eventRef])); 118 if (carbonEvent) { 119 Boolean ignorePAH = true; 120 SetEventParameter(carbonEvent, 'iPAH', typeBoolean, sizeof(ignorePAH), &ignorePAH); 121 } 122 123 if (![[_inputTextView inputContext] handleEvent:event]) 124 return NO; 125 126#pragma clang diagnostic push 127#pragma clang diagnostic ignored "-Wdeprecated-declarations" 128 if ([_inputTextView hasMarkedText]) { 129#pragma clang diagnostic pop 130 // Don't show the input method window for dead keys 131 if ([[event characters] length] > 0) 132 [self orderFront:nil]; 133 134 return YES; 135 } 136 137 bool shouldReturnTextString = hadMarkedText; 138 139 // In the updated Cocoa text input model spec, we always want to return the text even if the text view didn't have marked text. 140 if (!usingLegacyCocoaTextInput) 141 shouldReturnTextString = true; 142 143 if (shouldReturnTextString) { 144 [[_inputTextView inputContext] discardMarkedText]; // Don't show Cangjie predictive candidates, cf. <rdar://14458297>. 145 [self orderOut:nil]; 146 147 NSString *text = [[_inputTextView textStorage] string]; 148 if ([text length] > 0) 149 *string = [[text copy] autorelease]; 150 } 151 152 [_inputTextView setString:@""]; 153 return hadMarkedText; 154} 155 156- (NSTextInputContext *)_inputContext 157{ 158 return [_inputTextView inputContext]; 159} 160 161- (BOOL)_hasMarkedText 162{ 163#pragma clang diagnostic push 164#pragma clang diagnostic ignored "-Wdeprecated-declarations" 165 return [_inputTextView hasMarkedText]; 166#pragma clang diagnostic pop 167} 168 169@end 170 171@implementation WKTextInputWindowController 172 173+ (WKTextInputWindowController *)sharedTextInputWindowController 174{ 175 static WKTextInputWindowController *textInputWindowController; 176 if (!textInputWindowController) 177 textInputWindowController = [[WKTextInputWindowController alloc] init]; 178 179 return textInputWindowController; 180} 181 182- (id)init 183{ 184 self = [super init]; 185 if (!self) 186 return nil; 187 188 _panel = [[WKTextInputPanel alloc] init]; 189 190 return self; 191} 192 193- (NSTextInputContext *)inputContext 194{ 195 return [_panel _inputContext]; 196} 197 198- (BOOL)hasMarkedText 199{ 200 return [_panel _hasMarkedText]; 201} 202 203- (BOOL)interpretKeyEvent:(NSEvent *)event usingLegacyCocoaTextInput:(BOOL)usingLegacyCocoaTextInput string:(NSString **)string 204{ 205 return [_panel _interpretKeyEvent:event usingLegacyCocoaTextInput:usingLegacyCocoaTextInput string:string]; 206} 207 208- (void)unmarkText 209{ 210 [_panel _unmarkText]; 211} 212 213@end 214 215#endif // USE(APPKIT) 216