Chromium Code Reviews| 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 |