6package org.qtproject.qt.android;
8import android.annotation.SuppressLint;
9import android.app.Activity;
10import android.content.Context;
11import android.graphics.Canvas;
12import android.text.InputType;
13import android.view.View;
14import android.view.inputmethod.EditorInfo;
15import android.view.inputmethod.ExtractedText;
16import android.view.inputmethod.ExtractedTextRequest;
17import android.view.inputmethod.InputConnection;
18import android.view.KeyEvent;
19import android.util.Log;
21import org.qtproject.qt.android.QtInputConnection.QtInputConnectionListener;
23@SuppressLint(
"ViewConstructor")
24class QtEditText extends View
26 static final String QtTAG =
"QtEditText";
28 int m_initialCapsMode = 0;
30 int m_inputType = InputType.TYPE_CLASS_TEXT;
31 boolean m_optionsChanged =
false;
32 QtInputConnection m_inputConnection =
null;
43 private final int ImhDate = 0x80;
44 private final int ImhTime = 0x100;
66 static final int CursorHandleNotShown = 0;
67 static final int CursorHandleShowNormal = 1;
68 static final int CursorHandleShowSelection = 2;
69 static final int CursorHandleShowEdit = 0x100;
71 private CursorHandle m_cursorHandle;
72 private CursorHandle m_leftSelectionHandle;
73 private CursorHandle m_rightSelectionHandle;
75 final private EditPopupMenu m_editPopupMenu;
81 setFocusableInTouchMode(
true);
82 m_qtInputConnectionListener = listener;
83 m_editPopupMenu =
new EditPopupMenu(
this);
86 private void setImeOptions(
int imeOptions)
88 if (m_imeOptions == imeOptions)
90 m_imeOptions = imeOptions;
91 m_optionsChanged =
true;
94 private void setInitialCapsMode(
int initialCapsMode)
96 if (m_initialCapsMode == initialCapsMode)
98 m_initialCapsMode = initialCapsMode;
99 m_optionsChanged =
true;
103 private void setInputType(
int inputType)
105 if (m_inputType == inputType)
107 m_inputType = inputType;
108 m_optionsChanged =
true;
112 public InputConnection onCreateInputConnection(EditorInfo outAttrs)
114 outAttrs.inputType = m_inputType;
116 outAttrs.imeOptions = m_imeOptions;
117 if (
System.getenv(
"QT_ANDROID_NO_FULLSCREEN_KEYBOARD") !=
null) {
118 outAttrs.imeOptions = m_imeOptions | EditorInfo.IME_FLAG_NO_FULLSCREEN;
119 Log.w(QtTAG,
"Use Qt::ImhNoFullscreen instead of QT_ANDROID_NO_FULLSCREEN_KEYBOARD "
120 +
"environment variable on Qt 6.12 and newer.");
123 outAttrs.initialCapsMode = m_initialCapsMode;
124 m_inputConnection =
new QtInputConnection(
this,m_qtInputConnectionListener);
126 ExtractedText extracted = m_inputConnection.getExtractedText(
new ExtractedTextRequest(), 0);
127 if (extracted !=
null) {
128 outAttrs.initialSelStart = extracted.selectionStart;
129 outAttrs.initialSelEnd = extracted.selectionEnd;
132 return m_inputConnection;
136 public boolean onCheckIsTextEditor ()
142 public boolean onKeyDown (
int keyCode, KeyEvent
event)
144 if (
null != m_inputConnection)
145 m_inputConnection.restartImmInput();
147 return super.onKeyDown(keyCode,
event);
151 protected void onDraw(Canvas canvas) {
154 super.onDraw(canvas);
158 void setEditTextOptions(
int enterKeyType,
int inputHints)
160 int initialCapsMode = 0;
161 int imeOptions = imeOptionsFromEnterKeyType(enterKeyType);
162 int inputType = android.text.InputType.TYPE_CLASS_TEXT;
164 if ((inputHints & (ImhPreferNumbers | ImhDigitsOnly | ImhFormattedNumbersOnly)) != 0) {
165 inputType = android.text.InputType.TYPE_CLASS_NUMBER;
166 if ((inputHints & ImhFormattedNumbersOnly) != 0) {
167 inputType |= (android.text.InputType.TYPE_NUMBER_FLAG_DECIMAL
168 | android.text.InputType.TYPE_NUMBER_FLAG_SIGNED);
171 if ((inputHints & ImhHiddenText) != 0)
172 inputType |= android.text.InputType.TYPE_NUMBER_VARIATION_PASSWORD;
173 }
else if ((inputHints & ImhDecimaNumbersOnly) != 0) {
174 inputType |= android.text.InputType.TYPE_NUMBER_FLAG_DECIMAL;
175 }
else if ((inputHints & ImhDialableCharactersOnly) != 0) {
176 inputType = android.text.InputType.TYPE_CLASS_PHONE;
177 }
else if ((inputHints & (ImhDate | ImhTime)) != 0) {
178 inputType = android.text.InputType.TYPE_CLASS_DATETIME;
179 if ((inputHints & (ImhDate | ImhTime)) != (ImhDate | ImhTime)) {
180 if ((inputHints & ImhDate) != 0)
181 inputType |= android.text.InputType.TYPE_DATETIME_VARIATION_DATE;
183 inputType |= android.text.InputType.TYPE_DATETIME_VARIATION_TIME;
186 if ((inputHints & ImhHiddenText) != 0) {
187 inputType |= android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
188 }
else if ((inputHints & ImhSensitiveData) != 0 ||
189 isDisablePredictiveTextWorkaround(inputHints)) {
190 inputType |= android.text.InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
191 }
else if ((inputHints & ImhUrlCharactersOnly) != 0) {
192 inputType |= android.text.InputType.TYPE_TEXT_VARIATION_URI;
193 if (enterKeyType == 0)
194 imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_GO;
195 }
else if ((inputHints & ImhEmailCharactersOnly) != 0) {
196 inputType |= android.text.InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
199 if ((inputHints & ImhMultiLine) != 0) {
200 inputType |= android.text.InputType.TYPE_TEXT_FLAG_MULTI_LINE;
203 imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
205 if ((inputHints & (ImhNoPredictiveText | ImhSensitiveData | ImhHiddenText)) != 0)
206 inputType |= android.text.InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
208 if ((inputHints & ImhUppercaseOnly) != 0) {
209 initialCapsMode |= android.text.TextUtils.CAP_MODE_CHARACTERS;
210 inputType |= android.text.InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS;
211 }
else if ((inputHints & ImhLowercaseOnly) == 0
212 && (inputHints & ImhNoAutoUppercase) == 0) {
213 initialCapsMode |= android.text.TextUtils.CAP_MODE_SENTENCES;
214 inputType |= android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
218 if (enterKeyType == 0 && (inputHints & ImhMultiLine) != 0)
219 imeOptions = android.view.inputmethod.EditorInfo.IME_FLAG_NO_ENTER_ACTION;
221 if ((inputHints & ImhNoFullscreen) != 0)
222 imeOptions |= android.view.inputmethod.EditorInfo.IME_FLAG_NO_FULLSCREEN;
224 setInitialCapsMode(initialCapsMode);
225 setImeOptions(imeOptions);
226 setInputType(inputType);
229 private int imeOptionsFromEnterKeyType(
int enterKeyType)
231 int imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
234 switch (enterKeyType) {
238 imeOptions = android.view.inputmethod.EditorInfo.IME_FLAG_NO_ENTER_ACTION;
243 imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_GO;
246 imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_SEND;
249 imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_SEARCH;
252 imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_NEXT;
255 imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_PREVIOUS;
261 int getSelectionHandleBottom()
263 if (m_cursorHandle !=
null)
264 return m_cursorHandle.bottom();
265 if (m_leftSelectionHandle !=
null && m_rightSelectionHandle !=
null)
266 return Math.max(m_leftSelectionHandle.bottom(), m_rightSelectionHandle.bottom());
271 int getSelectionHandleWidth()
273 if (m_leftSelectionHandle !=
null && m_rightSelectionHandle !=
null)
274 return Math.max(m_leftSelectionHandle.width(), m_rightSelectionHandle.width());
275 if (m_cursorHandle !=
null)
276 return m_cursorHandle.width();
282 int x1,
int y1,
int x2,
int y2,
boolean rtl)
286 case CursorHandleNotShown:
287 if (m_cursorHandle !=
null) {
288 m_cursorHandle.hide();
289 m_cursorHandle =
null;
291 if (m_rightSelectionHandle !=
null) {
292 m_rightSelectionHandle.hide();
293 m_leftSelectionHandle.hide();
294 m_rightSelectionHandle =
null;
295 m_leftSelectionHandle =
null;
298 case CursorHandleShowNormal:
299 if (m_cursorHandle ==
null) {
300 m_cursorHandle =
new CursorHandle((Activity) getContext(),
this,
301 CursorHandle.IdCursorHandle,
302 android.R.attr.textSelectHandle,
false);
304 m_cursorHandle.setPosition(
x1,
y1);
305 if (m_rightSelectionHandle !=
null) {
306 m_rightSelectionHandle.hide();
307 m_leftSelectionHandle.hide();
308 m_rightSelectionHandle =
null;
309 m_leftSelectionHandle =
null;
312 case CursorHandleShowSelection:
313 if (m_rightSelectionHandle ==
null) {
314 m_leftSelectionHandle =
new CursorHandle((Activity) getContext(),
this,
315 CursorHandle.IdLeftHandle,
316 !rtl ? android.R.attr.textSelectHandleLeft :
317 android.R.attr.textSelectHandleRight,
319 m_rightSelectionHandle =
new CursorHandle((Activity) getContext(),
this,
320 CursorHandle.IdRightHandle,
321 !rtl ? android.R.attr.textSelectHandleRight :
322 android.R.attr.textSelectHandleLeft,
325 m_leftSelectionHandle.setPosition(
x1,
y1);
326 m_rightSelectionHandle.setPosition(
x2,
y2);
327 if (m_cursorHandle !=
null) {
328 m_cursorHandle.hide();
329 m_cursorHandle =
null;
331 mode |= CursorHandleShowEdit;
335 if (!QtClipboardManager.hasClipboardText(getContext()))
336 editButtons &= ~EditContextView.PASTE_BUTTON;
338 final boolean setEditPopupPosition = (
mode & QtEditText.CursorHandleShowEdit) ==
339 QtEditText.CursorHandleShowEdit && editButtons != 0;
340 if (setEditPopupPosition)
341 m_editPopupMenu.setPosition(editX, editY, editButtons);
343 m_editPopupMenu.hide();
346 private boolean isDisablePredictiveTextWorkaround(
int inputHints)
348 return (inputHints & ImhNoPredictiveText) != 0 &&
349 System.getenv(
"QT_ANDROID_ENABLE_WORKAROUND_TO_DISABLE_PREDICTIVE_TEXT") !=
null;
static const QString context()
@ ImhFormattedNumbersOnly
@ ImhDialableCharactersOnly
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLuint GLfloat GLfloat GLfloat x1
GLfixed GLfixed GLfixed y2