1// Copyright 2010-2018, Google Inc. 2// 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 are 6// met: 7// 8// * Redistributions of source code must retain the above copyright 9// notice, this list of conditions and the following disclaimer. 10// * Redistributions in binary form must reproduce the above 11// copyright notice, this list of conditions and the following disclaimer 12// in the documentation and/or other materials provided with the 13// distribution. 14// * Neither the name of Google Inc. nor the names of its 15// contributors may be used to endorse or promote products derived from 16// this software without specific prior written permission. 17// 18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30#import "mac/KeyCodeMap.h" 31 32#import <Carbon/Carbon.h> 33#import <Cocoa/Cocoa.h> 34 35#include "protocol/commands.pb.h" 36#include "testing/base/public/googletest.h" 37#include "testing/base/public/gunit.h" 38 39using mozc::commands::KeyEvent; 40 41struct TestCase { 42 string title; 43 NSString *characters; 44 NSString *unmodCharacters; 45 int flags; 46 uint16 keyCode; 47 string expected; 48}; 49 50class KeyCodeMapTest : public testing::Test { 51 protected: 52 void SetUp() { 53 pool_ = [[NSAutoreleasePool alloc] init]; 54 keyCodeMap_ = [[[KeyCodeMap alloc] init] autorelease]; 55 } 56 57 void TearDown() { 58 [pool_ drain]; 59 } 60 61 void KanaMode() { 62 keyCodeMap_.inputMode = KANA; 63 } 64 65 bool CreateKeyEvent(NSString *characters, NSString *unmodCharacters, 66 int flags, uint16 keyCode, KeyEvent *mozcKeyEvent) { 67 if (mozcKeyEvent == nullptr) { 68 return false; 69 } 70 71 NSEventType type = NSKeyDown; 72 // if the key event is just pressing modifiers, the type should be 73 // NSFlagsChanged. 74 if (characters == nil && unmodCharacters == nil) { 75 type = NSFlagsChanged; 76 } 77 78 if (characters == nil) { 79 characters = @""; 80 } 81 if (unmodCharacters == nil) { 82 unmodCharacters = [[characters copy] autorelease]; 83 } 84 85 NSEvent *event = [NSEvent keyEventWithType:type 86 location:NSZeroPoint 87 modifierFlags:flags 88 timestamp:0.0 89 windowNumber:0 90 context:nil 91 characters:characters 92 charactersIgnoringModifiers:unmodCharacters 93 isARepeat:NO 94 keyCode:keyCode]; 95 return [keyCodeMap_ getMozcKeyCodeFromKeyEvent:event 96 toMozcKeyEvent:mozcKeyEvent]; 97 } 98 99 bool CreateKeyEventFromTestCase(const TestCase &testCase, 100 KeyEvent *mozcKeyEvent) { 101 return CreateKeyEvent(testCase.characters, testCase.unmodCharacters, 102 testCase.flags, testCase.keyCode, mozcKeyEvent); 103 } 104 105 private: 106 NSAutoreleasePool *pool_; 107 KeyCodeMap *keyCodeMap_; 108}; 109 110static const TestCase kKeyEventTestCases[] = { 111 { "normal a", @"a", nil, 0, kVK_ANSI_A, "key_code: 97\n" }, 112 { "\\S-a", @"A", @"a", NSShiftKeyMask, kVK_ANSI_A, "key_code: 65\n" }, 113 { "\\C-a", @"\x01", @"a", NSControlKeyMask, kVK_ANSI_A, 114 "key_code: 97\n" 115 "modifier_keys: CTRL\n" 116 }, 117 { "\\S-C-a", @"a", nil, NSControlKeyMask | NSShiftKeyMask, kVK_ANSI_A, 118 "key_code: 97\n" 119 "modifier_keys: SHIFT\n" 120 "modifier_keys: CTRL\n" 121 }, 122 { "Tab key", @"\x09", nil, 0, kVK_Tab, "special_key: TAB\n" }, 123 { "\\S-Tab", @"\x09", nil, NSShiftKeyMask, kVK_Tab, 124 "special_key: TAB\n" 125 "modifier_keys: SHIFT\n" 126 }, 127 { "function key", @"\x10", nil, 0, kVK_F1, "special_key: F1\n" }, 128 { "tenkey", @"0", nil, 0, kVK_ANSI_Keypad0, "special_key: NUMPAD0\n" } 129}; 130 131static const TestCase kKanaTypingTestCases[] = { 132 { "a -> ち", @"a", nil, 0, kVK_ANSI_A, 133 "key_code: 97\n" 134 "key_string: \"\\343\\201\\241\"\n" 135 }, 136 { "yen mark", @"¥", nil, 0, kVK_JIS_Yen, 137 "key_code: 92\n" 138 "key_string: \"\\343\\203\\274\"\n" 139 }, 140 { "\\S-2 -> ふ", @"@", @"2", NSShiftKeyMask, kVK_ANSI_2, 141 "key_code: 64\n" 142 "key_string: \"\\343\\201\\265\"\n" 143 }, 144 { "\\C-a -> \\C-a", @"\x01", @"a", NSControlKeyMask, kVK_ANSI_A, 145 "key_code: 97\n" 146 "modifier_keys: CTRL\n" 147 "key_string: \"\\343\\201\\241\"\n" 148 }, 149 { "\\S-0 -> を", @"0", nil, NSShiftKeyMask, kVK_ANSI_0, 150 "key_code: 48\n" 151 "key_string: \"\\343\\202\\222\"\n" 152 }, 153 { "yen mark -> ー", @"¥", nil, 0, kVK_JIS_Yen, 154 "key_string: \"\\343\\203\\274\"\n" 155 }, 156 { "underscore -> ろ", @"_", nil, 0, kVK_JIS_Underscore, 157 "key_code: 95\n" 158 "key_string: \"\\343\\202\\215\"\n" 159 }, 160 { "@ -> ゛ in JIS keyboard", @"@", nil, 0, kVK_ANSI_LeftBracket, 161 "key_code: 64\n" 162 "key_string: \"\\343\\202\\233\"\n" 163 }, 164 { "[ -> ゛ in US keyboard", @"[", nil, 0, kVK_ANSI_LeftBracket, 165 "key_code: 91\n" 166 "key_string: \"\\343\\202\\233\"\n" 167 }, 168}; 169 170// Test for romaji typing 171TEST_F(KeyCodeMapTest, NormaKeyEvent) { 172 KeyEvent event; 173 for (int i = 0; i < arraysize(kKeyEventTestCases); ++i) { 174 const TestCase &testCase = kKeyEventTestCases[i]; 175 event.Clear(); 176 EXPECT_TRUE(CreateKeyEventFromTestCase(testCase, &event)); 177 EXPECT_EQ(testCase.expected, event.DebugString()) << testCase.title; 178 } 179} 180 181// Test for kana typing 182TEST_F(KeyCodeMapTest, KanaEvent) { 183 KanaMode(); 184 KeyEvent event; 185 for (int i = 0; i < arraysize(kKanaTypingTestCases); ++i) { 186 const TestCase &testCase = kKanaTypingTestCases[i]; 187 event.Clear(); 188 EXPECT_TRUE(CreateKeyEventFromTestCase(testCase, &event)); 189 EXPECT_EQ(testCase.expected, event.DebugString()) << testCase.title; 190 } 191} 192 193// Test for modifier key events 194TEST_F(KeyCodeMapTest, Modifiers) { 195 KeyEvent event; 196 TestCase testCase; 197 // Press shift key 198 EXPECT_FALSE(CreateKeyEvent(nil, nil, NSShiftKeyMask, kVK_Shift, &event)); 199 200 // Release the shift key -> emit Shift-key event 201 event.Clear(); 202 EXPECT_TRUE(CreateKeyEvent(nil, nil, 0, kVK_Shift, &event)); 203 EXPECT_EQ("modifier_keys: SHIFT\n", event.DebugString()); 204 205 // Press shift key 206 event.Clear(); 207 EXPECT_FALSE(CreateKeyEvent(nil, nil, NSShiftKeyMask, kVK_Shift, &event)); 208 209 // Press control key 210 event.Clear(); 211 EXPECT_FALSE(CreateKeyEvent( 212 nil, nil, NSShiftKeyMask | NSControlKeyMask, kVK_Control, &event)); 213 214 // Release shift key 215 event.Clear(); 216 EXPECT_FALSE(CreateKeyEvent(nil, nil, NSControlKeyMask, kVK_Control, &event)); 217 218 // Release control key -> emit Control + Shift 219 event.Clear(); 220 EXPECT_TRUE(CreateKeyEvent(nil, nil, 0, kVK_Control, &event)); 221 EXPECT_EQ("modifier_keys: SHIFT\nmodifier_keys: CTRL\n", event.DebugString()); 222 223 // Press control key 224 event.Clear(); 225 EXPECT_FALSE(CreateKeyEvent(nil, nil, NSControlKeyMask, kVK_Control, &event)); 226 227 // Press a -> emit \C-a 228 event.Clear(); 229 EXPECT_TRUE(CreateKeyEvent(@"a", nil, NSControlKeyMask, kVK_ANSI_A, &event)); 230 EXPECT_EQ("key_code: 97\nmodifier_keys: CTRL\n", event.DebugString()); 231 232 // Release control key -> Doesn't emit any key events 233 event.Clear(); 234 EXPECT_FALSE(CreateKeyEvent(nil, nil, 0, kVK_Control, &event)); 235} 236