Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recommended implementation of combining characters implementation. #7758

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package io.flutter.embedding.engine.android;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;

import io.flutter.embedding.engine.systemchannels.KeyEventChannel;

public class AndroidKeyProcessor {
private final KeyEventChannel keyEventChannel;
private int baseCharacter;
gspencergoog marked this conversation as resolved.
Show resolved Hide resolved

public AndroidKeyProcessor(@NonNull KeyEventChannel keyEventChannel) {
this.keyEventChannel = keyEventChannel;
}

public void onKeyUp(@NonNull KeyEvent keyEvent) {
Character complexCharacter = applyKeyToBaseCharacter(keyEvent.getUnicodeChar());
keyEventChannel.keyUp(
new KeyEventChannel.FlutterKeyEvent(keyEvent, complexCharacter)
);
}

public void onKeyDown(@NonNull KeyEvent keyEvent) {
Character complexCharacter = applyKeyToBaseCharacter(keyEvent.getUnicodeChar());
keyEventChannel.keyDown(
new KeyEventChannel.FlutterKeyEvent(keyEvent, complexCharacter)
);
}

/**
* Applies the given unicode character in {@code codePoint} to a previously entered
gspencergoog marked this conversation as resolved.
Show resolved Hide resolved
* unicode character and returns the combination of these characters if a combination
* exists.
*
* If the given unicode character is the first to be pressed in a session, or if
gspencergoog marked this conversation as resolved.
Show resolved Hide resolved
* the new unicode character cannot be combined with the previous unicode character,
* null is returned.
*
* This method mutates {@link #baseCharacter} over time to combine characters.
*/
@Nullable
private Character applyKeyToBaseCharacter(int codePoint) {
if (codePoint == 0) {
return null;
}

if ((codePoint & KeyCharacterMap.COMBINING_ACCENT) != 0) {
// If a combining character was entered before, combine this one with that one.
int plainCodePoint = codePoint & KeyCharacterMap.COMBINING_ACCENT_MASK;
if (baseCharacter != 0) {
baseCharacter = KeyCharacterMap.getDeadChar(baseCharacter, plainCodePoint);
} else {
baseCharacter = plainCodePoint;
}
} else {
if (baseCharacter != 0) {
int combinedChar = KeyCharacterMap.getDeadChar(baseCharacter, codePoint);
if (combinedChar > 0) {
codePoint = combinedChar;
}
baseCharacter = 0;
}
return (char) codePoint;
}

return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package io.flutter.embedding.engine.systemchannels;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.KeyEvent;

import java.util.HashMap;
Expand All @@ -26,7 +27,7 @@ public KeyEventChannel(@NonNull DartExecutor dartExecutor) {
this.channel = new BasicMessageChannel<>(dartExecutor, "flutter/keyevent", JSONMessageCodec.INSTANCE);
}

public void keyUp(@NonNull KeyEvent keyEvent) {
public void keyUp(@NonNull FlutterKeyEvent keyEvent) {
Map<String, Object> message = new HashMap<>();
message.put("type", "keyup");
message.put("keymap", "android");
Expand All @@ -35,7 +36,7 @@ public void keyUp(@NonNull KeyEvent keyEvent) {
channel.send(message);
}

public void keyDown(@NonNull KeyEvent keyEvent) {
public void keyDown(@NonNull FlutterKeyEvent keyEvent) {
Map<String, Object> message = new HashMap<>();
message.put("type", "keydown");
message.put("keymap", "android");
Expand All @@ -44,11 +45,63 @@ public void keyDown(@NonNull KeyEvent keyEvent) {
channel.send(message);
}

private void encodeKeyEvent(@NonNull KeyEvent event, @NonNull Map<String, Object> message) {
message.put("flags", event.getFlags());
message.put("codePoint", event.getUnicodeChar());
message.put("keyCode", event.getKeyCode());
message.put("scanCode", event.getScanCode());
message.put("metaState", event.getMetaState());
private void encodeKeyEvent(@NonNull FlutterKeyEvent event, @NonNull Map<String, Object> message) {
message.put("flags", event.flags);
message.put("codePoint", event.codePoint);
message.put("keyCode", event.keyCode);
message.put("scanCode", event.scanCode);
message.put("metaState", event.metaState);
if (event.complexCharacter != null) {
message.put("character", event.complexCharacter.toString());
}
}

/**
* Key event as defined by Flutter.
*/
public static class FlutterKeyEvent {
public final int flags;
public final int codePoint;
public final int keyCode;
@Nullable
public final Character complexCharacter;
public final int scanCode;
public final int metaState;

public FlutterKeyEvent(
@NonNull KeyEvent androidKeyEvent
) {
this(androidKeyEvent, null);
}

public FlutterKeyEvent(
@NonNull KeyEvent androidKeyEvent,
@Nullable Character complexCharacter
) {
this(
androidKeyEvent.getFlags(),
androidKeyEvent.getUnicodeChar(),
gspencergoog marked this conversation as resolved.
Show resolved Hide resolved
androidKeyEvent.getKeyCode(),
complexCharacter,
androidKeyEvent.getScanCode(),
androidKeyEvent.getMetaState()
);
}

public FlutterKeyEvent(
int flags,
int codePoint,
int keyCode,
@Nullable Character complexCharacter,
int scanCode,
int metaState
) {
this.flags = flags;
this.codePoint = codePoint;
this.keyCode = keyCode;
this.complexCharacter = complexCharacter;
this.scanCode = scanCode;
this.metaState = metaState;
}
}
}
8 changes: 5 additions & 3 deletions shell/platform/android/io/flutter/view/FlutterView.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import io.flutter.app.FlutterPluginRegistry;
import io.flutter.embedding.engine.android.AndroidKeyProcessor;
import io.flutter.embedding.engine.dart.DartExecutor;
import io.flutter.embedding.engine.systemchannels.KeyEventChannel;
import io.flutter.embedding.engine.systemchannels.LifecycleChannel;
Expand Down Expand Up @@ -93,6 +94,7 @@ static final class ViewportMetrics {
private final SystemChannel systemChannel;
private final InputMethodManager mImm;
private final TextInputPlugin mTextInputPlugin;
private final AndroidKeyProcessor androidKeyProcessor;
private final SurfaceHolder.Callback mSurfaceCallback;
private final ViewportMetrics mMetrics;
private final AccessibilityManager mAccessibilityManager;
Expand Down Expand Up @@ -172,7 +174,7 @@ public void surfaceDestroyed(SurfaceHolder holder) {
addActivityLifecycleListener(platformPlugin);
mImm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
mTextInputPlugin = new TextInputPlugin(this);
gspencergoog marked this conversation as resolved.
Show resolved Hide resolved

androidKeyProcessor = new AndroidKeyProcessor(keyEventChannel);

setLocales(getResources().getConfiguration());
sendUserPlatformSettingsToDart();
Expand All @@ -183,7 +185,7 @@ public boolean onKeyUp(int keyCode, KeyEvent event) {
if (!isAttached()) {
return super.onKeyUp(keyCode, event);
}
keyEventChannel.keyUp(event);
androidKeyProcessor.onKeyUp(event);
return super.onKeyUp(keyCode, event);
}

Expand All @@ -199,7 +201,7 @@ public boolean onKeyDown(int keyCode, KeyEvent event) {
}
}

keyEventChannel.keyDown(event);
androidKeyProcessor.onKeyDown(event);
return super.onKeyDown(keyCode, event);
}

Expand Down