#import <UIKit/UIPickerContentView_Private.h>
#import <UIKit/UIPickerView_Private.h>
#import <UIKit/UIPresentationController_Private.h>
+#import <UIKit/UIResponder_Private.h>
#import <UIKit/UIScrollView_Private.h>
#import <UIKit/UIStringDrawing_Private.h>
#import <UIKit/UITableViewCell_Private.h>
@end
typedef enum {
+ kUIKeyboardInputRepeat = 1 << 0,
+ kUIKeyboardInputPopupVariant = 1 << 1,
+ kUIKeyboardInputMultitap = 1 << 2,
+ kUIKeyboardInputSkipCandidateSelection = 1 << 3,
+ kUIKeyboardInputDeadKey = 1 << 4,
+ kUIKeyboardInputModifierFlagsChanged = 1 << 5,
+ kUIKeyboardInputFlick = 1 << 6,
+ kUIKeyboardInputPreProcessed = 1 << 7,
+} UIKeyboardInputFlags;
+
+@interface UIEvent (Details)
+@property (nonatomic, readonly) UIKeyboardInputFlags _inputFlags;
+- (void *)_hidEvent;
+- (NSString *)_unmodifiedInput;
+- (NSString *)_modifiedInput;
+- (NSInteger)_modifierFlags;
+- (BOOL)_isKeyDown;
+@end
+
+typedef enum {
UIFontTraitPlain = 0x00000000,
} UIFontTrait;
- (id)initWithCGImage:(CGImageRef)CGImage imageOrientation:(UIImageOrientation)imageOrientation;
@end
+@interface UIKeyCommand (Details)
+@property (nonatomic, readonly) UIEvent *_triggeringEvent;
+@end
+
@protocol UIKeyboardImplGeometryDelegate
@property (nonatomic, readwrite, getter=isMinimized) BOOL minimized;
- (void)prepareForImplBoundsHeightChange:(CGFloat)endDelta suppressNotification:(BOOL)suppressNotification;
@property (nonatomic, setter=_setMagnifierEnabled:) BOOL _magnifierEnabled;
@end
+@interface UIResponder (Details)
+- (void)_handleKeyUIEvent:(UIEvent *)event;
+@end
+
@interface UIScrollView (Details)
- (void)_stopScrollingAndZoomingAnimations;
- (void)_zoomToCenter:(CGPoint)center scale:(CGFloat)scale duration:(CFTimeInterval)duration force:(BOOL)force;
- (void)_zoomToCenter:(CGPoint)center scale:(CGFloat)scale duration:(CFTimeInterval)duration;
@property (nonatomic, getter=isZoomEnabled) BOOL zoomEnabled;
@property (nonatomic, readonly, getter=_isAnimatingZoom) BOOL isAnimatingZoom;
+@property (nonatomic, readonly, getter=_isAnimatingScroll) BOOL isAnimatingScroll;
@property (nonatomic) CGFloat horizontalScrollDecelerationFactor;
@property (nonatomic) CGFloat verticalScrollDecelerationFactor;
@end
extern const float UIWebViewScalesToFitScale;
extern const float UIWebViewStandardViewportWidth;
+extern NSString *const UIKeyInputPageUp;
+extern NSString *const UIKeyInputPageDown;
+
WTF_EXTERN_C_END
#import <WebCore/CoreGraphicsSPI.h>
#import <WebCore/FloatQuad.h>
#import <WebCore/Pasteboard.h>
+#import <WebCore/Scrollbar.h>
#import <WebCore/SoftLinking.h>
#import <WebCore/WebEvent.h>
#import <WebKit/WebSelectionRect.h> // FIXME: WK2 should not include WebKit headers!
#import <WebKitSystemInterfaceIOS.h>
#import <wtf/RetainPtr.h>
+@interface UIEvent(UIEventInternal)
+@property (nonatomic, assign) UIKeyboardInputFlags _inputFlags;
+@end
+
using namespace WebCore;
using namespace WebKit;
{
BOOL hasWebSelection = _webSelectionAssistant && !CGRectIsEmpty(_webSelectionAssistant.get().selectionFrame);
+ if (action == @selector(_arrowKey:))
+ return [self isFirstResponder];
+
if (action == @selector(_showTextStyleOptions:))
return _page->editorState().isContentRichlyEditable && _page->editorState().selectionIsRange && !_showingTextStyleOptions;
if (_showingTextStyleOptions)
- (NSArray *)keyCommands
{
- return @[[UIKeyCommand keyCommandWithInput:@"\t" modifierFlags:0 action:@selector(_nextAccessoryTab:)],
- [UIKeyCommand keyCommandWithInput:@"\t" modifierFlags:UIKeyModifierShift action:@selector(_prevAccessoryTab:)]];
+ static NSArray* nonEditableKeyCommands = [@[
+ [UIKeyCommand keyCommandWithInput:UIKeyInputUpArrow modifierFlags:0 action:@selector(_arrowKey:)],
+ [UIKeyCommand keyCommandWithInput:UIKeyInputDownArrow modifierFlags:0 action:@selector(_arrowKey:)],
+ [UIKeyCommand keyCommandWithInput:UIKeyInputLeftArrow modifierFlags:0 action:@selector(_arrowKey:)],
+ [UIKeyCommand keyCommandWithInput:UIKeyInputRightArrow modifierFlags:0 action:@selector(_arrowKey:)],
+
+ [UIKeyCommand keyCommandWithInput:UIKeyInputUpArrow modifierFlags:UIKeyModifierCommand action:@selector(_arrowKey:)],
+ [UIKeyCommand keyCommandWithInput:UIKeyInputDownArrow modifierFlags:UIKeyModifierCommand action:@selector(_arrowKey:)],
+
+ [UIKeyCommand keyCommandWithInput:UIKeyInputUpArrow modifierFlags:UIKeyModifierShift action:@selector(_arrowKey:)],
+ [UIKeyCommand keyCommandWithInput:UIKeyInputDownArrow modifierFlags:UIKeyModifierShift action:@selector(_arrowKey:)],
+ [UIKeyCommand keyCommandWithInput:UIKeyInputLeftArrow modifierFlags:UIKeyModifierShift action:@selector(_arrowKey:)],
+ [UIKeyCommand keyCommandWithInput:UIKeyInputRightArrow modifierFlags:UIKeyModifierShift action:@selector(_arrowKey:)],
+
+ [UIKeyCommand keyCommandWithInput:UIKeyInputUpArrow modifierFlags:UIKeyModifierAlternate action:@selector(_arrowKey:)],
+ [UIKeyCommand keyCommandWithInput:UIKeyInputDownArrow modifierFlags:UIKeyModifierAlternate action:@selector(_arrowKey:)],
+ [UIKeyCommand keyCommandWithInput:UIKeyInputLeftArrow modifierFlags:UIKeyModifierAlternate action:@selector(_arrowKey:)],
+ [UIKeyCommand keyCommandWithInput:UIKeyInputRightArrow modifierFlags:UIKeyModifierAlternate action:@selector(_arrowKey:)],
+
+ [UIKeyCommand keyCommandWithInput:@" " modifierFlags:0 action:@selector(_arrowKey:)],
+ [UIKeyCommand keyCommandWithInput:@" " modifierFlags:UIKeyModifierShift action:@selector(_arrowKey:)],
+
+ [UIKeyCommand keyCommandWithInput:UIKeyInputPageDown modifierFlags:0 action:@selector(_arrowKey:)],
+ [UIKeyCommand keyCommandWithInput:UIKeyInputPageDown modifierFlags:0 action:@selector(_arrowKey:)],
+ ] retain];
+
+ static NSArray* editableKeyCommands = [@[
+ [UIKeyCommand keyCommandWithInput:@"\t" modifierFlags:0 action:@selector(_nextAccessoryTab:)],
+ [UIKeyCommand keyCommandWithInput:@"\t" modifierFlags:UIKeyModifierShift action:@selector(_prevAccessoryTab:)]
+ ] retain];
+
+ return (_page->editorState().isContentEditable) ? editableKeyCommands : nonEditableKeyCommands;
+}
+
+- (void)_arrowKey:(id)sender
+{
+ UIKeyCommand* command = sender;
+ [self handleKeyEvent:command._triggeringEvent];
}
- (void)_nextAccessoryTab:(id)sender
return YES;
}
+- (void)_handleKeyUIEvent:(::UIEvent *)event
+{
+ // We only want to handle key event from the hardware keyboard when we are
+ // first responder and we are not interacting with editable content.
+ if ([self isFirstResponder] && event._hidEvent && !_page->editorState().isContentEditable)
+ [self handleKeyEvent:event];
+
+ [super _handleKeyUIEvent:event];
+}
+
+- (void)handleKeyEvent:(::UIEvent *)event
+{
+ ::WebEvent *webEvent = [[[::WebEvent alloc] initWithKeyEventType:(event._isKeyDown) ? WebEventKeyDown : WebEventKeyUp
+ timeStamp:event.timestamp
+ characters:event._modifiedInput
+ charactersIgnoringModifiers:event._unmodifiedInput
+ modifiers:event._modifierFlags
+ isRepeating:(event._inputFlags & kUIKeyboardInputRepeat)
+ withFlags:event._inputFlags
+ keyCode:0
+ isTabKey:[event._modifiedInput isEqualToString:@"\t"]
+ characterSet:WebEventCharacterSetUnicode] autorelease];
+
+ [self handleKeyWebEvent:webEvent];
+}
+
- (void)handleKeyWebEvent:(WebIOSEvent *)theEvent
{
_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent));
static const unsigned kWebBackspaceKey = 0x0008;
static const unsigned kWebReturnKey = 0x000D;
static const unsigned kWebDeleteKey = 0x007F;
- static const unsigned kWebLeftArrowKey = 0x00AC;
- static const unsigned kWebUpArrowKey = 0x00AD;
- static const unsigned kWebRightArrowKey = 0x00AE;
- static const unsigned kWebDownArrowKey = 0x00AF;
static const unsigned kWebDeleteForwardKey = 0xF728;
+ static const unsigned kWebSpaceKey = 0x20;
if (!_page->editorState().isContentEditable && event.isTabKey)
return NO;
BOOL shift = event.modifierFlags & WebEventFlagMaskShift;
+ BOOL command = event.modifierFlags & WebEventFlagMaskCommand;
+ BOOL option = event.modifierFlags & WebEventFlagMaskAlternate;
+ NSString *charactersIgnoringModifiers = [event charactersIgnoringModifiers];
+ BOOL shouldScroll = YES;
+ FloatPoint scrollOffset;
+
+ if ([charactersIgnoringModifiers isEqualToString:UIKeyInputLeftArrow])
+ scrollOffset.setX(-Scrollbar::pixelsPerLineStep());
+ else if ([charactersIgnoringModifiers isEqualToString:UIKeyInputUpArrow]) {
+ if (option)
+ scrollOffset.setY(-_page->unobscuredContentRect().height());
+ else if (command)
+ scrollOffset.setY(-[self bounds].size.height);
+ else
+ scrollOffset.setY(-Scrollbar::pixelsPerLineStep());
+ } else if ([charactersIgnoringModifiers isEqualToString:UIKeyInputRightArrow])
+ scrollOffset.setX(Scrollbar::pixelsPerLineStep());
+ else if ([charactersIgnoringModifiers isEqualToString:UIKeyInputDownArrow]) {
+ if (option)
+ scrollOffset.setY(_page->unobscuredContentRect().height());
+ else if (command)
+ scrollOffset.setY([self bounds].size.height);
+ else
+ scrollOffset.setY(Scrollbar::pixelsPerLineStep());
+ } else if ([charactersIgnoringModifiers isEqualToString:UIKeyInputPageDown])
+ scrollOffset.setY(_page->unobscuredContentRect().height());
+ else if ([charactersIgnoringModifiers isEqualToString:UIKeyInputPageUp])
+ scrollOffset.setY(-_page->unobscuredContentRect().height());
+ else
+ shouldScroll = NO;
- switch (event.characterSet) {
- case WebEventCharacterSetSymbol: {
- String command;
- NSString *characters = [event charactersIgnoringModifiers];
- if ([characters length] == 0)
- break;
- switch ([characters characterAtIndex:0]) {
- case kWebLeftArrowKey:
- command = shift ? ASCIILiteral("moveLeftAndModifySelection") : ASCIILiteral("moveLeft");
- break;
+ if (shouldScroll) {
+ [_webView _scrollByOffset:scrollOffset];
+ return YES;
+ }
- case kWebUpArrowKey:
- command = shift ? ASCIILiteral("moveUpAndModifySelection") : ASCIILiteral("moveUp");
- break;
+ UIKeyboardImpl *keyboard = [UIKeyboardImpl sharedInstance];
+ NSString *characters = [event characters];
+
+ if (![characters length])
+ return NO;
- case kWebRightArrowKey:
- command = shift ? ASCIILiteral("moveRightAndModifySelection") : ASCIILiteral("moveRight");
- break;
+ switch ([characters characterAtIndex:0]) {
+ case kWebBackspaceKey:
+ case kWebDeleteKey:
+ // FIXME: remove deleteFromInput once UIKit adopts deleteFromInputWithFlags
+ if ([keyboard respondsToSelector:@selector(deleteFromInputWithFlags:)])
+ [keyboard deleteFromInputWithFlags:event.keyboardFlags];
+ else
+ [keyboard deleteFromInput];
+ return YES;
- case kWebDownArrowKey:
- command = shift ? ASCIILiteral("moveDownAndModifySelection") : ASCIILiteral("moveDown");
- break;
+ case kWebSpaceKey:
+ if (!_page->editorState().isContentEditable) {
+ [_webView _scrollByOffset:FloatPoint(0, shift ? -_page->unobscuredContentRect().height() : _page->unobscuredContentRect().height())];
+ return YES;
}
- if (!command.isEmpty()) {
- _page->executeEditCommand(command);
+ if (isCharEvent) {
+ [keyboard addInputString:event.characters withFlags:event.keyboardFlags];
return YES;
}
break;
- }
- case WebEventCharacterSetASCII:
- case WebEventCharacterSetUnicode: {
- NSString *characters = [event characters];
- if ([characters length] == 0)
- break;
- UIKeyboardImpl *keyboard = [UIKeyboardImpl sharedInstance];
- switch ([characters characterAtIndex:0]) {
- case kWebBackspaceKey:
- case kWebDeleteKey:
- // FIXME: remove deleteFromInput once UIKit adopts deleteFromInputWithFlags
- if ([keyboard respondsToSelector:@selector(deleteFromInputWithFlags:)])
- [keyboard deleteFromInputWithFlags:event.keyboardFlags];
- else
- [keyboard deleteFromInput];
+
+ case kWebEnterKey:
+ case kWebReturnKey:
+ if (isCharEvent) {
+ // Map \r from HW keyboard to \n to match the behavior of the soft keyboard.
+ [keyboard addInputString:@"\n" withFlags:0];
return YES;
+ }
+ break;
- case kWebEnterKey:
- case kWebReturnKey:
- if (isCharEvent) {
- // Map \r from HW keyboard to \n to match the behavior of the soft keyboard.
- [keyboard addInputString:@"\n" withFlags:0];
- return YES;
- }
- return NO;
+ case kWebDeleteForwardKey:
+ _page->executeEditCommand(ASCIILiteral("deleteForward"));
+ return YES;
- case kWebDeleteForwardKey:
- _page->executeEditCommand(ASCIILiteral("deleteForward"));
+ default:
+ if (isCharEvent) {
+ [keyboard addInputString:event.characters withFlags:event.keyboardFlags];
return YES;
-
- default: {
- if (isCharEvent) {
- [keyboard addInputString:event.characters withFlags:event.keyboardFlags];
- return YES;
- }
- return NO;
}
- }
break;
}
- default:
- return NO;
- }
return NO;
}