initial import
[vuplus_webkit] / Source / WebCore / platform / mac / KeyEventMac.mm
1 /*
2  * Copyright (C) 2004, 2006, 2007, 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 COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "PlatformKeyboardEvent.h"
28
29 #if PLATFORM(MAC)
30
31 #import "KeyEventCocoa.h"
32 #import "Logging.h"
33 #import "WindowsKeyboardCodes.h"
34 #import <Carbon/Carbon.h>
35
36 using namespace WTF;
37
38 namespace WebCore {
39
40 static bool isKeypadEvent(NSEvent* event)
41 {
42     // Check that this is the type of event that has a keyCode.
43     switch ([event type]) {
44         case NSKeyDown:
45         case NSKeyUp:
46         case NSFlagsChanged:
47             break;
48         default:
49             return false;
50     }
51
52     if ([event modifierFlags] & NSNumericPadKeyMask)
53         return true;
54
55     switch ([event keyCode]) {
56         case 71: // Clear
57         case 81: // =
58         case 75: // /
59         case 67: // *
60         case 78: // -
61         case 69: // +
62         case 76: // Enter
63         case 65: // .
64         case 82: // 0
65         case 83: // 1
66         case 84: // 2
67         case 85: // 3
68         case 86: // 4
69         case 87: // 5
70         case 88: // 6
71         case 89: // 7
72         case 91: // 8
73         case 92: // 9
74             return true;
75      }
76
77      return false;
78 }
79
80 static inline bool isKeyUpEvent(NSEvent *event)
81 {
82     if ([event type] != NSFlagsChanged)
83         return [event type] == NSKeyUp;
84     // FIXME: This logic fails if the user presses both Shift keys at once, for example:
85     // we treat releasing one of them as keyDown.
86     switch ([event keyCode]) {
87         case 54: // Right Command
88         case 55: // Left Command
89             return ([event modifierFlags] & NSCommandKeyMask) == 0;
90
91         case 57: // Capslock
92             return ([event modifierFlags] & NSAlphaShiftKeyMask) == 0;
93
94         case 56: // Left Shift
95         case 60: // Right Shift
96             return ([event modifierFlags] & NSShiftKeyMask) == 0;
97
98         case 58: // Left Alt
99         case 61: // Right Alt
100             return ([event modifierFlags] & NSAlternateKeyMask) == 0;
101
102         case 59: // Left Ctrl
103         case 62: // Right Ctrl
104             return ([event modifierFlags] & NSControlKeyMask) == 0;
105
106         case 63: // Function
107             return ([event modifierFlags] & NSFunctionKeyMask) == 0;
108     }
109     return false;
110 }
111
112 static inline String textFromEvent(NSEvent* event)
113 {
114     if ([event type] == NSFlagsChanged)
115         return "";
116     return [event characters];
117 }
118
119
120 static inline String unmodifiedTextFromEvent(NSEvent* event)
121 {
122     if ([event type] == NSFlagsChanged)
123         return "";
124     return [event charactersIgnoringModifiers];
125 }
126
127 static String keyIdentifierForKeyEvent(NSEvent* event)
128 {
129     if ([event type] == NSFlagsChanged)
130         switch ([event keyCode]) {
131             case 54: // Right Command
132             case 55: // Left Command
133                 return "Meta";
134
135             case 57: // Capslock
136                 return "CapsLock";
137
138             case 56: // Left Shift
139             case 60: // Right Shift
140                 return "Shift";
141
142             case 58: // Left Alt
143             case 61: // Right Alt
144                 return "Alt";
145
146             case 59: // Left Ctrl
147             case 62: // Right Ctrl
148                 return "Control";
149
150             default:
151                 ASSERT_NOT_REACHED();
152                 return "";
153         }
154
155     NSString *s = [event charactersIgnoringModifiers];
156     if ([s length] != 1) {
157         LOG(Events, "received an unexpected number of characters in key event: %u", [s length]);
158         return "Unidentified";
159     }
160     return keyIdentifierForCharCode([s characterAtIndex:0]);
161 }
162
163 static int windowsKeyCodeForKeyEvent(NSEvent *event)
164 {
165     int code = 0;
166     // There are several kinds of characters for which we produce key code from char code:
167     // 1. Roman letters. Windows keyboard layouts affect both virtual key codes and character codes for these,
168     //    so e.g. 'A' gets the same keyCode on QWERTY, AZERTY or Dvorak layouts.
169     // 2. Keys for which there is no known Mac virtual key codes, like PrintScreen.
170     // 3. Certain punctuation keys. On Windows, these are also remapped depending on current keyboard layout,
171     //    but see comment in windowsKeyCodeForCharCode().
172     if ([event type] == NSKeyDown || [event type] == NSKeyUp) {
173         // Cmd switches Roman letters for Dvorak-QWERTY layout, so try modified characters first.
174         NSString* s = [event characters];
175         code = [s length] > 0 ? windowsKeyCodeForCharCode([s characterAtIndex:0]) : 0;
176         if (code)
177             return code;
178
179         // Ctrl+A on an AZERTY keyboard would get VK_Q keyCode if we relied on -[NSEvent keyCode] below.
180         s = [event charactersIgnoringModifiers];
181         code = [s length] > 0 ? windowsKeyCodeForCharCode([s characterAtIndex:0]) : 0;
182         if (code)
183             return code;
184     }
185
186     // Map Mac virtual key code directly to Windows one for any keys not handled above.
187     // E.g. the key next to Caps Lock has the same Event.keyCode on U.S. keyboard ('A') and on Russian keyboard (CYRILLIC LETTER EF).
188     return windowsKeyCodeForKeyCode([event keyCode]);
189 }
190
191 PlatformKeyboardEvent::PlatformKeyboardEvent(NSEvent *event)
192     : m_type(isKeyUpEvent(event) ? PlatformKeyboardEvent::KeyUp : PlatformKeyboardEvent::KeyDown)
193     , m_text(textFromEvent(event))
194     , m_unmodifiedText(unmodifiedTextFromEvent(event))
195     , m_keyIdentifier(keyIdentifierForKeyEvent(event))
196     , m_autoRepeat(([event type] != NSFlagsChanged) && [event isARepeat])
197     , m_windowsVirtualKeyCode(windowsKeyCodeForKeyEvent(event))
198     , m_nativeVirtualKeyCode([event keyCode])
199     , m_isKeypad(isKeypadEvent(event))
200     , m_shiftKey([event modifierFlags] & NSShiftKeyMask)
201     , m_ctrlKey([event modifierFlags] & NSControlKeyMask)
202     , m_altKey([event modifierFlags] & NSAlternateKeyMask)
203     , m_metaKey([event modifierFlags] & NSCommandKeyMask)
204     , m_macEvent(event)
205 {
206     // Always use 13 for Enter/Return -- we don't want to use AppKit's different character for Enter.
207     if (m_windowsVirtualKeyCode == VK_RETURN) {
208         m_text = "\r";
209         m_unmodifiedText = "\r";
210     }
211
212     // AppKit sets text to "\x7F" for backspace, but the correct KeyboardEvent character code is 8.
213     if (m_windowsVirtualKeyCode == VK_BACK) {
214         m_text = "\x8";
215         m_unmodifiedText = "\x8";
216     }
217
218     // Always use 9 for Tab -- we don't want to use AppKit's different character for shift-tab.
219     if (m_windowsVirtualKeyCode == VK_TAB) {
220         m_text = "\x9";
221         m_unmodifiedText = "\x9";
222     }
223 }
224
225 void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type type, bool backwardCompatibilityMode)
226 {
227     // Can only change type from KeyDown to RawKeyDown or Char, as we lack information for other conversions.
228     ASSERT(m_type == KeyDown);
229     ASSERT(type == RawKeyDown || type == Char);
230     m_type = type;
231     if (backwardCompatibilityMode)
232         return;
233
234     if (type == RawKeyDown) {
235         m_text = String();
236         m_unmodifiedText = String();
237     } else {
238         m_keyIdentifier = String();
239         m_windowsVirtualKeyCode = 0;
240         if (m_text.length() == 1 && (m_text[0U] >= 0xF700 && m_text[0U] <= 0xF7FF)) {
241             // According to NSEvents.h, OpenStep reserves the range 0xF700-0xF8FF for function keys. However, some actual private use characters
242             // happen to be in this range, e.g. the Apple logo (Option+Shift+K).
243             // 0xF7FF is an arbitrary cut-off.
244             m_text = String();
245             m_unmodifiedText = String();
246         }
247     }
248 }
249
250 bool PlatformKeyboardEvent::currentCapsLockState()
251 {
252     return GetCurrentKeyModifiers() & alphaLock;
253 }
254
255 void PlatformKeyboardEvent::getCurrentModifierState(bool& shiftKey, bool& ctrlKey, bool& altKey, bool& metaKey)
256 {
257     UInt32 currentModifiers = GetCurrentKeyModifiers();
258     shiftKey = currentModifiers & ::shiftKey;
259     ctrlKey = currentModifiers & ::controlKey;
260     altKey = currentModifiers & ::optionKey;
261     metaKey = currentModifiers & ::cmdKey;
262 }
263
264 }
265
266 #endif // PLATFORM(MAC)