OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/base/ime/character_composer.h" | 5 #include "ui/base/ime/character_composer.h" |
6 | 6 |
7 #include <X11/Xlib.h> | |
8 | |
7 #include <algorithm> | 9 #include <algorithm> |
8 #include <iterator> | 10 #include <iterator> |
9 | 11 |
10 #include "base/third_party/icu/icu_utf.h" | 12 #include "base/third_party/icu/icu_utf.h" |
11 #include "base/utf_string_conversions.h" | 13 #include "base/utf_string_conversions.h" |
12 // Note for Gtk removal: gdkkeysyms.h only contains a set of | 14 // Note for Gtk removal: gdkkeysyms.h only contains a set of |
13 // '#define GDK_KeyName 0xNNNN' macros and does not #include any Gtk headers. | 15 // '#define GDK_KeyName 0xNNNN' macros and does not #include any Gtk headers. |
14 #include "third_party/gtk+/gdk/gdkkeysyms.h" | 16 #include "third_party/gtk+/gdk/gdkkeysyms.h" |
15 #include "ui/base/events/event_constants.h" | 17 #include "ui/base/events/event_constants.h" |
16 #include "ui/base/glib/glib_integers.h" | 18 #include "ui/base/glib/glib_integers.h" |
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
342 if (!CBU_IS_UNICODE_CHAR(character)) | 344 if (!CBU_IS_UNICODE_CHAR(character)) |
343 return false; | 345 return false; |
344 if (character) { | 346 if (character) { |
345 output->resize(CBU16_LENGTH(character)); | 347 output->resize(CBU16_LENGTH(character)); |
346 size_t i = 0; | 348 size_t i = 0; |
347 CBU16_APPEND_UNSAFE(&(*output)[0], i, character); | 349 CBU16_APPEND_UNSAFE(&(*output)[0], i, character); |
348 } | 350 } |
349 return true; | 351 return true; |
350 } | 352 } |
351 | 353 |
354 // Converts a X keycode to a X keysym with no modifiers. | |
355 KeySym XKeyCodeToXKeySym(unsigned int keycode) { | |
356 Display* display = ::XOpenDisplay(NULL); | |
Seigo Nonaka
2013/05/23 08:19:21
How about using MessagePumpAuraForUI::GetDefaultXD
Yuki
2013/05/23 08:48:40
Done.
| |
357 if (!display) | |
358 return NoSymbol; | |
359 | |
360 XKeyEvent x_key_event = {0}; | |
361 x_key_event.type = KeyPress; | |
362 x_key_event.display = display; | |
363 x_key_event.keycode = keycode; | |
364 KeySym keysym = ::XLookupKeysym(&x_key_event, 0); | |
365 ::XCloseDisplay(display); | |
366 return keysym; | |
367 } | |
368 | |
352 // Returns an hexadecimal digit integer (0 to 15) corresponding to |keyval|. | 369 // Returns an hexadecimal digit integer (0 to 15) corresponding to |keyval|. |
353 // -1 is returned when |keyval| cannot be a hexadecimal digit. | 370 // -1 is returned when |keyval| cannot be a hexadecimal digit. |
354 int KeyvalToHexDigit(unsigned int keyval) { | 371 int KeyvalToHexDigit(unsigned int keyval) { |
355 if (GDK_KEY_0 <= keyval && keyval <= GDK_KEY_9) | 372 if (GDK_KEY_0 <= keyval && keyval <= GDK_KEY_9) |
356 return keyval - GDK_KEY_0; | 373 return keyval - GDK_KEY_0; |
357 if (GDK_KEY_a <= keyval && keyval <= GDK_KEY_f) | 374 if (GDK_KEY_a <= keyval && keyval <= GDK_KEY_f) |
358 return keyval - GDK_KEY_a + 10; | 375 return keyval - GDK_KEY_a + 10; |
359 if (GDK_KEY_A <= keyval && keyval <= GDK_KEY_F) | 376 if (GDK_KEY_A <= keyval && keyval <= GDK_KEY_F) |
360 return keyval - GDK_KEY_A + 10; | 377 return keyval - GDK_KEY_A + 10; |
361 return -1; // |keyval| cannot be a hexadecimal digit. | 378 return -1; // |keyval| cannot be a hexadecimal digit. |
362 } | 379 } |
363 | 380 |
364 } // namespace | 381 } // namespace |
365 | 382 |
366 namespace ui { | 383 namespace ui { |
367 | 384 |
368 CharacterComposer::CharacterComposer() : composition_mode_(KEY_SEQUENCE_MODE) {} | 385 CharacterComposer::CharacterComposer() : composition_mode_(KEY_SEQUENCE_MODE) {} |
369 | 386 |
370 CharacterComposer::~CharacterComposer() {} | 387 CharacterComposer::~CharacterComposer() {} |
371 | 388 |
372 void CharacterComposer::Reset() { | 389 void CharacterComposer::Reset() { |
373 compose_buffer_.clear(); | 390 compose_buffer_.clear(); |
374 composed_character_.clear(); | 391 composed_character_.clear(); |
375 preedit_string_.clear(); | 392 preedit_string_.clear(); |
376 composition_mode_ = KEY_SEQUENCE_MODE; | 393 composition_mode_ = KEY_SEQUENCE_MODE; |
377 } | 394 } |
378 | 395 |
379 bool CharacterComposer::FilterKeyPress(unsigned int keyval, | 396 bool CharacterComposer::FilterKeyPress(unsigned int keyval, |
380 unsigned int flags) { | 397 unsigned int keycode, |
398 int flags) { | |
381 composed_character_.clear(); | 399 composed_character_.clear(); |
382 preedit_string_.clear(); | 400 preedit_string_.clear(); |
383 | 401 |
384 // We don't care about modifier key presses. | 402 // We don't care about modifier key presses. |
385 if(KeypressShouldBeIgnored(keyval)) | 403 if(KeypressShouldBeIgnored(keyval)) |
386 return false; | 404 return false; |
387 | 405 |
388 // When the user presses Ctrl+Shift+U, maybe switch to HEX_MODE. | 406 // When the user presses Ctrl+Shift+U, maybe switch to HEX_MODE. |
389 // We don't care about other modifiers like Alt. When CapsLock is down, we | 407 // We don't care about other modifiers like Alt. When CapsLock is down, we |
390 // do nothing because what we receive is Ctrl+Shift+u (not U). | 408 // do nothing because what we receive is Ctrl+Shift+u (not U). |
391 if (keyval == GDK_KEY_U && (flags & EF_SHIFT_DOWN) && | 409 if (keyval == GDK_KEY_U && (flags & EF_SHIFT_DOWN) && |
392 (flags & EF_CONTROL_DOWN)) { | 410 (flags & EF_CONTROL_DOWN)) { |
393 if (composition_mode_ == KEY_SEQUENCE_MODE && compose_buffer_.empty()) { | 411 if (composition_mode_ == KEY_SEQUENCE_MODE && compose_buffer_.empty()) { |
394 // There is no ongoing composition. Let's switch to HEX_MODE. | 412 // There is no ongoing composition. Let's switch to HEX_MODE. |
395 composition_mode_ = HEX_MODE; | 413 composition_mode_ = HEX_MODE; |
396 UpdatePreeditStringHexMode(); | 414 UpdatePreeditStringHexMode(); |
397 return true; | 415 return true; |
398 } | 416 } |
399 } | 417 } |
400 | 418 |
401 // Filter key press in an appropriate manner. | 419 // Filter key press in an appropriate manner. |
402 switch (composition_mode_) { | 420 switch (composition_mode_) { |
403 case KEY_SEQUENCE_MODE: | 421 case KEY_SEQUENCE_MODE: |
404 return FilterKeyPressSequenceMode(keyval, flags); | 422 return FilterKeyPressSequenceMode(keyval, keycode, flags); |
405 case HEX_MODE: | 423 case HEX_MODE: |
406 return FilterKeyPressHexMode(keyval, flags); | 424 return FilterKeyPressHexMode(keyval, keycode, flags); |
407 default: | 425 default: |
408 NOTREACHED(); | 426 NOTREACHED(); |
409 return false; | 427 return false; |
410 } | 428 } |
411 } | 429 } |
412 | 430 |
413 bool CharacterComposer::FilterKeyPressSequenceMode(unsigned int keyval, | 431 bool CharacterComposer::FilterKeyPressSequenceMode(unsigned int keyval, |
414 unsigned int flags) { | 432 unsigned int keycode, |
433 int flags) { | |
415 DCHECK(composition_mode_ == KEY_SEQUENCE_MODE); | 434 DCHECK(composition_mode_ == KEY_SEQUENCE_MODE); |
416 compose_buffer_.push_back(keyval); | 435 compose_buffer_.push_back(keyval); |
417 | 436 |
418 // Check compose table. | 437 // Check compose table. |
419 uint32 composed_character_utf32 = 0; | 438 uint32 composed_character_utf32 = 0; |
420 if (CheckCharacterComposeTable(compose_buffer_, &composed_character_utf32)) { | 439 if (CheckCharacterComposeTable(compose_buffer_, &composed_character_utf32)) { |
421 // Key press is recognized as a part of composition. | 440 // Key press is recognized as a part of composition. |
422 if (composed_character_utf32 != 0) { | 441 if (composed_character_utf32 != 0) { |
423 // We get a composed character. | 442 // We get a composed character. |
424 compose_buffer_.clear(); | 443 compose_buffer_.clear(); |
425 UTF32CharacterToUTF16(composed_character_utf32, &composed_character_); | 444 UTF32CharacterToUTF16(composed_character_utf32, &composed_character_); |
426 } | 445 } |
427 return true; | 446 return true; |
428 } | 447 } |
429 // Key press is not a part of composition. | 448 // Key press is not a part of composition. |
430 compose_buffer_.pop_back(); // Remove the keypress added this time. | 449 compose_buffer_.pop_back(); // Remove the keypress added this time. |
431 if (!compose_buffer_.empty()) { | 450 if (!compose_buffer_.empty()) { |
432 compose_buffer_.clear(); | 451 compose_buffer_.clear(); |
433 return true; | 452 return true; |
434 } | 453 } |
435 return false; | 454 return false; |
436 } | 455 } |
437 | 456 |
438 bool CharacterComposer::FilterKeyPressHexMode(unsigned int keyval, | 457 bool CharacterComposer::FilterKeyPressHexMode(unsigned int keyval, |
439 unsigned int flags) { | 458 unsigned int keycode, |
459 int flags) { | |
440 DCHECK(composition_mode_ == HEX_MODE); | 460 DCHECK(composition_mode_ == HEX_MODE); |
441 const size_t kMaxHexSequenceLength = 8; | 461 const size_t kMaxHexSequenceLength = 8; |
442 const int hex_digit = KeyvalToHexDigit(keyval); | 462 int hex_digit = KeyvalToHexDigit(keyval); |
463 if (hex_digit < 0) { | |
464 // With 101 keyboard, control + shift + 3 produces '#', but a user may | |
465 // have intended to type '3'. So, if a hexadecimal character was not found, | |
466 // suppose a user is holding shift key (and possibly control key, too) and | |
467 // try a character with modifier keys removed. | |
468 hex_digit = KeyvalToHexDigit(XKeyCodeToXKeySym(keycode)); | |
469 } | |
443 | 470 |
444 if (keyval == GDK_KEY_Escape) { | 471 if (keyval == GDK_KEY_Escape) { |
445 // Cancel composition when ESC is pressed. | 472 // Cancel composition when ESC is pressed. |
446 Reset(); | 473 Reset(); |
447 } else if (keyval == GDK_KEY_Return || keyval == GDK_KEY_KP_Enter || | 474 } else if (keyval == GDK_KEY_Return || keyval == GDK_KEY_KP_Enter || |
448 keyval == GDK_KEY_ISO_Enter || | 475 keyval == GDK_KEY_ISO_Enter || |
449 keyval == GDK_KEY_space || keyval == GDK_KEY_KP_Space) { | 476 keyval == GDK_KEY_space || keyval == GDK_KEY_KP_Space) { |
450 // Commit the composed character when Enter or space is pressed. | 477 // Commit the composed character when Enter or space is pressed. |
451 CommitHex(); | 478 CommitHex(); |
452 } else if (keyval == GDK_KEY_BackSpace) { | 479 } else if (keyval == GDK_KEY_BackSpace) { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
489 std::string preedit_string_ascii("u"); | 516 std::string preedit_string_ascii("u"); |
490 for (size_t i = 0; i != compose_buffer_.size(); ++i) { | 517 for (size_t i = 0; i != compose_buffer_.size(); ++i) { |
491 const int digit = compose_buffer_[i]; | 518 const int digit = compose_buffer_[i]; |
492 DCHECK(0 <= digit && digit < 16); | 519 DCHECK(0 <= digit && digit < 16); |
493 preedit_string_ascii += digit <= 9 ? ('0' + digit) : ('a' + (digit - 10)); | 520 preedit_string_ascii += digit <= 9 ? ('0' + digit) : ('a' + (digit - 10)); |
494 } | 521 } |
495 preedit_string_ = ASCIIToUTF16(preedit_string_ascii); | 522 preedit_string_ = ASCIIToUTF16(preedit_string_ascii); |
496 } | 523 } |
497 | 524 |
498 } // namespace ui | 525 } // namespace ui |
OLD | NEW |