keycode_text_conversion_mac.mm revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/test/chromedriver/keycode_text_conversion.h" 6 7#import <Carbon/Carbon.h> 8 9#include <cctype> 10 11#include "base/mac/scoped_cftyperef.h" 12#include "base/utf_string_conversions.h" 13#include "chrome/test/chromedriver/chrome/ui_events.h" 14#include "ui/base/keycodes/keyboard_code_conversion_mac.h" 15 16std::string ConvertKeyCodeToText(ui::KeyboardCode key_code, int modifiers) { 17 int mac_key_code = 0; 18 { 19 unichar character, unmodified_character; 20 mac_key_code = ui::MacKeyCodeForWindowsKeyCode( 21 key_code, 22 0, 23 &character, 24 &unmodified_character); 25 } 26 if (mac_key_code < 0) 27 return ""; 28 29 int mac_modifiers = 0; 30 if (modifiers & kShiftKeyModifierMask) 31 mac_modifiers |= shiftKey; 32 if (modifiers & kControlKeyModifierMask) 33 mac_modifiers |= controlKey; 34 if (modifiers & kAltKeyModifierMask) 35 mac_modifiers |= optionKey; 36 if (modifiers & kMetaKeyModifierMask) 37 mac_modifiers |= cmdKey; 38 // Convert EventRecord modifiers to format UCKeyTranslate accepts. See docs 39 // on UCKeyTranslate for more info. 40 UInt32 modifier_key_state = (mac_modifiers >> 8) & 0xFF; 41 42 base::mac::ScopedCFTypeRef<TISInputSourceRef> input_source_copy( 43 TISCopyCurrentKeyboardLayoutInputSource()); 44 CFDataRef layout_data = static_cast<CFDataRef>(TISGetInputSourceProperty( 45 input_source_copy, kTISPropertyUnicodeKeyLayoutData)); 46 47 UInt32 dead_key_state = 0; 48 UniCharCount char_count = 0; 49 UniChar character = 0; 50 OSStatus status = UCKeyTranslate( 51 reinterpret_cast<const UCKeyboardLayout*>(CFDataGetBytePtr(layout_data)), 52 static_cast<UInt16>(mac_key_code), 53 kUCKeyActionDown, 54 modifier_key_state, 55 LMGetKbdLast(), 56 kUCKeyTranslateNoDeadKeysBit, 57 &dead_key_state, 58 1, 59 &char_count, 60 &character); 61 if (status == noErr && char_count == 1 && !std::iscntrl(character)) { 62 string16 text; 63 text.push_back(character); 64 return UTF16ToUTF8(text); 65 } else { 66 return ""; 67 } 68} 69 70bool ConvertCharToKeyCode( 71 char16 key, ui::KeyboardCode* key_code, int *necessary_modifiers) { 72 string16 key_string; 73 key_string.push_back(key); 74 std::string key_string_utf8 = UTF16ToUTF8(key_string); 75 bool found_code = false; 76 // There doesn't seem to be a way to get a mac key code for a given unicode 77 // character. So here we check every key code to see if it produces the 78 // right character. We could cache the results and regenerate everytime the 79 // language changes, but this brute force technique has negligble performance 80 // effects (on my laptop it is a submillisecond difference). 81 for (int i = 0; i < 256; ++i) { 82 ui::KeyboardCode code = static_cast<ui::KeyboardCode>(i); 83 // Skip the numpad keys. 84 if (code >= ui::VKEY_NUMPAD0 && code <= ui::VKEY_DIVIDE) 85 continue; 86 found_code = key_string_utf8 == ConvertKeyCodeToText(code, 0); 87 if (!found_code && key_string_utf8 == ConvertKeyCodeToText( 88 code, kShiftKeyModifierMask)) { 89 *necessary_modifiers = kShiftKeyModifierMask; 90 found_code = true; 91 } 92 if (found_code) { 93 *key_code = code; 94 break; 95 } 96 } 97 return found_code; 98} 99