Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Side by Side Diff: ui/base/ime/character_composer.cc

Issue 15816003: Supports unicode composition(Ctrl+Shift+U) with C-S pressed. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added a TODO. Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/base/ime/character_composer.h ('k') | ui/base/ime/character_composer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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"
19 #include "ui/base/x/x11_util.h"
17 20
18 // Note for Gtk removal: gtkimcontextsimpleseqs.h does not #include any Gtk 21 // Note for Gtk removal: gtkimcontextsimpleseqs.h does not #include any Gtk
19 // headers and only contains one big guint16 array |gtk_compose_seqs_compact| 22 // headers and only contains one big guint16 array |gtk_compose_seqs_compact|
20 // which defines the main compose table. The table has internal linkage. 23 // which defines the main compose table. The table has internal linkage.
21 // The order of header inclusion is out of order because 24 // The order of header inclusion is out of order because
22 // gtkimcontextsimpleseqs.h depends on guint16, which is defined in 25 // gtkimcontextsimpleseqs.h depends on guint16, which is defined in
23 // "ui/base/glib/glib_integers.h". 26 // "ui/base/glib/glib_integers.h".
24 #include "third_party/gtk+/gtk/gtkimcontextsimpleseqs.h" 27 #include "third_party/gtk+/gtk/gtkimcontextsimpleseqs.h"
25 28
26 namespace { 29 namespace {
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 if (!CBU_IS_UNICODE_CHAR(character)) 345 if (!CBU_IS_UNICODE_CHAR(character))
343 return false; 346 return false;
344 if (character) { 347 if (character) {
345 output->resize(CBU16_LENGTH(character)); 348 output->resize(CBU16_LENGTH(character));
346 size_t i = 0; 349 size_t i = 0;
347 CBU16_APPEND_UNSAFE(&(*output)[0], i, character); 350 CBU16_APPEND_UNSAFE(&(*output)[0], i, character);
348 } 351 }
349 return true; 352 return true;
350 } 353 }
351 354
355 // Converts a X keycode to a X keysym with no modifiers.
356 KeySym XKeyCodeToXKeySym(unsigned int keycode) {
357 Display* display = ui::GetXDisplay();
358 if (!display)
359 return NoSymbol;
360
361 XKeyEvent x_key_event = {0};
362 x_key_event.type = KeyPress;
363 x_key_event.display = display;
364 x_key_event.keycode = keycode;
365 return ::XLookupKeysym(&x_key_event, 0);
366 }
367
352 // Returns an hexadecimal digit integer (0 to 15) corresponding to |keyval|. 368 // Returns an hexadecimal digit integer (0 to 15) corresponding to |keyval|.
353 // -1 is returned when |keyval| cannot be a hexadecimal digit. 369 // -1 is returned when |keyval| cannot be a hexadecimal digit.
354 int KeyvalToHexDigit(unsigned int keyval) { 370 int KeyvalToHexDigit(unsigned int keyval) {
355 if (GDK_KEY_0 <= keyval && keyval <= GDK_KEY_9) 371 if (GDK_KEY_0 <= keyval && keyval <= GDK_KEY_9)
356 return keyval - GDK_KEY_0; 372 return keyval - GDK_KEY_0;
357 if (GDK_KEY_a <= keyval && keyval <= GDK_KEY_f) 373 if (GDK_KEY_a <= keyval && keyval <= GDK_KEY_f)
358 return keyval - GDK_KEY_a + 10; 374 return keyval - GDK_KEY_a + 10;
359 if (GDK_KEY_A <= keyval && keyval <= GDK_KEY_F) 375 if (GDK_KEY_A <= keyval && keyval <= GDK_KEY_F)
360 return keyval - GDK_KEY_A + 10; 376 return keyval - GDK_KEY_A + 10;
361 return -1; // |keyval| cannot be a hexadecimal digit. 377 return -1; // |keyval| cannot be a hexadecimal digit.
362 } 378 }
363 379
364 } // namespace 380 } // namespace
365 381
366 namespace ui { 382 namespace ui {
367 383
368 CharacterComposer::CharacterComposer() : composition_mode_(KEY_SEQUENCE_MODE) {} 384 CharacterComposer::CharacterComposer() : composition_mode_(KEY_SEQUENCE_MODE) {}
369 385
370 CharacterComposer::~CharacterComposer() {} 386 CharacterComposer::~CharacterComposer() {}
371 387
372 void CharacterComposer::Reset() { 388 void CharacterComposer::Reset() {
373 compose_buffer_.clear(); 389 compose_buffer_.clear();
374 composed_character_.clear(); 390 composed_character_.clear();
375 preedit_string_.clear(); 391 preedit_string_.clear();
376 composition_mode_ = KEY_SEQUENCE_MODE; 392 composition_mode_ = KEY_SEQUENCE_MODE;
377 } 393 }
378 394
379 bool CharacterComposer::FilterKeyPress(unsigned int keyval, 395 bool CharacterComposer::FilterKeyPress(unsigned int keyval,
380 unsigned int flags) { 396 unsigned int keycode,
397 int flags) {
381 composed_character_.clear(); 398 composed_character_.clear();
382 preedit_string_.clear(); 399 preedit_string_.clear();
383 400
384 // We don't care about modifier key presses. 401 // We don't care about modifier key presses.
385 if(KeypressShouldBeIgnored(keyval)) 402 if(KeypressShouldBeIgnored(keyval))
386 return false; 403 return false;
387 404
388 // When the user presses Ctrl+Shift+U, maybe switch to HEX_MODE. 405 // 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 406 // 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). 407 // do nothing because what we receive is Ctrl+Shift+u (not U).
391 if (keyval == GDK_KEY_U && (flags & EF_SHIFT_DOWN) && 408 if (keyval == GDK_KEY_U && (flags & EF_SHIFT_DOWN) &&
392 (flags & EF_CONTROL_DOWN)) { 409 (flags & EF_CONTROL_DOWN)) {
393 if (composition_mode_ == KEY_SEQUENCE_MODE && compose_buffer_.empty()) { 410 if (composition_mode_ == KEY_SEQUENCE_MODE && compose_buffer_.empty()) {
394 // There is no ongoing composition. Let's switch to HEX_MODE. 411 // There is no ongoing composition. Let's switch to HEX_MODE.
395 composition_mode_ = HEX_MODE; 412 composition_mode_ = HEX_MODE;
396 UpdatePreeditStringHexMode(); 413 UpdatePreeditStringHexMode();
397 return true; 414 return true;
398 } 415 }
399 } 416 }
400 417
401 // Filter key press in an appropriate manner. 418 // Filter key press in an appropriate manner.
402 switch (composition_mode_) { 419 switch (composition_mode_) {
403 case KEY_SEQUENCE_MODE: 420 case KEY_SEQUENCE_MODE:
404 return FilterKeyPressSequenceMode(keyval, flags); 421 return FilterKeyPressSequenceMode(keyval, keycode, flags);
405 case HEX_MODE: 422 case HEX_MODE:
406 return FilterKeyPressHexMode(keyval, flags); 423 return FilterKeyPressHexMode(keyval, keycode, flags);
407 default: 424 default:
408 NOTREACHED(); 425 NOTREACHED();
409 return false; 426 return false;
410 } 427 }
411 } 428 }
412 429
413 bool CharacterComposer::FilterKeyPressSequenceMode(unsigned int keyval, 430 bool CharacterComposer::FilterKeyPressSequenceMode(unsigned int keyval,
414 unsigned int flags) { 431 unsigned int keycode,
432 int flags) {
415 DCHECK(composition_mode_ == KEY_SEQUENCE_MODE); 433 DCHECK(composition_mode_ == KEY_SEQUENCE_MODE);
416 compose_buffer_.push_back(keyval); 434 compose_buffer_.push_back(keyval);
417 435
418 // Check compose table. 436 // Check compose table.
419 uint32 composed_character_utf32 = 0; 437 uint32 composed_character_utf32 = 0;
420 if (CheckCharacterComposeTable(compose_buffer_, &composed_character_utf32)) { 438 if (CheckCharacterComposeTable(compose_buffer_, &composed_character_utf32)) {
421 // Key press is recognized as a part of composition. 439 // Key press is recognized as a part of composition.
422 if (composed_character_utf32 != 0) { 440 if (composed_character_utf32 != 0) {
423 // We get a composed character. 441 // We get a composed character.
424 compose_buffer_.clear(); 442 compose_buffer_.clear();
425 UTF32CharacterToUTF16(composed_character_utf32, &composed_character_); 443 UTF32CharacterToUTF16(composed_character_utf32, &composed_character_);
426 } 444 }
427 return true; 445 return true;
428 } 446 }
429 // Key press is not a part of composition. 447 // Key press is not a part of composition.
430 compose_buffer_.pop_back(); // Remove the keypress added this time. 448 compose_buffer_.pop_back(); // Remove the keypress added this time.
431 if (!compose_buffer_.empty()) { 449 if (!compose_buffer_.empty()) {
432 compose_buffer_.clear(); 450 compose_buffer_.clear();
433 return true; 451 return true;
434 } 452 }
435 return false; 453 return false;
436 } 454 }
437 455
438 bool CharacterComposer::FilterKeyPressHexMode(unsigned int keyval, 456 bool CharacterComposer::FilterKeyPressHexMode(unsigned int keyval,
439 unsigned int flags) { 457 unsigned int keycode,
458 int flags) {
440 DCHECK(composition_mode_ == HEX_MODE); 459 DCHECK(composition_mode_ == HEX_MODE);
441 const size_t kMaxHexSequenceLength = 8; 460 const size_t kMaxHexSequenceLength = 8;
442 const int hex_digit = KeyvalToHexDigit(keyval); 461 int hex_digit = KeyvalToHexDigit(keyval);
462 if (hex_digit < 0) {
463 // With 101 keyboard, control + shift + 3 produces '#', but a user may
464 // have intended to type '3'. So, if a hexadecimal character was not found,
465 // suppose a user is holding shift key (and possibly control key, too) and
466 // try a character with modifier keys removed.
467 hex_digit = KeyvalToHexDigit(XKeyCodeToXKeySym(keycode));
468 }
443 469
444 if (keyval == GDK_KEY_Escape) { 470 if (keyval == GDK_KEY_Escape) {
445 // Cancel composition when ESC is pressed. 471 // Cancel composition when ESC is pressed.
446 Reset(); 472 Reset();
447 } else if (keyval == GDK_KEY_Return || keyval == GDK_KEY_KP_Enter || 473 } else if (keyval == GDK_KEY_Return || keyval == GDK_KEY_KP_Enter ||
448 keyval == GDK_KEY_ISO_Enter || 474 keyval == GDK_KEY_ISO_Enter ||
449 keyval == GDK_KEY_space || keyval == GDK_KEY_KP_Space) { 475 keyval == GDK_KEY_space || keyval == GDK_KEY_KP_Space) {
450 // Commit the composed character when Enter or space is pressed. 476 // Commit the composed character when Enter or space is pressed.
451 CommitHex(); 477 CommitHex();
452 } else if (keyval == GDK_KEY_BackSpace) { 478 } else if (keyval == GDK_KEY_BackSpace) {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
489 std::string preedit_string_ascii("u"); 515 std::string preedit_string_ascii("u");
490 for (size_t i = 0; i != compose_buffer_.size(); ++i) { 516 for (size_t i = 0; i != compose_buffer_.size(); ++i) {
491 const int digit = compose_buffer_[i]; 517 const int digit = compose_buffer_[i];
492 DCHECK(0 <= digit && digit < 16); 518 DCHECK(0 <= digit && digit < 16);
493 preedit_string_ascii += digit <= 9 ? ('0' + digit) : ('a' + (digit - 10)); 519 preedit_string_ascii += digit <= 9 ? ('0' + digit) : ('a' + (digit - 10));
494 } 520 }
495 preedit_string_ = ASCIIToUTF16(preedit_string_ascii); 521 preedit_string_ = ASCIIToUTF16(preedit_string_ascii);
496 } 522 }
497 523
498 } // namespace ui 524 } // namespace ui
OLDNEW
« no previous file with comments | « ui/base/ime/character_composer.h ('k') | ui/base/ime/character_composer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698