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 #include "session/random_keyevents_generator.h"
31 
32 #include <string>
33 #include <vector>
34 
35 #include "base/logging.h"
36 #include "base/mutex.h"
37 #include "base/port.h"
38 #include "base/util.h"
39 #include "protocol/commands.pb.h"
40 
41 namespace mozc {
42 namespace session {
43 namespace {
44 
45 #include "session/session_stress_test_data.h"
46 
47 // Constants for ProbableKeyEvent.
48 const double kMostPossibleKeyProbability = 0.98;
49 const size_t kProbableKeyEventSize = 8;
50 
51 const commands::KeyEvent::SpecialKey kSpecialKeys[] = {
52   commands::KeyEvent::SPACE,
53   commands::KeyEvent::BACKSPACE,
54   commands::KeyEvent::DEL,
55   commands::KeyEvent::DOWN,
56   commands::KeyEvent::END,
57   commands::KeyEvent::ENTER,
58   commands::KeyEvent::ESCAPE,
59   commands::KeyEvent::HOME,
60   commands::KeyEvent::INSERT,
61   commands::KeyEvent::HENKAN,
62   commands::KeyEvent::MUHENKAN,
63   commands::KeyEvent::LEFT,
64   commands::KeyEvent::RIGHT,
65   commands::KeyEvent::UP,
66   commands::KeyEvent::DOWN,
67   commands::KeyEvent::PAGE_UP,
68   commands::KeyEvent::PAGE_DOWN,
69   commands::KeyEvent::TAB,
70   commands::KeyEvent::F1,
71   commands::KeyEvent::F2,
72   commands::KeyEvent::F3,
73   commands::KeyEvent::F4,
74   commands::KeyEvent::F5,
75   commands::KeyEvent::F6,
76   commands::KeyEvent::F7,
77   commands::KeyEvent::F8,
78   commands::KeyEvent::F9,
79   commands::KeyEvent::F10,
80   commands::KeyEvent::F11,
81   commands::KeyEvent::F12,
82   commands::KeyEvent::NUMPAD0,
83   commands::KeyEvent::NUMPAD1,
84   commands::KeyEvent::NUMPAD2,
85   commands::KeyEvent::NUMPAD3,
86   commands::KeyEvent::NUMPAD4,
87   commands::KeyEvent::NUMPAD5,
88   commands::KeyEvent::NUMPAD6,
89   commands::KeyEvent::NUMPAD7,
90   commands::KeyEvent::NUMPAD8,
91   commands::KeyEvent::NUMPAD9,
92   commands::KeyEvent::MULTIPLY,
93   commands::KeyEvent::ADD,
94   commands::KeyEvent::SEPARATOR,
95   commands::KeyEvent::SUBTRACT,
96   commands::KeyEvent::DECIMAL,
97   commands::KeyEvent::DIVIDE,
98   commands::KeyEvent::EQUALS,
99   commands::KeyEvent::COMMA,
100 };
101 
GetRandomAsciiKey()102 uint32 GetRandomAsciiKey() {
103   return static_cast<uint32>(' ') +
104       Util::Random(static_cast<uint32>('~' - ' '));
105 }
106 
InitSeedWithRandomValue()107 void InitSeedWithRandomValue() {
108   uint32 seed = 0;
109   mozc::Util::GetRandomSequence(reinterpret_cast<char *>(&seed), sizeof(seed));
110   Util::SetRandomSeed(seed);
111 }
112 
DoNothing()113 void DoNothing() {
114   // Do nothing.
115   // Used only for marking the seed initialized.
116 }
117 
118 once_t seed_init_once = MOZC_ONCE_INIT;
119 }  // namespace
120 
PrepareForMemoryLeakTest()121 void RandomKeyEventsGenerator::PrepareForMemoryLeakTest() {
122   // Read all kTestSentences and load these to memory.
123   const int size = arraysize(kTestSentences);
124   for (int i = 0; i < size; ++i) {
125     const char *sentence = kTestSentences[i];
126     CHECK_GT(strlen(sentence), 0);
127   }
128 }
129 
130 // Generates KeyEvent instances based on |romaji| and stores into |keys|.
TypeRawKeys(StringPiece romaji,bool create_probable_key_events,std::vector<commands::KeyEvent> * keys)131 void TypeRawKeys(StringPiece romaji, bool create_probable_key_events,
132                  std::vector<commands::KeyEvent> *keys) {
133   for (ConstChar32Iterator iter(romaji); !iter.Done(); iter.Next()) {
134     const uint32 ucs4 = iter.Get();
135     if (ucs4 < 0x20 || ucs4 > 0x7F) {
136       continue;
137     }
138     commands::KeyEvent key;
139     key.set_key_code(ucs4);
140     if (create_probable_key_events) {
141       commands::KeyEvent::ProbableKeyEvent *probable_key_event =
142           key.add_probable_key_event();
143         probable_key_event->set_key_code(ucs4);
144         probable_key_event->set_probability(kMostPossibleKeyProbability);
145       for (size_t i = 0; i < kProbableKeyEventSize; ++i) {
146         commands::KeyEvent::ProbableKeyEvent *probable_key_event =
147             key.add_probable_key_event();
148         probable_key_event->set_key_code(0x20 + Util::Random(0x7F - 0x20));
149         probable_key_event->set_probability(
150             (1.0 - kMostPossibleKeyProbability) / kProbableKeyEventSize);
151       }
152     }
153     keys->push_back(key);
154   }
155 }
156 
157 // Converts from Hiragana to Romaji.
ToRomaji(StringPiece hiragana)158 string ToRomaji(StringPiece hiragana) {
159   string tmp, result;
160   Util::HiraganaToRomanji(hiragana, &tmp);
161   Util::FullWidthToHalfWidth(tmp, &result);
162   return result;
163 }
164 
InitSeed(uint32 seed)165 void RandomKeyEventsGenerator::InitSeed(uint32 seed) {
166   Util::SetRandomSeed(seed);
167   CallOnce(&seed_init_once, &DoNothing);
168 }
169 
170 // Generates KeyEvent instances based on |sentence| and stores into |keys|.
171 // And Enter key event is appended at the tail.
172 // The instances have ProbableKeyEvent if |create_probable_key_events| is set.
GenerateMobileSequenceInternal(StringPiece sentence,bool create_probable_key_events,std::vector<commands::KeyEvent> * keys)173 void GenerateMobileSequenceInternal(
174     StringPiece sentence, bool create_probable_key_events,
175     std::vector<commands::KeyEvent> *keys) {
176   const string input = ToRomaji(sentence);
177   VLOG(1) << input;
178 
179   // Type the sentence
180   TypeRawKeys(input, create_probable_key_events, keys);
181 
182   commands::KeyEvent key;
183   key.set_special_key(commands::KeyEvent::ENTER);
184   keys->push_back(key);
185 }
186 
GenerateMobileSequence(bool create_probable_key_events,std::vector<commands::KeyEvent> * keys)187 void RandomKeyEventsGenerator::GenerateMobileSequence(
188     bool create_probable_key_events, std::vector<commands::KeyEvent> *keys) {
189   CHECK(keys);
190   keys->clear();
191 
192   // If seed was not initialized, set seed randomly.
193   CallOnce(&seed_init_once, &InitSeedWithRandomValue);
194 
195   const StringPiece sentence(
196       kTestSentences[Util::Random(arraysize(kTestSentences))]);
197   CHECK(!sentence.empty());
198   for (size_t i = 0; i < sentence.size(); ) {
199     // To simulate mobile key events, split given sentence into smaller parts.
200     // Average 5, Min 1, Max 15
201     const size_t len = Util::Random(5) + Util::Random(5) + Util::Random(5);
202     GenerateMobileSequenceInternal(ClippedSubstr(sentence, i, len),
203                                    create_probable_key_events, keys);
204     i += len;
205   }
206 }
207 
GenerateSequence(std::vector<commands::KeyEvent> * keys)208 void RandomKeyEventsGenerator::GenerateSequence(
209     std::vector<commands::KeyEvent> *keys) {
210   CHECK(keys);
211   keys->clear();
212 
213   // If seed was not initialized, set seed randomly.
214   CallOnce(&seed_init_once, &InitSeedWithRandomValue);
215 
216   const string sentence =
217       kTestSentences[Util::Random(arraysize(kTestSentences))];
218   CHECK(!sentence.empty());
219 
220   const string input = ToRomaji(sentence);
221 
222   VLOG(1) << input;
223 
224   // Must send ON event first.
225   {
226     commands::KeyEvent key;
227     key.set_special_key(commands::KeyEvent::ON);
228     keys->push_back(key);
229   }
230 
231   std::vector<commands::KeyEvent> basic_keys;
232 
233   // generate basic input
234   TypeRawKeys(input, false, &basic_keys);
235 
236   // basic keys + conversion
237   {
238     for (size_t i = 0; i < basic_keys.size(); ++i) {
239       keys->push_back(basic_keys[i]);
240     }
241 
242     for (int i = 0; i < 5; ++i) {
243       const size_t num = Util::Random(30) + 8;
244       for (size_t j = 0; j < num; ++j) {
245         commands::KeyEvent key;
246         key.set_special_key(commands::KeyEvent::SPACE);
247         if (Util::Random(4) == 0) {
248           key.add_modifier_keys(commands::KeyEvent::SHIFT);
249           keys->push_back(key);
250         }
251       }
252       commands::KeyEvent key;
253       key.set_special_key(commands::KeyEvent::RIGHT);
254       keys->push_back(key);
255     }
256 
257     commands::KeyEvent key;
258     key.set_special_key(commands::KeyEvent::ENTER);
259     keys->push_back(key);
260   }
261 
262   // segment resize
263   {
264     for (size_t i = 0; i < basic_keys.size(); ++i) {
265       keys->push_back(basic_keys[i]);
266     }
267 
268     const size_t num = Util::Random(30) + 10;
269     for (size_t i = 0; i < num; ++i) {
270       commands::KeyEvent key;
271       switch (Util::Random(4)) {
272         case 0:
273           key.set_special_key(commands::KeyEvent::LEFT);
274           if (Util::Random(2) == 0) {
275             key.add_modifier_keys(commands::KeyEvent::SHIFT);
276           }
277           break;
278         case 1:
279           key.set_special_key(commands::KeyEvent::RIGHT);
280           if (Util::Random(2) == 0) {
281             key.add_modifier_keys(commands::KeyEvent::SHIFT);
282           }
283           break;
284         default:
285           {
286             const size_t space_num = Util::Random(20) + 3;
287             for (size_t i = 0; i < space_num; ++i) {
288               key.set_special_key(commands::KeyEvent::SPACE);
289               keys->push_back(key);
290             }
291           }
292           break;
293       }
294 
295       if (Util::Random(4) == 0) {
296         key.add_modifier_keys(commands::KeyEvent::CTRL);
297       }
298 
299       if (Util::Random(10) == 0) {
300         key.add_modifier_keys(commands::KeyEvent::ALT);
301       }
302 
303       keys->push_back(key);
304     }
305 
306     commands::KeyEvent key;
307     key.set_special_key(commands::KeyEvent::ENTER);
308     keys->push_back(key);
309   }
310 
311   // insert + delete
312   {
313     for (size_t i = 0; i < basic_keys.size(); ++i) {
314       keys->push_back(basic_keys[i]);
315     }
316 
317     const size_t num = Util::Random(20) + 10;
318     for (size_t i = 0; i < num; ++i) {
319       commands::KeyEvent key;
320       switch (Util::Random(5)) {
321         case 0:
322           key.set_special_key(commands::KeyEvent::LEFT);
323           break;
324         case 1:
325           key.set_special_key(commands::KeyEvent::RIGHT);
326           break;
327         case 2:
328           key.set_special_key(commands::KeyEvent::DEL);
329           break;
330         case 3:
331           key.set_special_key(commands::KeyEvent::BACKSPACE);
332           break;
333         default:
334           {
335             // add any ascii
336             const size_t insert_num = Util::Random(5) + 1;
337             for (size_t i = 0; i < insert_num; ++i) {
338               key.set_key_code(GetRandomAsciiKey());
339             }
340           }
341       }
342       keys->push_back(key);
343     }
344 
345     commands::KeyEvent key;
346     key.set_special_key(commands::KeyEvent::ENTER);
347     keys->push_back(key);
348   }
349 
350   // basic keys + modifiers
351   {
352     for (size_t i = 0; i < basic_keys.size(); ++i) {
353       commands::KeyEvent key;
354       switch (Util::Random(8)) {
355         case 0:
356           key.set_key_code(kSpecialKeys[Util::Random(arraysize(kSpecialKeys))]);
357           break;
358         case 1:
359           key.set_key_code(GetRandomAsciiKey());
360           break;
361         default:
362           key.CopyFrom(basic_keys[i]);
363           break;
364       }
365 
366       if (Util::Random(10) == 0) {  // 10%
367         key.add_modifier_keys(commands::KeyEvent::CTRL);
368       }
369 
370       if (Util::Random(10) == 0) {  // 10%
371         key.add_modifier_keys(commands::KeyEvent::SHIFT);
372       }
373 
374       if (Util::Random(50) == 0) {  // 2%
375         key.add_modifier_keys(commands::KeyEvent::KEY_DOWN);
376       }
377 
378       if (Util::Random(50) == 0) {  // 2%
379         key.add_modifier_keys(commands::KeyEvent::KEY_UP);
380       }
381 
382       keys->push_back(key);
383     }
384 
385     // submit
386     commands::KeyEvent key;
387     key.set_special_key(commands::KeyEvent::ENTER);
388     keys->push_back(key);
389   }
390 
391   CHECK_GT(keys->size(), 0);
392   VLOG(1) << "key sequence is generated: " << keys->size();
393 }
394 
395 // static
GetTestSentences(size_t * size)396 const char **RandomKeyEventsGenerator::GetTestSentences(size_t *size) {
397   *size = arraysize(kTestSentences);
398   return kTestSentences;
399 }
400 }  // namespace session
401 }  // namespace mozc
402