Skip to content

Commit

Permalink
Ozone keyboard layout
Browse files Browse the repository at this point in the history
This replaces core X11 XKB on Ozone, providing a platform-independent
interface mapping (DomCode, EventFlags) to (DomKey, character)
and KeyboardCode, and a layout set/property interface equivalent
to ImeKeyboard.

BUG=430194

Review URL: https://codereview.chromium.org/742103002

Cr-Commit-Position: refs/heads/master@{#308390}
  • Loading branch information
kpschoedel authored and Commit bot committed Dec 15, 2014
1 parent 9b3c1cb commit 763ff21
Show file tree
Hide file tree
Showing 37 changed files with 1,549 additions and 280 deletions.
2 changes: 2 additions & 0 deletions ui/events/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ component("events") {

if (use_ozone) {
sources += [ "ozone/events_ozone.cc" ]
deps += [ "//ui/events/ozone:events_ozone_layout" ]
}

if (use_aura) {
Expand Down Expand Up @@ -334,6 +335,7 @@ test("events_unittests") {
deps += [
"//ui/events/ozone:events_ozone",
"//ui/events/ozone:events_ozone_evdev",
"//ui/events/ozone:events_ozone_layout",
]
}

Expand Down
75 changes: 52 additions & 23 deletions ui/events/event.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "base/strings/stringprintf.h"
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/dom3/dom_code.h"
#include "ui/events/keycodes/dom3/dom_key.h"
#include "ui/events/keycodes/dom4/keycode_converter.h"
#include "ui/events/keycodes/keyboard_code_conversion.h"
#include "ui/gfx/geometry/safe_integer_conversions.h"
Expand All @@ -28,7 +29,8 @@
#if defined(USE_X11)
#include "ui/events/keycodes/keyboard_code_conversion_x.h"
#elif defined(USE_OZONE)
#include "ui/events/keycodes/keyboard_code_conversion.h"
#include "ui/events/ozone/layout/keyboard_layout_engine.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
#endif

namespace {
Expand Down Expand Up @@ -644,6 +646,7 @@ KeyEvent::KeyEvent(const base::NativeEvent& native_event)
code_(CodeFromNative(native_event)),
is_char_(IsCharFromNative(native_event)),
platform_keycode_(PlatformKeycodeFromNative(native_event)),
key_(DomKey::NONE),
character_(0) {
if (IsRepeated(*this))
set_flags(flags() | ui::EF_IS_REPEAT);
Expand All @@ -666,6 +669,7 @@ KeyEvent::KeyEvent(EventType type,
code_(DomCode::NONE),
is_char_(false),
platform_keycode_(0),
key_(DomKey::NONE),
character_() {
}

Expand All @@ -678,15 +682,32 @@ KeyEvent::KeyEvent(EventType type,
code_(code),
is_char_(false),
platform_keycode_(0),
key_(DomKey::NONE),
character_(0) {
}

KeyEvent::KeyEvent(EventType type,
KeyboardCode key_code,
DomCode code,
int flags,
DomKey key,
base::char16 character)
: Event(type, EventTimeForNow(), flags),
key_code_(key_code),
code_(code),
is_char_(false),
platform_keycode_(0),
key_(key),
character_(character) {
}

KeyEvent::KeyEvent(base::char16 character, KeyboardCode key_code, int flags)
: Event(ET_KEY_PRESSED, EventTimeForNow(), flags),
key_code_(key_code),
code_(DomCode::NONE),
is_char_(true),
platform_keycode_(0),
key_(DomKey::CHARACTER),
character_(character) {
}

Expand All @@ -696,6 +717,7 @@ KeyEvent::KeyEvent(const KeyEvent& rhs)
code_(rhs.code_),
is_char_(rhs.is_char_),
platform_keycode_(rhs.platform_keycode_),
key_(rhs.key_),
character_(rhs.character_) {
if (rhs.extended_key_event_data_)
extended_key_event_data_.reset(rhs.extended_key_event_data_->Clone());
Expand All @@ -706,6 +728,7 @@ KeyEvent& KeyEvent::operator=(const KeyEvent& rhs) {
Event::operator=(rhs);
key_code_ = rhs.key_code_;
code_ = rhs.code_;
key_ = rhs.key_;
is_char_ = rhs.is_char_;
platform_keycode_ = rhs.platform_keycode_;
character_ = rhs.character_;
Expand All @@ -722,48 +745,54 @@ void KeyEvent::SetExtendedKeyEventData(scoped_ptr<ExtendedKeyEventData> data) {
extended_key_event_data_ = data.Pass();
}

base::char16 KeyEvent::GetCharacter() const {
if (is_char_ || character_)
return character_;

// TODO(kpschoedel): streamline these cases after settling Ozone
// positional coding.
void KeyEvent::ApplyLayout() const {
#if defined(OS_WIN)
// Native Windows character events always have is_char_ == true,
// so this is a synthetic or native keystroke event.
character_ = GetCharacterFromKeyCode(key_code_, flags());
return character_;
// Therefore, perform only the fallback action.
GetMeaningFromKeyCode(key_code_, flags(), &key_, &character_);
#elif defined(USE_X11)
if (!native_event()) {
character_ = GetCharacterFromKeyCode(key_code_, flags());
return character_;
}

DCHECK(native_event()->type == KeyPress ||
native_event()->type == KeyRelease ||
(native_event()->type == GenericEvent &&
(native_event()->xgeneric.evtype == XI_KeyPress ||
native_event()->xgeneric.evtype == XI_KeyRelease)));

// When a control key is held, prefer ASCII characters to non ASCII
// characters in order to use it for shortcut keys. GetCharacterFromKeyCode
// returns 'a' for VKEY_A even if the key is actually bound to 'à' in X11.
// GetCharacterFromXEvent returns 'à' in that case.
return IsControlDown() ?
character_ = (IsControlDown() || !native_event()) ?
GetCharacterFromKeyCode(key_code_, flags()) :
GetCharacterFromXEvent(native_event());
// TODO(kpschoedel): set key_ field for X11.
#elif defined(USE_OZONE)
KeyboardCode key_code;
if (!KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()->Lookup(
code_, flags(), &key_, &character_, &key_code)) {
GetMeaningFromKeyCode(key_code_, flags(), &key_, &character_);
}
#else
if (native_event()) {
DCHECK(EventTypeFromNative(native_event()) == ET_KEY_PRESSED ||
EventTypeFromNative(native_event()) == ET_KEY_RELEASED);
}

return GetCharacterFromKeyCode(key_code_, flags());
// TODO(kpschoedel): revise to use DOM code_ instead of Windows key_code_
GetMeaningFromKeyCode(key_code_, flags(), &key_, &character_);
#endif
}

DomKey KeyEvent::GetDomKey() const {
// Determination of character_ and key_ may be done lazily.
if (key_ == DomKey::NONE)
ApplyLayout();
return key_;
}

base::char16 KeyEvent::GetCharacter() const {
// Determination of character_ and key_ may be done lazily.
if (key_ == DomKey::NONE)
ApplyLayout();
return character_;
}

base::char16 KeyEvent::GetText() const {
if ((flags() & EF_CONTROL_DOWN) != 0) {
// TODO(kpschoedel): revise to use DOM code_ instead of Windows key_code_
return GetControlCharacterForKeycode(key_code_,
(flags() & EF_SHIFT_DOWN) != 0);
}
Expand Down
59 changes: 51 additions & 8 deletions ui/events/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class Transform;
namespace ui {
class EventTarget;
enum class DomCode;
enum class DomKey;

class EVENTS_EXPORT Event {
public:
Expand Down Expand Up @@ -585,25 +586,38 @@ class EVENTS_EXPORT ExtendedKeyEventData {
//
// For a keystroke event,
// -- is_char_ is false.
// -- type() can be any one of ET_KEY_PRESSED, ET_KEY_RELEASED,
// -- Event::type() can be any one of ET_KEY_PRESSED, ET_KEY_RELEASED,
// ET_TRANSLATED_KEY_PRESS, or ET_TRANSLATED_KEY_RELEASE.
// -- character_ functions as a bypass or cache for GetCharacter().
// -- key_code_ is a VKEY_ value associated with the key. For printable
// characters, this may or may not be a mapped value, imitating MS Windows:
// -- code_ and Event::flags() represent the physical key event.
// - code_ is a platform-independent representation of the physical key,
// based on DOM KeyboardEvent |code| values. It does not vary depending
// on key layout.
// - Event::flags() provides the active modifiers for the physical key
// press. Its value reflects the state after the event; that is, for
// a modifier key, a press includes the corresponding flag and a release
// does not.
// -- key_ and character_ provide the meaning of the key event, in the context
// of the active layout and modifiers. Together they correspond to DOM
// KeyboardEvent |key| values.
// - key_ is an enumeration of non-Unicode meanings, plus sentinels
// (specifically DomKey::CHARACTER for Unicode meanings).
// - character_ is the code point for Unicode meanings.
// -- key_code_ is a KeyboardCode value associated with the key. This supports
// the legacy web event |keyCode| field, and the VKEY_ values are chosen
// to match Windows/IE for compatibility. For printable characters, this
// may or may not be a layout-mapped value, imitating MS Windows:
// if the mapped key generates a character that has an associated VKEY_
// code, then key_code_ is that code; if not, then key_code_ is the unmapped
// VKEY_ code. For example, US, Greek, Cyrillic, Japanese, etc. all use
// VKEY_Q for the key beside Tab, while French uses VKEY_A.
// -- code_ is in one-to-one correspondence with a physical keyboard
// location, and does not vary depending on key layout.
//
// For a character event,
// -- is_char_ is true.
// -- type() is ET_KEY_PRESSED.
// -- character_ is a UTF-16 character value.
// -- code_ is DomCode::NONE.
// -- key_ is DomKey::CHARACTER and character_ is a UTF-16 code point.
// -- key_code_ is conflated with character_ by some code, because both
// arrive in the wParam field of a Windows event.
// -- code_ is DomCode::NONE.
//
class EVENTS_EXPORT KeyEvent : public Event {
public:
Expand All @@ -615,6 +629,14 @@ class EVENTS_EXPORT KeyEvent : public Event {
// Create a keystroke event.
KeyEvent(EventType type, KeyboardCode key_code, int flags);

// Create a fully defined keystroke event.
KeyEvent(EventType type,
KeyboardCode key_code,
DomCode code,
int flags,
DomKey key,
base::char16 character);

// Create a character event.
KeyEvent(base::char16 character, KeyboardCode key_code, int flags);

Expand Down Expand Up @@ -698,6 +720,9 @@ class EVENTS_EXPORT KeyEvent : public Event {
DomCode code() const { return code_; };
std::string GetCodeString() const;

// Returns the DOM .key (layout meaning) for a keystroke event.
DomKey GetDomKey() const;

// Normalizes flags_ so that it describes the state after the event.
// (Native X11 event flags describe the state before the event.)
void NormalizeFlags();
Expand All @@ -718,6 +743,9 @@ class EVENTS_EXPORT KeyEvent : public Event {
// True if the key press originated from a 'right' key (VKEY_RSHIFT, etc.).
bool IsRightSideKey() const;

// Determine key_ and character_ on a keystroke event from code_ and flags().
void ApplyLayout() const;

KeyboardCode key_code_;

// DOM KeyboardEvent |code| (e.g. DomCode::KEY_A, DomCode::SPACE).
Expand All @@ -734,6 +762,21 @@ class EVENTS_EXPORT KeyEvent : public Event {
// For now, this is used for CharacterComposer in ChromeOS.
uint32 platform_keycode_;

// TODO(kpschoedel): refactor so that key_ and character_ are not mutable.
// This requires defining the KeyEvent completely at construction rather
// than lazily under GetCharacter(), which likely also means removing
// the two 'incomplete' constructors.
//
// DOM KeyboardEvent |key|
// http://www.w3.org/TR/DOM-Level-3-Events-key/
//
// This value, together with character_, represents the meaning of a key.
// The value is DomKey::CHARACTER when the interpretation is a character.
// This, along with character_, is not necessarily initialized when the
// event is constructed; it may be set only if and when GetCharacter()
// or GetDomKey() is called.
mutable DomKey key_;

// String of 'key' defined in DOM KeyboardEvent (e.g. 'a', 'â')
// http://www.w3.org/TR/uievents/#keyboard-key-codes.
//
Expand Down
6 changes: 6 additions & 0 deletions ui/events/events.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,11 @@
'linux/text_edit_key_bindings_delegate_auralinux.h',
],
}],
['use_ozone==1', {
'dependencies': [
'ozone/events_ozone.gyp:events_ozone_layout',
],
}],
],
},
{
Expand Down Expand Up @@ -353,6 +358,7 @@
'dependencies': [
'ozone/events_ozone.gyp:events_ozone',
'ozone/events_ozone.gyp:events_ozone_evdev',
'ozone/events_ozone.gyp:events_ozone_layout',
]
}],
['use_aura==0', {
Expand Down
Loading

0 comments on commit 763ff21

Please sign in to comment.