[CB01] Reset some old assumptions about dead keys
The combining framework will be more generic than previously thought. We don't need to handle dead keys as a special type of event, as all events can be combined arbitrarily. Bug: 13406701 Change-Id: I8137fdb186c4d70eaa71808c5a1430b1559db1aemain
parent
5dc17c22ca
commit
92db209c60
|
@ -43,19 +43,19 @@ public class DeadKeyCombiner implements Combiner {
|
||||||
final int resultingCodePoint =
|
final int resultingCodePoint =
|
||||||
KeyCharacterMap.getDeadChar(deadCodePoint, event.mCodePoint);
|
KeyCharacterMap.getDeadChar(deadCodePoint, event.mCodePoint);
|
||||||
if (0 == resultingCodePoint) {
|
if (0 == resultingCodePoint) {
|
||||||
// We can't combine both characters. We need to commit the dead key as a committable
|
// We can't combine both characters. We need to commit the dead key as a separate
|
||||||
// character, and the next char too unless it's a space (because as a special case,
|
// character, and the next char too unless it's a space (because as a special case,
|
||||||
// dead key + space should result in only the dead key being committed - that's
|
// dead key + space should result in only the dead key being committed - that's
|
||||||
// how dead keys work).
|
// how dead keys work).
|
||||||
// If the event is a space, we should commit the dead char alone, but if it's
|
// If the event is a space, we should commit the dead char alone, but if it's
|
||||||
// not, we need to commit both.
|
// not, we need to commit both.
|
||||||
return Event.createCommittableEvent(deadCodePoint,
|
return Event.createInputKeypressEvent(deadCodePoint, event.mKeyCode,
|
||||||
Constants.CODE_SPACE == event.mCodePoint ? null : event /* next */);
|
Constants.CODE_SPACE == event.mCodePoint ? null : event /* next */);
|
||||||
} else {
|
} else {
|
||||||
// We could combine the characters.
|
// We could combine the characters.
|
||||||
return Event.createCommittableEvent(resultingCodePoint, null /* next */);
|
return Event.createInputKeypressEvent(resultingCodePoint, event.mKeyCode,
|
||||||
|
null /* next */);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,61 +33,83 @@ public class Event {
|
||||||
// but probably a bit too much
|
// but probably a bit too much
|
||||||
// An event we don't handle in Latin IME, for example pressing Ctrl on a hardware keyboard.
|
// An event we don't handle in Latin IME, for example pressing Ctrl on a hardware keyboard.
|
||||||
final public static int EVENT_NOT_HANDLED = 0;
|
final public static int EVENT_NOT_HANDLED = 0;
|
||||||
// A character that is already final, for example pressing an alphabetic character on a
|
// A key press that is part of input, for example pressing an alphabetic character on a
|
||||||
// hardware qwerty keyboard.
|
// hardware qwerty keyboard. It may be part of a sequence that will be re-interpreted later
|
||||||
final public static int EVENT_COMMITTABLE = 1;
|
// through combination.
|
||||||
// A dead key, which means a character that should combine with what is coming next. Examples
|
final public static int EVENT_INPUT_KEYPRESS = 1;
|
||||||
// include the "^" character on an azerty keyboard which combines with "e" to make "ê", or
|
|
||||||
// AltGr+' on a dvorak international keyboard which combines with "e" to make "é". This is
|
|
||||||
// true regardless of the language or combining mode, and should be seen as a property of the
|
|
||||||
// key - a dead key followed by another key with which it can combine should be regarded as if
|
|
||||||
// the keyboard actually had such a key.
|
|
||||||
final public static int EVENT_DEAD = 2;
|
|
||||||
// A toggle event is triggered by a key that affects the previous character. An example would
|
// A toggle event is triggered by a key that affects the previous character. An example would
|
||||||
// be a numeric key on a 10-key keyboard, which would toggle between 1 - a - b - c with
|
// be a numeric key on a 10-key keyboard, which would toggle between 1 - a - b - c with
|
||||||
// repeated presses.
|
// repeated presses.
|
||||||
final public static int EVENT_TOGGLE = 3;
|
final public static int EVENT_TOGGLE = 2;
|
||||||
// A mode event instructs the combiner to change modes. The canonical example would be the
|
// A mode event instructs the combiner to change modes. The canonical example would be the
|
||||||
// hankaku/zenkaku key on a Japanese keyboard, or even the caps lock key on a qwerty keyboard
|
// hankaku/zenkaku key on a Japanese keyboard, or even the caps lock key on a qwerty keyboard
|
||||||
// if handled at the combiner level.
|
// if handled at the combiner level.
|
||||||
final public static int EVENT_MODE_KEY = 4;
|
final public static int EVENT_MODE_KEY = 3;
|
||||||
|
// An event corresponding to a gesture.
|
||||||
|
final public static int EVENT_GESTURE = 4;
|
||||||
|
|
||||||
final private static int NOT_A_CODE_POINT = 0;
|
// 0 is a valid code point, so we use -1 here.
|
||||||
|
final public static int NOT_A_CODE_POINT = -1;
|
||||||
|
// -1 is a valid key code, so we use 0 here.
|
||||||
|
final public static int NOT_A_KEY_CODE = 0;
|
||||||
|
|
||||||
|
final private static int FLAG_NONE = 0;
|
||||||
|
// This event is a dead character, usually input by a dead key. Examples include dead-acute
|
||||||
|
// or dead-abovering.
|
||||||
|
final private static int FLAG_DEAD = 0x1;
|
||||||
|
|
||||||
final private int mType; // The type of event - one of the constants above
|
final private int mType; // The type of event - one of the constants above
|
||||||
// The code point associated with the event, if relevant. This is a unicode code point, and
|
// The code point associated with the event, if relevant. This is a unicode code point, and
|
||||||
// has nothing to do with other representations of the key. It is only relevant if this event
|
// has nothing to do with other representations of the key. It is only relevant if this event
|
||||||
// is the right type: COMMITTABLE or DEAD or TOGGLE, but for a mode key like hankaku/zenkaku or
|
// is of KEYPRESS type, but for a mode key like hankaku/zenkaku or ctrl, there is no code point
|
||||||
// ctrl, there is no code point associated so this should be NOT_A_CODE_POINT to avoid
|
// associated so this should be NOT_A_CODE_POINT to avoid unintentional use of its value when
|
||||||
// unintentional use of its value when it's not relevant.
|
// it's not relevant.
|
||||||
final public int mCodePoint;
|
final public int mCodePoint;
|
||||||
|
|
||||||
|
// The key code associated with the event, if relevant. This is relevant whenever this event
|
||||||
|
// has been triggered by a key press, but not for a gesture for example. This has conceptually
|
||||||
|
// no link to the code point, although keys that enter a straight code point may often set
|
||||||
|
// this to be equal to mCodePoint for convenience. If this is not a key, this must contain
|
||||||
|
// NOT_A_KEY_CODE.
|
||||||
|
final public int mKeyCode;
|
||||||
|
|
||||||
|
// Some flags that can't go into the key code. It's a bit field of FLAG_*
|
||||||
|
final private int mFlags;
|
||||||
|
|
||||||
// The next event, if any. Null if there is no next event yet.
|
// The next event, if any. Null if there is no next event yet.
|
||||||
final public Event mNextEvent;
|
final public Event mNextEvent;
|
||||||
|
|
||||||
// This method is private - to create a new event, use one of the create* utility methods.
|
// This method is private - to create a new event, use one of the create* utility methods.
|
||||||
private Event(final int type, final int codePoint, final Event next) {
|
private Event(final int type, final int codePoint, final int keyCode, final int flags,
|
||||||
|
final Event next) {
|
||||||
mType = type;
|
mType = type;
|
||||||
mCodePoint = codePoint;
|
mCodePoint = codePoint;
|
||||||
|
mKeyCode = keyCode;
|
||||||
|
mFlags = flags;
|
||||||
mNextEvent = next;
|
mNextEvent = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Event createDeadEvent(final int codePoint, final Event next) {
|
public static Event createInputKeypressEvent(final int codePoint, final int keyCode,
|
||||||
return new Event(EVENT_DEAD, codePoint, next);
|
final Event next) {
|
||||||
|
return new Event(EVENT_INPUT_KEYPRESS, codePoint, keyCode, FLAG_NONE, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Event createCommittableEvent(final int codePoint, final Event next) {
|
// This creates an input event for a dead character. @see {@link #FLAG_DEAD}
|
||||||
return new Event(EVENT_COMMITTABLE, codePoint, next);
|
public static Event createDeadEvent(final int codePoint, final int keyCode, final Event next) {
|
||||||
|
return new Event(EVENT_INPUT_KEYPRESS, codePoint, keyCode, FLAG_DEAD, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Event createNotHandledEvent() {
|
public static Event createNotHandledEvent() {
|
||||||
return new Event(EVENT_NOT_HANDLED, NOT_A_CODE_POINT, null);
|
return new Event(EVENT_NOT_HANDLED, NOT_A_CODE_POINT, NOT_A_KEY_CODE, FLAG_NONE, null);
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCommittable() {
|
|
||||||
return EVENT_COMMITTABLE == mType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns whether this event is for a dead character. @see {@link #FLAG_DEAD}
|
||||||
public boolean isDead() {
|
public boolean isDead() {
|
||||||
return EVENT_DEAD == mType;
|
return 0 != (FLAG_DEAD & mFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: remove this method - we should not have to test this
|
||||||
|
public boolean isCommittable() {
|
||||||
|
return EVENT_INPUT_KEYPRESS == mType || EVENT_MODE_KEY == mType || EVENT_TOGGLE == mType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,27 +47,33 @@ public class HardwareKeyboardEventDecoder implements HardwareEventDecoder {
|
||||||
// the key for 'A' or Space, but also Backspace or Ctrl or Caps Lock.
|
// the key for 'A' or Space, but also Backspace or Ctrl or Caps Lock.
|
||||||
final int keyCode = keyEvent.getKeyCode();
|
final int keyCode = keyEvent.getKeyCode();
|
||||||
if (KeyEvent.KEYCODE_DEL == keyCode) {
|
if (KeyEvent.KEYCODE_DEL == keyCode) {
|
||||||
return Event.createCommittableEvent(Constants.CODE_DELETE, null /* next */);
|
return Event.createInputKeypressEvent(Event.NOT_A_CODE_POINT, Constants.CODE_DELETE,
|
||||||
|
null /* next */);
|
||||||
}
|
}
|
||||||
if (keyEvent.isPrintingKey() || KeyEvent.KEYCODE_SPACE == keyCode
|
if (keyEvent.isPrintingKey() || KeyEvent.KEYCODE_SPACE == keyCode
|
||||||
|| KeyEvent.KEYCODE_ENTER == keyCode) {
|
|| KeyEvent.KEYCODE_ENTER == keyCode) {
|
||||||
if (0 != (codePointAndFlags & KeyCharacterMap.COMBINING_ACCENT)) {
|
if (0 != (codePointAndFlags & KeyCharacterMap.COMBINING_ACCENT)) {
|
||||||
// A dead key.
|
// A dead key.
|
||||||
return Event.createDeadEvent(
|
return Event.createDeadEvent(
|
||||||
codePointAndFlags & KeyCharacterMap.COMBINING_ACCENT_MASK, null /* next */);
|
codePointAndFlags & KeyCharacterMap.COMBINING_ACCENT_MASK, keyCode,
|
||||||
|
null /* next */);
|
||||||
}
|
}
|
||||||
if (KeyEvent.KEYCODE_ENTER == keyCode) {
|
if (KeyEvent.KEYCODE_ENTER == keyCode) {
|
||||||
// The Enter key. If the Shift key is not being pressed, this should send a
|
// The Enter key. If the Shift key is not being pressed, this should send a
|
||||||
// CODE_ENTER to trigger the action if any, or a carriage return otherwise. If the
|
// CODE_ENTER to trigger the action if any, or a carriage return otherwise. If the
|
||||||
// Shift key is being pressed, this should send a CODE_SHIFT_ENTER and let
|
// Shift key is being pressed, this should send a CODE_SHIFT_ENTER and let
|
||||||
// Latin IME decide what to do with it.
|
// Latin IME decide what to do with it.
|
||||||
return Event.createCommittableEvent(keyEvent.isShiftPressed()
|
if (keyEvent.isShiftPressed()) {
|
||||||
? Constants.CODE_SHIFT_ENTER : Constants.CODE_ENTER,
|
return Event.createInputKeypressEvent(Event.NOT_A_CODE_POINT,
|
||||||
|
Constants.CODE_SHIFT_ENTER, null /* next */);
|
||||||
|
} else {
|
||||||
|
return Event.createInputKeypressEvent(Constants.CODE_ENTER, keyCode,
|
||||||
null /* next */);
|
null /* next */);
|
||||||
}
|
}
|
||||||
// If not Enter, then we have a committable character. This should be committed
|
}
|
||||||
// right away, taking into account the current state.
|
// If not Enter, then this is just a regular keypress event for a normal character
|
||||||
return Event.createCommittableEvent(codePointAndFlags, null /* next */);
|
// that can be committed right away, taking into account the current state.
|
||||||
|
return Event.createInputKeypressEvent(keyCode, codePointAndFlags, null /* next */);
|
||||||
}
|
}
|
||||||
return Event.createNotHandledEvent();
|
return Event.createNotHandledEvent();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue