1 /*************************************************************************/ 2 /* GodotEditText.java */ 3 /*************************************************************************/ 4 /* This file is part of: */ 5 /* GODOT ENGINE */ 6 /* https://godotengine.org */ 7 /*************************************************************************/ 8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ 9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ 10 /* */ 11 /* Permission is hereby granted, free of charge, to any person obtaining */ 12 /* a copy of this software and associated documentation files (the */ 13 /* "Software"), to deal in the Software without restriction, including */ 14 /* without limitation the rights to use, copy, modify, merge, publish, */ 15 /* distribute, sublicense, and/or sell copies of the Software, and to */ 16 /* permit persons to whom the Software is furnished to do so, subject to */ 17 /* the following conditions: */ 18 /* */ 19 /* The above copyright notice and this permission notice shall be */ 20 /* included in all copies or substantial portions of the Software. */ 21 /* */ 22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ 25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ 26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ 27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ 28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 29 /*************************************************************************/ 30 31 package org.godotengine.godot.input; 32 33 import org.godotengine.godot.*; 34 35 import android.content.Context; 36 import android.os.Handler; 37 import android.os.Message; 38 import android.text.InputFilter; 39 import android.text.InputType; 40 import android.util.AttributeSet; 41 import android.view.KeyEvent; 42 import android.view.inputmethod.EditorInfo; 43 import android.view.inputmethod.InputMethodManager; 44 import android.widget.EditText; 45 46 import java.lang.ref.WeakReference; 47 48 public class GodotEditText extends EditText { 49 // =========================================================== 50 // Constants 51 // =========================================================== 52 private final static int HANDLER_OPEN_IME_KEYBOARD = 2; 53 private final static int HANDLER_CLOSE_IME_KEYBOARD = 3; 54 55 // =========================================================== 56 // Fields 57 // =========================================================== 58 private GodotView mView; 59 private GodotTextInputWrapper mInputWrapper; 60 private EditHandler sHandler = new EditHandler(this); 61 private String mOriginText; 62 private int mMaxInputLength = Integer.MAX_VALUE; 63 private boolean mMultiline = false; 64 65 private static class EditHandler extends Handler { 66 private final WeakReference<GodotEditText> mEdit; EditHandler(GodotEditText edit)67 public EditHandler(GodotEditText edit) { 68 mEdit = new WeakReference<>(edit); 69 } 70 71 @Override handleMessage(Message msg)72 public void handleMessage(Message msg) { 73 GodotEditText edit = mEdit.get(); 74 if (edit != null) { 75 edit.handleMessage(msg); 76 } 77 } 78 } 79 80 // =========================================================== 81 // Constructors 82 // =========================================================== GodotEditText(final Context context)83 public GodotEditText(final Context context) { 84 super(context); 85 this.initView(); 86 } 87 GodotEditText(final Context context, final AttributeSet attrs)88 public GodotEditText(final Context context, final AttributeSet attrs) { 89 super(context, attrs); 90 this.initView(); 91 } 92 GodotEditText(final Context context, final AttributeSet attrs, final int defStyle)93 public GodotEditText(final Context context, final AttributeSet attrs, final int defStyle) { 94 super(context, attrs, defStyle); 95 this.initView(); 96 } 97 initView()98 protected void initView() { 99 this.setPadding(0, 0, 0, 0); 100 this.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_DONE); 101 } 102 isMultiline()103 public boolean isMultiline() { 104 return mMultiline; 105 } 106 handleMessage(final Message msg)107 private void handleMessage(final Message msg) { 108 switch (msg.what) { 109 case HANDLER_OPEN_IME_KEYBOARD: { 110 GodotEditText edit = (GodotEditText)msg.obj; 111 String text = edit.mOriginText; 112 if (edit.requestFocus()) { 113 edit.removeTextChangedListener(edit.mInputWrapper); 114 setMaxInputLength(edit); 115 edit.setText(""); 116 edit.append(text); 117 if (msg.arg2 != -1) { 118 edit.setSelection(msg.arg1, msg.arg2); 119 edit.mInputWrapper.setSelection(true); 120 } else { 121 edit.mInputWrapper.setSelection(false); 122 } 123 124 int inputType = InputType.TYPE_CLASS_TEXT; 125 if (edit.isMultiline()) { 126 inputType |= InputType.TYPE_TEXT_FLAG_MULTI_LINE; 127 } 128 edit.setInputType(inputType); 129 130 edit.mInputWrapper.setOriginText(text); 131 edit.addTextChangedListener(edit.mInputWrapper); 132 final InputMethodManager imm = (InputMethodManager)mView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 133 imm.showSoftInput(edit, 0); 134 } 135 } break; 136 137 case HANDLER_CLOSE_IME_KEYBOARD: { 138 GodotEditText edit = (GodotEditText)msg.obj; 139 140 edit.removeTextChangedListener(mInputWrapper); 141 final InputMethodManager imm = (InputMethodManager)mView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 142 imm.hideSoftInputFromWindow(edit.getWindowToken(), 0); 143 edit.mView.requestFocus(); 144 } break; 145 } 146 } 147 setMaxInputLength(EditText p_edit_text)148 private void setMaxInputLength(EditText p_edit_text) { 149 InputFilter[] filters = new InputFilter[1]; 150 filters[0] = new InputFilter.LengthFilter(this.mMaxInputLength); 151 p_edit_text.setFilters(filters); 152 } 153 154 // =========================================================== 155 // Getter & Setter 156 // =========================================================== setView(final GodotView view)157 public void setView(final GodotView view) { 158 this.mView = view; 159 if (mInputWrapper == null) 160 mInputWrapper = new GodotTextInputWrapper(mView, this); 161 this.setOnEditorActionListener(mInputWrapper); 162 view.requestFocus(); 163 } 164 165 // =========================================================== 166 // Methods for/from SuperClass/Interfaces 167 // =========================================================== 168 @Override onKeyDown(final int keyCode, final KeyEvent keyEvent)169 public boolean onKeyDown(final int keyCode, final KeyEvent keyEvent) { 170 super.onKeyDown(keyCode, keyEvent); 171 172 /* Let GlSurfaceView get focus if back key is input. */ 173 if (keyCode == KeyEvent.KEYCODE_BACK) { 174 this.mView.requestFocus(); 175 } 176 177 return true; 178 } 179 180 // =========================================================== 181 // Methods 182 // =========================================================== showKeyboard(String p_existing_text, boolean p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end)183 public void showKeyboard(String p_existing_text, boolean p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) { 184 int maxInputLength = (p_max_input_length <= 0) ? Integer.MAX_VALUE : p_max_input_length; 185 if (p_cursor_start == -1) { // cursor position not given 186 this.mOriginText = p_existing_text; 187 this.mMaxInputLength = maxInputLength; 188 } else if (p_cursor_end == -1) { // not text selection 189 this.mOriginText = p_existing_text.substring(0, p_cursor_start); 190 this.mMaxInputLength = maxInputLength - (p_existing_text.length() - p_cursor_start); 191 } else { 192 this.mOriginText = p_existing_text.substring(0, p_cursor_end); 193 this.mMaxInputLength = maxInputLength - (p_existing_text.length() - p_cursor_end); 194 } 195 196 this.mMultiline = p_multiline; 197 198 final Message msg = new Message(); 199 msg.what = HANDLER_OPEN_IME_KEYBOARD; 200 msg.obj = this; 201 msg.arg1 = p_cursor_start; 202 msg.arg2 = p_cursor_end; 203 sHandler.sendMessage(msg); 204 } 205 hideKeyboard()206 public void hideKeyboard() { 207 final Message msg = new Message(); 208 msg.what = HANDLER_CLOSE_IME_KEYBOARD; 209 msg.obj = this; 210 sHandler.sendMessage(msg); 211 } 212 213 // =========================================================== 214 // Inner and Anonymous Classes 215 // =========================================================== 216 } 217