Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "ui/views/cocoa/bridged_content_view.h" | 5 #import "ui/views/cocoa/bridged_content_view.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #import "base/mac/scoped_nsobject.h" | 8 #import "base/mac/scoped_nsobject.h" |
| 9 #include "base/strings/sys_string_conversions.h" | 9 #include "base/strings/sys_string_conversions.h" |
| 10 #include "ui/base/ime/text_input_client.h" | 10 #include "ui/base/ime/text_input_client.h" |
| 11 #import "ui/events/cocoa/cocoa_event_utils.h" | |
| 12 #include "ui/events/keycodes/dom3/dom_code.h" | |
| 13 #import "ui/events/keycodes/keyboard_code_conversion_mac.h" | |
| 11 #include "ui/gfx/canvas_paint_mac.h" | 14 #include "ui/gfx/canvas_paint_mac.h" |
| 12 #include "ui/gfx/geometry/rect.h" | 15 #include "ui/gfx/geometry/rect.h" |
| 13 #include "ui/strings/grit/ui_strings.h" | 16 #include "ui/strings/grit/ui_strings.h" |
| 17 #include "ui/views/controls/menu/menu_controller.h" | |
| 14 #include "ui/views/view.h" | 18 #include "ui/views/view.h" |
| 15 #include "ui/views/widget/widget.h" | 19 #include "ui/views/widget/widget.h" |
| 16 | 20 |
| 21 using views::MenuController; | |
| 22 | |
| 17 namespace { | 23 namespace { |
| 18 | 24 |
| 19 // Convert a |point| in |source_window|'s AppKit coordinate system (origin at | 25 // Convert a |point| in |source_window|'s AppKit coordinate system (origin at |
| 20 // the bottom left of the window) to |target_window|'s content rect, with the | 26 // the bottom left of the window) to |target_window|'s content rect, with the |
| 21 // origin at the top left of the content area. | 27 // origin at the top left of the content area. |
| 22 // If |source_window| is nil, |point| will be treated as screen coordinates. | 28 // If |source_window| is nil, |point| will be treated as screen coordinates. |
| 23 gfx::Point MovePointToWindow(const NSPoint& point, | 29 gfx::Point MovePointToWindow(const NSPoint& point, |
| 24 NSWindow* source_window, | 30 NSWindow* source_window, |
| 25 NSWindow* target_window) { | 31 NSWindow* target_window) { |
| 26 NSPoint point_in_screen = source_window | 32 NSPoint point_in_screen = source_window |
| 27 ? [source_window convertBaseToScreen:point] | 33 ? [source_window convertBaseToScreen:point] |
| 28 : point; | 34 : point; |
| 29 | 35 |
| 30 NSPoint point_in_window = [target_window convertScreenToBase:point_in_screen]; | 36 NSPoint point_in_window = [target_window convertScreenToBase:point_in_screen]; |
| 31 NSRect content_rect = | 37 NSRect content_rect = |
| 32 [target_window contentRectForFrameRect:[target_window frame]]; | 38 [target_window contentRectForFrameRect:[target_window frame]]; |
| 33 return gfx::Point(point_in_window.x, | 39 return gfx::Point(point_in_window.x, |
| 34 NSHeight(content_rect) - point_in_window.y); | 40 NSHeight(content_rect) - point_in_window.y); |
| 35 } | 41 } |
| 36 | 42 |
| 37 } | 43 } |
| 38 | 44 |
| 39 @interface BridgedContentView () | 45 @interface BridgedContentView () |
| 40 | 46 |
| 41 // Translates the location of |theEvent| to toolkit-views coordinates and passes | 47 // Translates the location of |theEvent| to toolkit-views coordinates and passes |
| 42 // the event to NativeWidgetMac for handling. | 48 // the event to NativeWidgetMac for handling. |
| 43 - (void)handleMouseEvent:(NSEvent*)theEvent; | 49 - (void)handleMouseEvent:(NSEvent*)theEvent; |
| 44 | 50 |
| 51 // Handles an NSResponder Action Message by mapping it to the keyCode that | |
| 52 // toolkit-views expects internally. E.g. moveToBeginningOfLine: would pass | |
| 53 // ui::VKEY_HOME even though the Home key on Mac defaults to | |
| 54 // moveToBeginningOfDocument:. This approach also allows action messages a user | |
| 55 // may have remapped in ~/Library/KeyBindings/DefaultKeyBinding.dict to be | |
| 56 // catered for. | |
| 57 - (void)handleActionAsKey:(ui::KeyboardCode)keyCode | |
| 58 domCode:(ui::DomCode)domCode; | |
| 59 | |
| 45 // Execute a command on the currently focused TextInputClient. | 60 // Execute a command on the currently focused TextInputClient. |
| 46 // |commandId| should be a resource ID from ui_strings.grd. | 61 // |commandId| should be a resource ID from ui_strings.grd. |
| 47 - (void)doCommandByID:(int)commandId; | 62 - (void)doCommandByID:(int)commandId; |
| 48 | 63 |
| 49 @end | 64 @end |
| 50 | 65 |
| 51 @implementation BridgedContentView | 66 @implementation BridgedContentView |
| 52 | 67 |
| 53 @synthesize hostedView = hostedView_; | 68 @synthesize hostedView = hostedView_; |
| 54 @synthesize textInputClient = textInputClient_; | 69 @synthesize textInputClient = textInputClient_; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 104 // BridgedContentView private implementation. | 119 // BridgedContentView private implementation. |
| 105 | 120 |
| 106 - (void)handleMouseEvent:(NSEvent*)theEvent { | 121 - (void)handleMouseEvent:(NSEvent*)theEvent { |
| 107 if (!hostedView_) | 122 if (!hostedView_) |
| 108 return; | 123 return; |
| 109 | 124 |
| 110 ui::MouseEvent event(theEvent); | 125 ui::MouseEvent event(theEvent); |
| 111 hostedView_->GetWidget()->OnMouseEvent(&event); | 126 hostedView_->GetWidget()->OnMouseEvent(&event); |
| 112 } | 127 } |
| 113 | 128 |
| 129 - (void)handleActionAsKey:(ui::KeyboardCode)keyCode | |
| 130 domCode:(ui::DomCode)domCode { | |
| 131 if (!hostedView_) | |
| 132 return; | |
| 133 | |
| 134 ui::KeyEvent event(ui::ET_KEY_PRESSED, keyCode, domCode, | |
| 135 ui::EventFlagsFromModifiers([NSEvent modifierFlags])); | |
| 136 | |
| 137 MenuController* menuController = MenuController::GetActiveInstance(); | |
| 138 if (menuController && | |
| 139 menuController->owner() == hostedView_->GetWidget() && | |
| 140 menuController->OnWillDispatchEvent(event) == ui::POST_DISPATCH_NONE) | |
| 141 return; | |
| 142 | |
| 143 hostedView_->GetWidget()->OnKeyEvent(&event); | |
| 144 } | |
| 145 | |
| 114 - (void)doCommandByID:(int)commandId { | 146 - (void)doCommandByID:(int)commandId { |
| 115 if (textInputClient_ && textInputClient_->IsEditingCommandEnabled(commandId)) | 147 if (textInputClient_ && textInputClient_->IsEditingCommandEnabled(commandId)) |
| 116 textInputClient_->ExecuteEditingCommand(commandId); | 148 textInputClient_->ExecuteEditingCommand(commandId); |
| 117 } | 149 } |
| 118 | 150 |
| 119 // NSView implementation. | 151 // NSView implementation. |
| 120 | 152 |
| 121 - (BOOL)acceptsFirstResponder { | 153 - (BOOL)acceptsFirstResponder { |
| 122 return YES; | 154 return YES; |
| 123 } | 155 } |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 140 if (hostedView_->GetWidget()->GetLayer()) | 172 if (hostedView_->GetWidget()->GetLayer()) |
| 141 return; | 173 return; |
| 142 | 174 |
| 143 gfx::CanvasSkiaPaint canvas(dirtyRect, false /* opaque */); | 175 gfx::CanvasSkiaPaint canvas(dirtyRect, false /* opaque */); |
| 144 hostedView_->GetWidget()->OnNativeWidgetPaint(&canvas); | 176 hostedView_->GetWidget()->OnNativeWidgetPaint(&canvas); |
| 145 } | 177 } |
| 146 | 178 |
| 147 // NSResponder implementation. | 179 // NSResponder implementation. |
| 148 | 180 |
| 149 - (void)keyDown:(NSEvent*)theEvent { | 181 - (void)keyDown:(NSEvent*)theEvent { |
| 150 if (textInputClient_) | 182 [self interpretKeyEvents:@[ theEvent ]]; |
|
Andre
2014/12/19 06:41:57
How about when BridgedContentView is not first res
tapted
2015/01/28 11:18:06
So this was an excellent point :)
it crossed my m
| |
| 151 [self interpretKeyEvents:@[ theEvent ]]; | |
| 152 else | |
| 153 [super keyDown:theEvent]; | |
| 154 } | 183 } |
| 155 | 184 |
| 156 - (void)mouseDown:(NSEvent*)theEvent { | 185 - (void)mouseDown:(NSEvent*)theEvent { |
| 157 [self handleMouseEvent:theEvent]; | 186 [self handleMouseEvent:theEvent]; |
| 158 } | 187 } |
| 159 | 188 |
| 160 - (void)rightMouseDown:(NSEvent*)theEvent { | 189 - (void)rightMouseDown:(NSEvent*)theEvent { |
| 161 [self handleMouseEvent:theEvent]; | 190 [self handleMouseEvent:theEvent]; |
| 162 } | 191 } |
| 163 | 192 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 214 | 243 |
| 215 - (void)moveLeft:(id)sender { | 244 - (void)moveLeft:(id)sender { |
| 216 [self doCommandByID:IDS_MOVE_LEFT]; | 245 [self doCommandByID:IDS_MOVE_LEFT]; |
| 217 } | 246 } |
| 218 | 247 |
| 219 - (void)moveRight:(id)sender { | 248 - (void)moveRight:(id)sender { |
| 220 [self doCommandByID:IDS_MOVE_RIGHT]; | 249 [self doCommandByID:IDS_MOVE_RIGHT]; |
| 221 } | 250 } |
| 222 | 251 |
| 223 - (void)insertText:(id)text { | 252 - (void)insertText:(id)text { |
| 224 if (textInputClient_) | 253 [self insertText:text replacementRange:NSMakeRange(NSNotFound, 0)]; |
| 225 textInputClient_->InsertText(base::SysNSStringToUTF16(text)); | 254 } |
| 255 | |
| 256 - (void)moveUp:(id)sender { | |
| 257 [self handleActionAsKey:ui::VKEY_UP domCode:ui::DomCode::ARROW_UP]; | |
| 258 } | |
| 259 | |
| 260 - (void)moveDown:(id)sender { | |
| 261 [self handleActionAsKey:ui::VKEY_DOWN domCode:ui::DomCode::ARROW_DOWN]; | |
| 262 } | |
| 263 | |
| 264 - (void)cancelOperation:(id)sender { | |
| 265 [self handleActionAsKey:ui::VKEY_ESCAPE domCode:ui::DomCode::ESCAPE]; | |
| 226 } | 266 } |
| 227 | 267 |
| 228 // Support for Services in context menus. | 268 // Support for Services in context menus. |
| 229 // Currently we only support reading and writing plain strings. | 269 // Currently we only support reading and writing plain strings. |
| 230 - (id)validRequestorForSendType:(NSString*)sendType | 270 - (id)validRequestorForSendType:(NSString*)sendType |
| 231 returnType:(NSString*)returnType { | 271 returnType:(NSString*)returnType { |
| 232 BOOL canWrite = [sendType isEqualToString:NSStringPboardType] && | 272 BOOL canWrite = [sendType isEqualToString:NSStringPboardType] && |
| 233 [self selectedRange].length > 0; | 273 [self selectedRange].length > 0; |
| 234 BOOL canRead = [returnType isEqualToString:NSStringPboardType]; | 274 BOOL canRead = [returnType isEqualToString:NSStringPboardType]; |
| 235 // Valid if (sendType, returnType) is either (string, nil), (nil, string), | 275 // Valid if (sendType, returnType) is either (string, nil), (nil, string), |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 281 return [[[NSAttributedString alloc] | 321 return [[[NSAttributedString alloc] |
| 282 initWithString:base::SysUTF16ToNSString(substring)] autorelease]; | 322 initWithString:base::SysUTF16ToNSString(substring)] autorelease]; |
| 283 } | 323 } |
| 284 | 324 |
| 285 - (NSUInteger)characterIndexForPoint:(NSPoint)aPoint { | 325 - (NSUInteger)characterIndexForPoint:(NSPoint)aPoint { |
| 286 NOTIMPLEMENTED(); | 326 NOTIMPLEMENTED(); |
| 287 return 0; | 327 return 0; |
| 288 } | 328 } |
| 289 | 329 |
| 290 - (void)doCommandBySelector:(SEL)selector { | 330 - (void)doCommandBySelector:(SEL)selector { |
| 291 if ([self respondsToSelector:selector]) | 331 if ([self respondsToSelector:selector]) { |
| 292 [self performSelector:selector withObject:nil]; | 332 [self performSelector:selector withObject:nil]; |
| 293 else | 333 } else { |
| 334 NSLog(@"Unmatched selector: %@\n", NSStringFromSelector(selector)); | |
| 294 [[self nextResponder] doCommandBySelector:selector]; | 335 [[self nextResponder] doCommandBySelector:selector]; |
| 336 } | |
| 295 } | 337 } |
| 296 | 338 |
| 297 - (NSRect)firstRectForCharacterRange:(NSRange)range | 339 - (NSRect)firstRectForCharacterRange:(NSRange)range |
| 298 actualRange:(NSRangePointer)actualRange { | 340 actualRange:(NSRangePointer)actualRange { |
| 299 NOTIMPLEMENTED(); | 341 NOTIMPLEMENTED(); |
| 300 return NSZeroRect; | 342 return NSZeroRect; |
| 301 } | 343 } |
| 302 | 344 |
| 303 - (BOOL)hasMarkedText { | 345 - (BOOL)hasMarkedText { |
| 304 return textInputClient_ && textInputClient_->HasCompositionText(); | 346 return textInputClient_ && textInputClient_->HasCompositionText(); |
| 305 } | 347 } |
| 306 | 348 |
| 307 - (void)insertText:(id)text replacementRange:(NSRange)replacementRange { | 349 - (void)insertText:(id)text replacementRange:(NSRange)replacementRange { |
| 308 if (!textInputClient_) | 350 if (!hostedView_) |
| 309 return; | 351 return; |
| 310 | 352 |
| 311 if ([text isKindOfClass:[NSAttributedString class]]) | 353 if ([text isKindOfClass:[NSAttributedString class]]) |
| 312 text = [text string]; | 354 text = [text string]; |
| 355 | |
| 356 MenuController* menuController = MenuController::GetActiveInstance(); | |
| 357 if (menuController && menuController->owner() == hostedView_->GetWidget()) { | |
| 358 DCHECK([text length] > 0); | |
| 359 ui::KeyEvent event(ui::ET_KEY_PRESSED, | |
| 360 ui::KeyboardCodeFromCharCode([text characterAtIndex:0]), | |
| 361 ui::DomCode::NONE, | |
| 362 ui::EventFlagsFromModifiers([NSEvent modifierFlags])); | |
| 363 if (menuController->OnWillDispatchEvent(event) == ui::POST_DISPATCH_NONE) | |
| 364 return; | |
| 365 } | |
| 366 | |
| 367 if (!textInputClient_) | |
| 368 return; | |
| 369 | |
| 313 textInputClient_->DeleteRange(gfx::Range(replacementRange)); | 370 textInputClient_->DeleteRange(gfx::Range(replacementRange)); |
| 314 textInputClient_->InsertText(base::SysNSStringToUTF16(text)); | 371 textInputClient_->InsertText(base::SysNSStringToUTF16(text)); |
| 315 } | 372 } |
| 316 | 373 |
| 317 - (NSRange)markedRange { | 374 - (NSRange)markedRange { |
| 318 if (!textInputClient_) | 375 if (!textInputClient_) |
| 319 return NSMakeRange(NSNotFound, 0); | 376 return NSMakeRange(NSNotFound, 0); |
| 320 | 377 |
| 321 gfx::Range range; | 378 gfx::Range range; |
| 322 textInputClient_->GetCompositionTextRange(&range); | 379 textInputClient_->GetCompositionTextRange(&range); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 363 } | 420 } |
| 364 | 421 |
| 365 return [super accessibilityAttributeValue:attribute]; | 422 return [super accessibilityAttributeValue:attribute]; |
| 366 } | 423 } |
| 367 | 424 |
| 368 - (id)accessibilityHitTest:(NSPoint)point { | 425 - (id)accessibilityHitTest:(NSPoint)point { |
| 369 return [hostedView_->GetNativeViewAccessible() accessibilityHitTest:point]; | 426 return [hostedView_->GetNativeViewAccessible() accessibilityHitTest:point]; |
| 370 } | 427 } |
| 371 | 428 |
| 372 @end | 429 @end |
| OLD | NEW |