Skip to content
This repository has been archived by the owner on Jul 22, 2024. It is now read-only.

Commit

Permalink
Implement Japanese keyboard (#1311)
Browse files Browse the repository at this point in the history
* Implement Japanese keyboard #974

* Refactored OpenWnn to a maven artifact (jcenter)

* Fixed crash with certain syllable combinations

* Fixed Japanese keyboard title

Restored column width to the original value
  • Loading branch information
keianhzo authored and MortimerGoro committed Jun 28, 2019
1 parent b646db9 commit 861b17c
Show file tree
Hide file tree
Showing 10 changed files with 357 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ infer-out/
fastlane/

app/.externalNativeBuild
openwnn/.externalNativeBuild

*.swp

Expand Down
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ repositories {

dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation deps.openwnn

// Common
// implementation deps.google_vr.sdk_audio
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public class CustomKeyboard extends Keyboard {
public static final int KEYCODE_SYMBOLS_CHANGE = -10;
public static final int KEYCODE_VOICE_INPUT = -11;
public static final int KEYCODE_LANGUAGE_CHANGE = -12;
public static final int KEYCODE_EMOJI = -13;

public CustomKeyboard(Context context, int xmlLayoutResId) {
super(context, xmlLayoutResId, 0);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
package org.mozilla.vrbrowser.ui.keyboards;

import android.content.Context;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import org.mozilla.vrbrowser.R;
import org.mozilla.vrbrowser.input.CustomKeyboard;
import org.mozilla.vrbrowser.utils.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

import jp.co.omronsoft.openwnn.ComposingText;
import jp.co.omronsoft.openwnn.JAJP.OpenWnnEngineJAJP;
import jp.co.omronsoft.openwnn.JAJP.Romkan;
import jp.co.omronsoft.openwnn.LetterConverter;
import jp.co.omronsoft.openwnn.StrSegment;
import jp.co.omronsoft.openwnn.SymbolList;
import jp.co.omronsoft.openwnn.WnnEngine;
import jp.co.omronsoft.openwnn.WnnWord;

public class JapaneseKeyboard extends BaseKeyboard {

private static final String LOGTAG = "VRB";

private CustomKeyboard mKeyboard;
private CustomKeyboard mSymbolsKeyboard;
private List<Character> mAutocompleteEndings = Arrays.asList(
' ', '、', '。','!','?','ー'
);

private SymbolList mSymbolsConverter;

/** OpenWnn dictionary */
private WnnEngine mConverter;

/** Pre-converter (for Romaji-to-Kana input, Hangul input, etc.) */
protected LetterConverter mPreConverter;

/** The inputing/editing string */
protected ComposingText mComposingText;


public JapaneseKeyboard(Context aContext) {
super(aContext);

mConverter = new OpenWnnEngineJAJP();
((OpenWnnEngineJAJP) mConverter).setKeyboardType(OpenWnnEngineJAJP.KEYBOARD_QWERTY);
((OpenWnnEngineJAJP) mConverter).setDictionary(OpenWnnEngineJAJP.DIC_LANG_JP);
mConverter.init();

mPreConverter = new Romkan();
mComposingText = new ComposingText();
}

@NonNull
@Override
public CustomKeyboard getAlphabeticKeyboard() {
if (mKeyboard == null) {
mKeyboard = new CustomKeyboard(mContext.getApplicationContext(), R.xml.keyboard_qwerty_japanese);
}

return mKeyboard;
}

@Nullable
@Override
public CustomKeyboard getSymbolsKeyboard() {
if (mSymbolsKeyboard == null) {
mSymbolsKeyboard = new CustomKeyboard(mContext.getApplicationContext(), R.xml.keyboard_symbols_japanese);

mSymbolsConverter = new SymbolList(mContext, SymbolList.LANG_JA);
}
return mSymbolsKeyboard;
}

@Nullable
@Override
public CandidatesResult getCandidates(String aComposingText) {
if (StringUtils.isEmpty(aComposingText)) {
mComposingText.clear();
return null;
}

// Autocomplete when special characters are clicked
char lastChar = aComposingText.charAt(aComposingText.length() - 1);
boolean autocompose = mAutocompleteEndings.indexOf(lastChar) >= 0;

aComposingText = aComposingText.replaceAll("\\s","");
if (aComposingText.isEmpty()) {
return null;
}

initializeComposingText(aComposingText);

List<Words> words = new ArrayList<>();
int candidates = mConverter.predict(mComposingText, 0, -1);
if (candidates > 0) {
WnnWord word;
while ((word = mConverter.getNextCandidate()) != null) {
words.add(new Words(1, word.stroke, word.candidate));
}
}

CandidatesResult result = new CandidatesResult();
result.words = words;

if (autocompose) {
result.action = CandidatesResult.Action.AUTO_COMPOSE;
result.composing = aComposingText;

mComposingText.clear();

} else {
result.action = CandidatesResult.Action.SHOW_CANDIDATES;
result.composing = mComposingText.toString(ComposingText.LAYER2);
}

return result;
}

@Override
public CandidatesResult getEmojiCandidates(String aComposingText) {
ComposingText text = new ComposingText();
mSymbolsConverter.convert(text);

List<Words> words = new ArrayList<>();
int candidates = mSymbolsConverter.predict(mComposingText, 0, -1);
if (candidates > 0) {
WnnWord word;
while ((word = mSymbolsConverter.getNextCandidate()) != null) {
words.add(new Words(1, word.stroke, word.candidate));
}
}

CandidatesResult result = new CandidatesResult();
result.words = words;
result.action = CandidatesResult.Action.SHOW_CANDIDATES;
result.composing = aComposingText;

return result;
}

@Override
public String getComposingText(String aComposing, String aCode) {
return "";
}

private void initializeComposingText(String text) {
mComposingText.clear();
for (int i=0; i<text.length(); i++) {
mComposingText.insertStrSegment(ComposingText.LAYER0, ComposingText.LAYER1, new StrSegment(text.substring(i, i+1)));
mPreConverter.convert(mComposingText);
}
mComposingText.debugout();
}

@Override
public boolean supportsAutoCompletion() {
return true;
}

@Override
public boolean usesComposingText() {
return true;
}

@Override
public String getKeyboardTitle() {
return StringUtils.getStringByLocale(mContext, R.string.settings_language_japanese, getLocale());
}

@Override
public Locale getLocale() {
return Locale.JAPAN;
}

@Override
public String getSpaceKeyText(String aComposingText) {
if (aComposingText == null || aComposingText.trim().isEmpty()) {
return mContext.getString(R.string.japanese_spacebar_space);
} else {
return mContext.getString(R.string.japanese_spacebar_selection);
}
}

@Override
public String getEnterKeyText(int aIMEOptions, String aComposingText) {
if (aComposingText == null || aComposingText.trim().isEmpty()) {
return super.getEnterKeyText(aIMEOptions, aComposingText);
} else {
return mContext.getString(R.string.japanese_enter_completion);
}
}

@Override
public String getModeChangeKeyText() {
return mContext.getString(R.string.japanese_keyboard_mode_change);
}

@Override
public void clear() {
mConverter.init();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public enum Action {
default @Nullable CandidatesResult getCandidates(String aComposingText) { return null; }
default @Nullable String overrideAddText(String aTextBeforeCursor, String aNextText) { return null; }
default @Nullable String overrideBackspace(String aTextBeforeCursor) { return null; }
default @Nullable CandidatesResult getEmojiCandidates(String aComposingText) { return null; }
default boolean supportsAutoCompletion() { return false; }
default boolean usesComposingText() { return false; }
default boolean usesTextOverride() { return false; }
Expand All @@ -43,4 +44,5 @@ public enum Action {
String getSpaceKeyText(String aComposingText);
String getEnterKeyText(int aIMEOptions, String aComposingText);
String getModeChangeKeyText();
default @Nullable void clear() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.mozilla.vrbrowser.ui.keyboards.FrenchKeyboard;
import org.mozilla.vrbrowser.ui.keyboards.GermanKeyboard;
import org.mozilla.vrbrowser.ui.keyboards.ChineseZhuyinKeyboard;
import org.mozilla.vrbrowser.ui.keyboards.JapaneseKeyboard;
import org.mozilla.vrbrowser.ui.keyboards.KeyboardInterface;
import org.mozilla.vrbrowser.ui.keyboards.RussianKeyboard;
import org.mozilla.vrbrowser.ui.keyboards.KoreanKeyboard;
Expand Down Expand Up @@ -139,6 +140,7 @@ private void initialize(Context aContext) {
mKeyboards.add(new ChinesePinyinKeyboard(aContext));
mKeyboards.add(new ChineseZhuyinKeyboard(aContext));
mKeyboards.add(new KoreanKeyboard(aContext));
mKeyboards.add(new JapaneseKeyboard(aContext));

mDefaultKeyboardSymbols = new CustomKeyboard(aContext.getApplicationContext(), R.xml.keyboard_symbols);
mKeyboardNumeric = new CustomKeyboard(aContext.getApplicationContext(), R.xml.keyboard_numeric);
Expand Down Expand Up @@ -278,6 +280,7 @@ public void updateFocusedView(View aFocusedView) {
mWidgetManager.updateWidget(this);
}

mCurrentKeyboard.clear();
updateCandidates();
updateSpecialKeyLabels();
}
Expand Down Expand Up @@ -391,6 +394,9 @@ public void onKey(int primaryCode, int[] keyCodes, boolean hasPopup) {
case CustomKeyboard.KEYCODE_LANGUAGE_CHANGE:
handleGlobeClick();
break;
case CustomKeyboard.KEYCODE_EMOJI:
handleEmojiInput();
break;
case ' ':
handleSpace();
break;
Expand Down Expand Up @@ -579,6 +585,12 @@ private void handleGlobeClick() {
mPopupKeyboardLayer.setVisibility(View.VISIBLE);
}

private void handleEmojiInput() {
final KeyboardInterface.CandidatesResult candidates = mCurrentKeyboard.getEmojiCandidates(mComposingText);
setAutoCompletionVisible(candidates != null && candidates.words.size() > 0);
mAutoCompletionView.setItems(candidates != null ? candidates.words : null);
}

private void handleLanguageChange(KeyboardInterface aKeyboard) {
cleanComposingText();

Expand Down Expand Up @@ -949,6 +961,7 @@ public void afterTextChanged(Editable aEditable) {
if (!mInternalDeleteHint && mCurrentKeyboard.usesComposingText() && mComposingText.length() > 0 && mTextBefore.length() > 0 && aEditable.toString().length() == 0) {
// Text has been cleared externally (e.g. URLBar text clear button)
mComposingText = "";
mCurrentKeyboard.clear();
updateCandidates();
}
mInternalDeleteHint = false;
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/res/values/non_L10n.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@
<string name="zhuyin_enter_completion" translatable="false">選定</string>
<string name="zhuyin_keyboard_mode_change" translatable="false">ㄅㄆㄇ</string>

<string name="japanese_spacebar_selection" translatable="false">次変換</string>
<string name="japanese_spacebar_space" translatable="false">空白</string>
<string name="japanese_enter_completion" translatable="false">確定</string>
<string name="japanese_keyboard_mode_change" translatable="false">かな</string>

<!-- Keyboard -->
<string name="keyboard_popup_a" translatable="false">aáàäãåâąæā</string>
<string name="keyboard_popup_b" translatable="false">bƀḃḅḇ</string>
Expand Down
61 changes: 61 additions & 0 deletions app/src/main/res/xml/keyboard_qwerty_japanese.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:horizontalGap="@dimen/keyboard_horizontal_gap"
android:verticalGap="@dimen/keyboard_vertical_gap"
android:keyWidth="@dimen/keyboard_key_width"
android:keyHeight="@dimen/keyboard_key_height">
<Row>
<Key android:codes="113" android:keyLabel="q" android:keyEdgeFlags="left" />
<Key android:codes="119" android:keyLabel="w" />
<Key android:codes="101" android:keyLabel="e" />
<Key android:codes="114" android:keyLabel="r" />
<Key android:codes="116" android:keyLabel="t" />
<Key android:codes="121" android:keyLabel="y" />
<Key android:codes="117" android:keyLabel="u" />
<Key android:codes="105" android:keyLabel="i" />
<Key android:codes="111" android:keyLabel="o" />
<Key android:codes="112" android:keyLabel="p" />
<Key android:codes="95" android:keyLabel="_"/>
<Key android:codes="-5" android:keyIcon="@drawable/ic_icon_keyboard_backspace" android:isRepeatable="true" android:keyWidth="@dimen/keyboard_key_backspace_width" />
</Row>

<Row>
<Key android:codes="97" android:keyLabel="a" android:keyEdgeFlags="left" android:horizontalGap="@dimen/keyboard_left_margin" />
<Key android:codes="115" android:keyLabel="s" />
<Key android:codes="100" android:keyLabel="d" />
<Key android:codes="102" android:keyLabel="f" />
<Key android:codes="103" android:keyLabel="g" />
<Key android:codes="104" android:keyLabel="h" />
<Key android:codes="106" android:keyLabel="j" />
<Key android:codes="107" android:keyLabel="k" />
<Key android:codes="108" android:keyLabel="l" />
<Key android:keyOutputText="" android:keyLabel=""/>
<Key android:codes="-4" android:keyLabel="@string/keyboard_enter_label" android:keyWidth="@dimen/keyboard_key_enter_width" />
</Row>

<Row>
<Key android:codes="-1" android:keyIcon="@drawable/ic_icon_keyboard_shift_off" android:keyEdgeFlags="left"/>
<Key android:codes="122" android:keyLabel="z" />
<Key android:codes="120" android:keyLabel="x" />
<Key android:codes="99" android:keyLabel="c" />
<Key android:codes="118" android:keyLabel="v" />
<Key android:codes="98" android:keyLabel="b" />
<Key android:codes="110" android:keyLabel="n" />
<Key android:codes="109" android:keyLabel="m" />
<Key android:codes="45" android:keyLabel="-" />
<Key android:codes="43" android:keyLabel="+" />
<Key android:codes="47" android:keyLabel="/" />
<Key android:codes="-1" android:keyIcon="@drawable/ic_icon_keyboard_shift_off" />
</Row>

<Row>
<Key android:codes="-2" android:keyLabel="@string/keyboard_symbol" android:keyEdgeFlags="left"/>
<Key android:codes="-12" android:keyIcon="@drawable/ic_icon_keyboard_globe" />
<Key android:codes="32" android:keyLabel="" android:keyWidth="@dimen/keyboard_key_space_width" android:isRepeatable="true"/>
<Key android:keyOutputText="" android:keyLabel=""/>
<Key android:keyOutputText="" android:keyLabel=""/>
<Key android:codes="33" android:keyLabel="!" />
<Key android:codes="63" android:keyLabel="\?" />
<Key android:codes="64" android:keyLabel="\@"/>
</Row>
</Keyboard>
Loading

0 comments on commit 861b17c

Please sign in to comment.