[iOS] Draw caps lock indicator in password fields
[WebKit-https.git] / Source / WebCore / platform / ios / PlatformEventFactoryIOS.mm
1 /*
2  * Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010, 2011, 2014 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 "PlatformEventFactoryIOS.h"
28
29 #if PLATFORM(IOS_FAMILY)
30
31 #import "IntPoint.h"
32 #import "KeyEventCocoa.h"
33 #import "KeyEventCodesIOS.h"
34 #import "Logging.h"
35 #import "WAKAppKitStubs.h"
36 #import "WebEvent.h"
37 #import "WindowsKeyboardCodes.h"
38 #import <wtf/Optional.h>
39 #import <wtf/WallTime.h>
40
41 namespace WebCore {
42
43 static OptionSet<PlatformEvent::Modifier> modifiersForEvent(WebEvent *event)
44 {
45     OptionSet<PlatformEvent::Modifier> modifiers;
46
47     if (event.modifierFlags & WebEventFlagMaskShiftKey)
48         modifiers.add(PlatformEvent::Modifier::ShiftKey);
49     if (event.modifierFlags & WebEventFlagMaskControlKey)
50         modifiers.add(PlatformEvent::Modifier::CtrlKey);
51     if (event.modifierFlags & WebEventFlagMaskOptionKey)
52         modifiers.add(PlatformEvent::Modifier::AltKey);
53     if (event.modifierFlags & WebEventFlagMaskCommandKey)
54         modifiers.add(PlatformEvent::Modifier::MetaKey);
55     if (event.modifierFlags & WebEventFlagMaskLeftCapsLockKey)
56         modifiers.add(PlatformEvent::Modifier::CapsLockKey);
57
58     return modifiers;
59 }
60
61 static inline IntPoint pointForEvent(WebEvent *event)
62 {
63     return IntPoint(event.locationInWindow);
64 }
65
66 static inline IntPoint globalPointForEvent(WebEvent *event)
67 {
68     // iOS WebKit works as if it is full screen. Therefore Web coords are Global coords.
69     return pointForEvent(event);
70 }
71
72 static PlatformEvent::Type mouseEventType(WebEvent *event)
73 {
74     switch (event.type) {
75     case WebEventMouseDown:
76         return PlatformEvent::MousePressed;
77     case WebEventMouseUp:
78         return PlatformEvent::MouseReleased;
79     case WebEventMouseMoved:
80         return PlatformEvent::MouseMoved;
81     default:
82         ASSERT_NOT_REACHED();
83         return PlatformEvent::MousePressed;
84     }
85 }
86
87 class PlatformMouseEventBuilder : public PlatformMouseEvent {
88 public:
89     PlatformMouseEventBuilder(WebEvent *event)
90     {
91         m_type = mouseEventType(event);
92         m_timestamp = WallTime::now();
93
94         m_position = pointForEvent(event);
95         m_globalPosition = globalPointForEvent(event);
96         m_button = LeftButton; // This has always been the LeftButton on iOS.
97         m_clickCount = 1; // This has always been 1 on iOS.
98     }
99 };
100
101 PlatformMouseEvent PlatformEventFactory::createPlatformMouseEvent(WebEvent *event)
102 {
103     return PlatformMouseEventBuilder(event);
104 }
105
106 class PlatformWheelEventBuilder : public PlatformWheelEvent {
107 public:
108     PlatformWheelEventBuilder(WebEvent *event)
109     {
110         ASSERT(event.type == WebEventScrollWheel);
111
112         m_type = PlatformEvent::Wheel;
113         m_timestamp = WallTime::now();
114
115         m_position = pointForEvent(event);
116         m_globalPosition = globalPointForEvent(event);
117         m_deltaX = event.deltaX;
118         m_deltaY = event.deltaY;
119         m_granularity = ScrollByPixelWheelEvent; // iOS only supports continuous (pixel-mode) scrolling.
120     }
121 };
122
123 PlatformWheelEvent PlatformEventFactory::createPlatformWheelEvent(WebEvent *event)
124 {
125     return PlatformWheelEventBuilder(event);
126 }
127
128 String keyIdentifierForKeyEvent(WebEvent *event)
129 {
130     if (event.keyboardFlags & WebEventKeyboardInputModifierFlagsChanged) {
131         switch (event.keyCode) {
132         case VK_LWIN: // Left Command
133         case VK_APPS: // Right Command
134             return "Meta"_s;
135
136         case VK_CAPITAL: // Caps Lock
137             return "CapsLock"_s;
138
139         case VK_LSHIFT: // Left Shift
140         case VK_RSHIFT: // Right Shift
141             return "Shift"_s;
142
143         case VK_LMENU: // Left Alt
144         case VK_RMENU: // Right Alt
145             return "Alt"_s;
146
147         case VK_LCONTROL: // Left Ctrl
148         case VK_RCONTROL: // Right Ctrl
149             return "Control"_s;
150
151         default:
152             ASSERT_NOT_REACHED();
153             return emptyString();
154         }
155     }
156     NSString *characters = event.charactersIgnoringModifiers;
157     if ([characters length] != 1) {
158         LOG(Events, "received an unexpected number of characters in key event: %u", [characters length]);
159         return "Unidentified"_s;
160     }
161     return keyIdentifierForCharCode([characters characterAtIndex:0]);
162 }
163
164 String keyForKeyEvent(WebEvent *event)
165 {
166     if (event.keyboardFlags & WebEventKeyboardInputModifierFlagsChanged) {
167         switch (event.keyCode) {
168         case VK_LWIN: // Left Command
169         case VK_APPS: // Right Command
170             return "Meta"_s;
171
172         case VK_CAPITAL: // Caps Lock
173             return "CapsLock"_s;
174
175         case VK_LSHIFT: // Left Shift
176         case VK_RSHIFT: // Right Shift
177             return "Shift"_s;
178
179         case VK_LMENU: // Left Alt
180         case VK_RMENU: // Right Alt
181             return "Alt"_s;
182
183         case VK_LCONTROL: // Left Ctrl
184         case VK_RCONTROL: // Right Ctrl
185             return "Control"_s;
186
187         default:
188             ASSERT_NOT_REACHED();
189             return "Unidentified"_s;
190         }
191     }
192
193     NSString *characters = event.characters;
194     auto length = [characters length];
195     // characters return an empty string for dead keys.
196     // https://developer.apple.com/reference/appkit/nsevent/1534183-characters
197     // "Dead" is defined here https://w3c.github.io/uievents-key/#keys-composition.
198     if (!length)
199         return "Dead"_s;
200     if (length > 1)
201         return characters;
202     return keyForCharCode([characters characterAtIndex:0]);
203 }
204
205 // https://w3c.github.io/uievents-code/
206 String codeForKeyEvent(WebEvent *event)
207 {
208     switch (event.keyCode) {
209     // Keys in the alphanumeric section.
210     case VK_OEM_3: return "Backquote"_s;
211     case VK_OEM_5: return "Backslash"_s;
212     case VK_BACK: return "Backspace"_s;
213     case VK_OEM_4: return "BracketLeft"_s;
214     case VK_OEM_6: return "BracketRight"_s;
215     case VK_OEM_COMMA: return "Comma"_s;
216     case VK_0: return "Digit0"_s;
217     case VK_1: return "Digit1"_s;
218     case VK_2: return "Digit2"_s;
219     case VK_3: return "Digit3"_s;
220     case VK_4: return "Digit4"_s;
221     case VK_5: return "Digit5"_s;
222     case VK_6: return "Digit6"_s;
223     case VK_7: return "Digit7"_s;
224     case VK_8: return "Digit8"_s;
225     case VK_9: return "Digit9"_s;
226     case VK_OEM_PLUS: return "Equal"_s;
227     case VK_OEM_102: return "IntlBackslash"_s;
228     // IntlRo.
229     // IntlYen.
230     case VK_A: return "KeyA"_s;
231     case VK_B: return "KeyB"_s;
232     case VK_C: return "KeyC"_s;
233     case VK_D: return "KeyD"_s;
234     case VK_E: return "KeyE"_s;
235     case VK_F: return "KeyF"_s;
236     case VK_G: return "KeyG"_s;
237     case VK_H: return "KeyH"_s;
238     case VK_I: return "KeyI"_s;
239     case VK_J: return "KeyJ"_s;
240     case VK_K: return "KeyK"_s;
241     case VK_L: return "KeyL"_s;
242     case VK_M: return "KeyM"_s;
243     case VK_N: return "KeyN"_s;
244     case VK_O: return "KeyO"_s;
245     case VK_P: return "KeyP"_s;
246     case VK_Q: return "KeyQ"_s;
247     case VK_R: return "KeyR"_s;
248     case VK_S: return "KeyS"_s;
249     case VK_T: return "KeyT"_s;
250     case VK_U: return "KeyU"_s;
251     case VK_V: return "KeyV"_s;
252     case VK_W: return "KeyW"_s;
253     case VK_X: return "KeyX"_s;
254     case VK_Y: return "KeyY"_s;
255     case VK_Z: return "KeyZ"_s;
256     case VK_OEM_MINUS: return "Minus"_s;
257     case VK_OEM_PERIOD: return "Period"_s;
258     case VK_OEM_7: return "Quote"_s;
259     case VK_OEM_1: return "Semicolon"_s;
260     case VK_OEM_2: return "Slash"_s;
261
262     // Functional keys in alphanumeric section.
263     case VK_MENU: return "AltLeft"_s;
264     // AltRight.
265     case VK_CAPITAL: return "CapsLock"_s;
266     // ContextMenu.
267     case VK_LCONTROL: return "ControlLeft"_s;
268     case VK_RCONTROL: return "ControlRight"_s;
269     case VK_RETURN: return "Enter"_s; //  Labeled Return on Apple keyboards.
270     case VK_LWIN: return "MetaLeft"_s;
271     case VK_RWIN: return "MetaRight"_s;
272     case VK_LSHIFT: return "ShiftLeft"_s;
273     case VK_RSHIFT: return "ShiftRight"_s;
274     case VK_SPACE: return "Space"_s;
275     case VK_TAB: return "Tab"_s;
276
277     // Functional keys found on Japanese and Korean keyboards.
278     // Convert.
279     case VK_KANA: return "KanaMode"_s;
280     // Lang1.
281     // Lang2.
282     // Lang3.
283     // Lang4.
284     // Lang5.
285     // NonConvert.
286
287     // Keys in the ControlPad section.
288     // Delete
289     case VK_END: return "End"_s;
290     case VK_HELP: return "Help"_s;
291     case VK_HOME: return "Home"_s;
292     // Insert: Not present on Apple keyboards.
293     case VK_NEXT: return "PageDown"_s;
294     case VK_PRIOR: return "PageUp"_s;
295
296     // Keys in the ArrowPad section.
297     case VK_DOWN: return "ArrowDown"_s;
298     case VK_LEFT: return "ArrowLeft"_s;
299     case VK_RIGHT: return "ArrowRight"_s;
300     case VK_UP: return "ArrowUp"_s;
301
302     // Keys in the Numpad section.
303     case VK_NUMLOCK: return "NumLock"_s;
304     case VK_NUMPAD0: return "Numpad0"_s;
305     case VK_NUMPAD1: return "Numpad1"_s;
306     case VK_NUMPAD2: return "Numpad2"_s;
307     case VK_NUMPAD3: return "Numpad3"_s;
308     case VK_NUMPAD4: return "Numpad4"_s;
309     case VK_NUMPAD5: return "Numpad5"_s;
310     case VK_NUMPAD6: return "Numpad6"_s;
311     case VK_NUMPAD7: return "Numpad7"_s;
312     case VK_NUMPAD8: return "Numpad8"_s;
313     case VK_NUMPAD9: return "Numpad9"_s;
314     case VK_ADD: return "NumpadAdd"_s;
315     // NumpadBackspace.
316     // NumpadClear.
317     // NumpadClearEntry.
318     case VK_SEPARATOR: return "NumpadComma"_s;
319     case VK_DECIMAL: return "NumpadDecimal"_s;
320     case VK_DIVIDE: return "NumpadDivide"_s;
321     // NumpadEnter.
322     case VK_CLEAR: return "NumpadEqual"_s;
323     // NumpadHash.
324     // NumpadMemoryAdd.
325     // NumpadMemoryClear.
326     // NumpadMemoryRecall.
327     // NumpadMemoryStore.
328     // NumpadMemorySubtract.
329     case VK_MULTIPLY: return "NumpadMultiply"_s;
330     // NumpadParenLeft.
331     // NumpadParenRight.
332     // NumpadStar: The specification says to use "NumpadMultiply" for the * key on numeric keypads.
333     case VK_SUBTRACT: return "NumpadSubtract"_s;
334
335     // Keys in the Function section.
336     case VK_ESCAPE: return "Escape"_s;
337     case VK_F1: return "F1"_s;
338     case VK_F2: return "F2"_s;
339     case VK_F3: return "F3"_s;
340     case VK_F4: return "F4"_s;
341     case VK_F5: return "F5"_s;
342     case VK_F6: return "F6"_s;
343     case VK_F7: return "F7"_s;
344     case VK_F8: return "F8"_s;
345     case VK_F9: return "F9"_s;
346     case VK_F10: return "F10"_s;
347     case VK_F11: return "F11"_s;
348     case VK_F12: return "F12"_s;
349     case VK_F13: return "F13"_s;
350     case VK_F14: return "F14"_s;
351     case VK_F15: return "F15"_s;
352     case VK_F16: return "F16"_s;
353     case VK_F17: return "F17"_s;
354     case VK_F18: return "F18"_s;
355     case VK_F19: return "F19"_s;
356     case VK_F20: return "F20"_s;
357     // Fn: This is typically a hardware key that does not generate a separate code.
358     // FnLock.
359     // PrintScreen.
360     // ScrollLock.
361     // Pause.
362
363     // Media keys.
364     // BrowserBack.
365     // BrowserFavorites.
366     // BrowserForward.
367     // BrowserHome.
368     // BrowserRefresh.
369     // BrowserSearch.
370     // BrowserStop.
371     // Eject.
372     // LaunchApp1.
373     // LaunchApp2.
374     // LaunchMail.
375     // MediaPlayPause.
376     // MediaSelect.
377     // MediaStop.
378     // MediaTrackNext.
379     // MediaTrackPrevious.
380     // Power.
381     // Sleep.
382     case VK_VOLUME_DOWN: return "AudioVolumeDown"_s;
383     case VK_VOLUME_MUTE: return "AudioVolumeMute"_s;
384     case VK_VOLUME_UP: return "AudioVolumeUp"_s;
385     // WakeUp.
386
387     // Legacy modifier keys.
388     // Hyper.
389     // Super.
390     // Turbo.
391
392     // Legacy process control keys.
393     // Abort.
394     // Resume.
395     // Suspend.
396
397     // Legacy editing keys.
398     // Again.
399     // Copy.
400     // Cut.
401     // Find.
402     // Open.
403     // Paste.
404     // Props.
405     // Select.
406     // Undo.
407
408     // Keys found on international keyboards.
409     // Hiragana.
410     // Katakana.
411
412     default:
413         return "Unidentified"_s;
414     }
415 }
416
417 class PlatformKeyboardEventBuilder : public PlatformKeyboardEvent {
418 public:
419     PlatformKeyboardEventBuilder(WebEvent *event)
420     {
421         ASSERT(event.type == WebEventKeyDown || event.type == WebEventKeyUp);
422
423         m_type = (event.type == WebEventKeyUp ? PlatformEvent::KeyUp : PlatformEvent::KeyDown);
424         m_modifiers = modifiersForEvent(event);
425         m_timestamp = WallTime::now();
426
427         if (event.keyboardFlags & WebEventKeyboardInputModifierFlagsChanged) {
428             m_text = emptyString();
429             m_unmodifiedText = emptyString();
430             m_autoRepeat = false;
431         } else {
432             m_text = event.characters;
433             m_unmodifiedText = event.charactersIgnoringModifiers;
434             m_autoRepeat = event.isKeyRepeating;
435         }
436         m_key = keyForKeyEvent(event);
437         m_code = codeForKeyEvent(event);
438         m_keyIdentifier = keyIdentifierForKeyEvent(event);
439         m_windowsVirtualKeyCode = event.keyCode;
440         m_isKeypad = false; // iOS does not distinguish the numpad. See <rdar://problem/7190835>.
441         m_isSystemKey = false;
442         m_Event = event;
443
444         // Always use 13 for Enter/Return -- we don't want to use AppKit's different character for Enter.
445         if (m_windowsVirtualKeyCode == '\r') {
446             m_text = "\r";
447             m_unmodifiedText = "\r";
448         }
449
450         // The adjustments below are only needed in backward compatibility mode, but we cannot tell what mode we are in from here.
451
452         // Turn 0x7F into 8, because backspace needs to always be 8.
453         if (m_text == "\x7F")
454             m_text = "\x8";
455         if (m_unmodifiedText == "\x7F")
456             m_unmodifiedText = "\x8";
457         // Always use 9 for tab -- we don't want to use AppKit's different character for shift-tab.
458         if (m_windowsVirtualKeyCode == 9) {
459             m_text = "\x9";
460             m_unmodifiedText = "\x9";
461         }
462     }
463 };
464
465 PlatformKeyboardEvent PlatformEventFactory::createPlatformKeyboardEvent(WebEvent *event)
466 {
467     return PlatformKeyboardEventBuilder(event);
468 }
469
470 #if ENABLE(TOUCH_EVENTS)
471 static PlatformTouchPoint::TouchPhaseType convertTouchPhase(NSNumber *touchPhaseNumber)
472 {
473     WebEventTouchPhaseType touchPhase = static_cast<WebEventTouchPhaseType>([touchPhaseNumber unsignedIntValue]);
474     switch (touchPhase) {
475     case WebEventTouchPhaseBegan:
476         return PlatformTouchPoint::TouchPhaseBegan;
477     case WebEventTouchPhaseMoved:
478         return PlatformTouchPoint::TouchPhaseMoved;
479     case WebEventTouchPhaseStationary:
480         return PlatformTouchPoint::TouchPhaseStationary;
481     case WebEventTouchPhaseEnded:
482         return PlatformTouchPoint::TouchPhaseEnded;
483     case WebEventTouchPhaseCancelled:
484         return PlatformTouchPoint::TouchPhaseCancelled;
485     default:
486         ASSERT_NOT_REACHED();
487     }
488     return PlatformTouchPoint::TouchPhaseBegan;
489 }
490
491 static PlatformEvent::Type touchEventType(WebEvent *event)
492 {
493     switch (event.type) {
494     case WebEventTouchBegin:
495         return PlatformEvent::TouchStart;
496     case WebEventTouchEnd:
497         return PlatformEvent::TouchEnd;
498     case WebEventTouchCancel:
499         return PlatformEvent::TouchCancel;
500     case WebEventTouchChange:
501         return PlatformEvent::TouchMove;
502     default:
503         ASSERT_NOT_REACHED();
504         return PlatformEvent::TouchCancel;
505     }
506 }
507     
508 static PlatformTouchPoint::TouchPhaseType touchPhaseFromPlatformEventType(PlatformEvent::Type type)
509 {
510     switch (type) {
511     case PlatformEvent::TouchStart:
512         return PlatformTouchPoint::TouchPhaseBegan;
513     case PlatformEvent::TouchMove:
514         return PlatformTouchPoint::TouchPhaseMoved;
515     case PlatformEvent::TouchEnd:
516         return PlatformTouchPoint::TouchPhaseEnded;
517     default:
518         ASSERT_NOT_REACHED();
519         return PlatformTouchPoint::TouchPhaseCancelled;
520     }
521 }
522
523 class PlatformTouchPointBuilder : public PlatformTouchPoint {
524 public:
525     PlatformTouchPointBuilder(unsigned identifier, const IntPoint& location, TouchPhaseType phase)
526         : PlatformTouchPoint(identifier, location, phase)
527     {
528     }
529 };
530
531 class PlatformTouchEventBuilder : public PlatformTouchEvent {
532 public:
533     PlatformTouchEventBuilder(WebEvent *event)
534     {
535         m_type = touchEventType(event);
536         m_modifiers = modifiersForEvent(event);
537         m_timestamp = WallTime::fromRawSeconds(event.timestamp);
538
539         m_gestureScale = event.gestureScale;
540         m_gestureRotation = event.gestureRotation;
541         m_isGesture = event.isGesture;
542         m_position = pointForEvent(event);
543         m_globalPosition = globalPointForEvent(event);
544
545         unsigned touchCount = event.touchCount;
546         m_touchPoints.reserveInitialCapacity(touchCount);
547         for (unsigned i = 0; i < touchCount; ++i) {
548             unsigned identifier = [(NSNumber *)[event.touchIdentifiers objectAtIndex:i] unsignedIntValue];
549             IntPoint location = IntPoint([(NSValue *)[event.touchLocations objectAtIndex:i] pointValue]);
550             PlatformTouchPoint::TouchPhaseType touchPhase = convertTouchPhase([event.touchPhases objectAtIndex:i]);
551             m_touchPoints.uncheckedAppend(PlatformTouchPointBuilder(identifier, location, touchPhase));
552         }
553     }
554     
555     PlatformTouchEventBuilder(PlatformEvent::Type type, IntPoint location)
556     {
557         m_type = type;
558         m_timestamp = WallTime::now();
559         
560         m_gestureScale = 1;
561         m_gestureRotation = 0;
562         m_isGesture = 0;
563         m_position = location;
564         m_globalPosition = location;
565         m_isPotentialTap = true;
566         
567         unsigned touchCount = 1;
568         m_touchPoints.reserveInitialCapacity(touchCount);
569         for (unsigned i = 0; i < touchCount; ++i)
570             m_touchPoints.uncheckedAppend(PlatformTouchPointBuilder(1, location, touchPhaseFromPlatformEventType(type)));
571     }
572 };
573
574 PlatformTouchEvent PlatformEventFactory::createPlatformTouchEvent(WebEvent *event)
575 {
576     return PlatformTouchEventBuilder(event);
577 }
578     
579 PlatformTouchEvent PlatformEventFactory::createPlatformSimulatedTouchEvent(PlatformEvent::Type type, IntPoint location)
580 {
581     return PlatformTouchEventBuilder(type, location);
582 }
583
584 #endif // ENABLE(TOUCH_EVENTS)
585
586 } // namespace WebCore
587
588 #endif // PLATFORM(IOS_FAMILY)