Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
QtInputConnection.java
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5package org.qtproject.qt.android;
6
7import android.content.Context;
8import android.os.Build;
9import android.util.Log;
10import android.view.WindowMetrics;
11import android.view.inputmethod.BaseInputConnection;
12import android.view.inputmethod.CompletionInfo;
13import android.view.inputmethod.ExtractedText;
14import android.view.inputmethod.ExtractedTextRequest;
15import android.view.inputmethod.InputMethodManager;
16import android.view.KeyEvent;
17import android.graphics.Rect;
18import android.app.Activity;
19import android.util.DisplayMetrics;
20
21class QtExtractedText
22{
23 public int partialEndOffset;
24 public int partialStartOffset;
25 public int selectionEnd;
26 public int selectionStart;
27 public int startOffset;
28 public String text;
29}
30
31class QtNativeInputConnection
32{
33 static native boolean beginBatchEdit();
34 static native boolean endBatchEdit();
35 static native boolean commitText(String text, int newCursorPosition);
36 static native boolean commitCompletion(String text, int position);
37 static native boolean deleteSurroundingText(int leftLength, int rightLength);
38 static native boolean finishComposingText();
39 static native int getCursorCapsMode(int reqModes);
40 static native QtExtractedText getExtractedText(int hintMaxChars, int hintMaxLines, int flags);
41 static native String getSelectedText(int flags);
42 static native String getTextAfterCursor(int length, int flags);
43 static native String getTextBeforeCursor(int length, int flags);
44 static native boolean setComposingText(String text, int newCursorPosition);
45 static native boolean setComposingRegion(int start, int end);
46 static native boolean setSelection(int start, int end);
47 static native boolean selectAll();
48 static native boolean cut();
49 static native boolean copy();
50 static native boolean copyURL();
51 static native boolean paste();
52 static native boolean updateCursorPosition();
53 static native void reportFullscreenMode(boolean enabled);
54 static native boolean fullscreenMode();
55}
56
57class QtInputConnection extends BaseInputConnection
58{
59 private static final int ID_SELECT_ALL = android.R.id.selectAll;
60 private static final int ID_CUT = android.R.id.cut;
61 private static final int ID_COPY = android.R.id.copy;
62 private static final int ID_PASTE = android.R.id.paste;
63 private static final int ID_COPY_URL = android.R.id.copyUrl;
64 private static final int ID_SWITCH_INPUT_METHOD = android.R.id.switchInputMethod;
65 private static final int ID_ADD_TO_DICTIONARY = android.R.id.addToDictionary;
66
67 private static final String QtTAG = "QtInputConnection";
68
69 private final QtInputConnectionListener m_qtInputConnectionListener;
70
71 class HideKeyboardRunnable implements Runnable {
72 @Override
73 public void run() {
74 // Check that the keyboard is really no longer there.
75 Activity activity = QtNative.activity();
76 if (activity == null) {
77 Log.w(QtTAG, "HideKeyboardRunnable: The activity reference is null");
78 return;
79 }
80
81 Rect r = new Rect();
82 activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
83
84 int screenHeight;
85 if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
86 DisplayMetrics metrics = new DisplayMetrics();
87 activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
88 screenHeight = metrics.heightPixels;
89 } else {
90 final WindowMetrics maximumWindowMetrics = activity.getWindowManager().getMaximumWindowMetrics();
91 screenHeight = maximumWindowMetrics.getBounds().height();
92 }
93 final int kbHeight = screenHeight - r.bottom;
94 if (kbHeight < 100)
95 m_qtInputConnectionListener.onHideKeyboardRunnableDone(false, System.nanoTime());
96 }
97 }
98
99 public interface QtInputConnectionListener {
100 void onSetClosing(boolean closing);
101 void onHideKeyboardRunnableDone(boolean visibility, long hideTimeStamp);
103 }
104
105 private final QtEditText m_view;
106 private final InputMethodManager m_imm;
107
108 private void setClosing(boolean closing)
109 {
110 if (closing)
111 m_view.postDelayed(new HideKeyboardRunnable(), 100);
112 else
113 m_qtInputConnectionListener.onSetClosing(false);
114 }
115
116 public QtInputConnection(QtEditText targetView, QtInputConnectionListener listener)
117 {
118 super(targetView, true);
119 m_view = targetView;
120 m_imm = (InputMethodManager)m_view.getContext().getSystemService(
121 Context.INPUT_METHOD_SERVICE);
122 m_qtInputConnectionListener = listener;
123 }
124
125 public void restartImmInput()
126 {
127 if (QtNativeInputConnection.fullscreenMode()) {
128 if (m_imm != null)
129 m_imm.restartInput(m_view);
130 }
131
132 }
133
134 @Override
135 public boolean beginBatchEdit()
136 {
137 setClosing(false);
138 return QtNativeInputConnection.beginBatchEdit();
139 }
140
141 @Override
142 public boolean reportFullscreenMode (boolean enabled)
143 {
144 QtNativeInputConnection.reportFullscreenMode(enabled);
145 // Always ignored on calling editor.
146 // Always false on Android 8 and later, true with earlier.
147 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
148 return false;
149
150 return true;
151 }
152
153 @Override
154 public boolean endBatchEdit()
155 {
156 setClosing(false);
157 return QtNativeInputConnection.endBatchEdit();
158 }
159
160 @Override
161 public boolean commitCompletion(CompletionInfo text)
162 {
163 setClosing(false);
164 return QtNativeInputConnection.commitCompletion(text.getText().toString(), text.getPosition());
165 }
166
167 @Override
168 public boolean commitText(CharSequence text, int newCursorPosition)
169 {
170 setClosing(false);
171 restartImmInput();
172 return QtNativeInputConnection.commitText(text.toString(), newCursorPosition);
173 }
174
175 @Override
176 public boolean deleteSurroundingText(int leftLength, int rightLength)
177 {
178 setClosing(false);
179 return QtNativeInputConnection.deleteSurroundingText(leftLength, rightLength);
180 }
181
182 @Override
183 public boolean finishComposingText()
184 {
185 // on some/all android devices hide event is not coming, but instead finishComposingText() is called twice
186 setClosing(true);
187 return QtNativeInputConnection.finishComposingText();
188 }
189
190 @Override
191 public int getCursorCapsMode(int reqModes)
192 {
193 return QtNativeInputConnection.getCursorCapsMode(reqModes);
194 }
195
196 @Override
197 public ExtractedText getExtractedText(ExtractedTextRequest request, int flags)
198 {
199 QtExtractedText qExtractedText = QtNativeInputConnection.getExtractedText(request.hintMaxChars,
200 request.hintMaxLines,
201 flags);
202 if (qExtractedText == null)
203 return null;
204
205 ExtractedText extractedText = new ExtractedText();
206 extractedText.partialEndOffset = qExtractedText.partialEndOffset;
207 extractedText.partialStartOffset = qExtractedText.partialStartOffset;
208 extractedText.selectionEnd = qExtractedText.selectionEnd;
209 extractedText.selectionStart = qExtractedText.selectionStart;
210 extractedText.startOffset = qExtractedText.startOffset;
211 extractedText.text = qExtractedText.text;
212 return extractedText;
213 }
214
215 public CharSequence getSelectedText(int flags)
216 {
217 return QtNativeInputConnection.getSelectedText(flags);
218 }
219
220 @Override
221 public CharSequence getTextAfterCursor(int length, int flags)
222 {
223 return QtNativeInputConnection.getTextAfterCursor(length, flags);
224 }
225
226 @Override
227 public CharSequence getTextBeforeCursor(int length, int flags)
228 {
229 return QtNativeInputConnection.getTextBeforeCursor(length, flags);
230 }
231
232 @Override
233 public boolean performContextMenuAction(int id)
234 {
235 switch (id) {
236 case ID_SELECT_ALL:
237 restartImmInput();
238 return QtNativeInputConnection.selectAll();
239 case ID_COPY:
240 restartImmInput();
241 return QtNativeInputConnection.copy();
242 case ID_COPY_URL:
243 restartImmInput();
244 return QtNativeInputConnection.copyURL();
245 case ID_CUT:
246 restartImmInput();
247 return QtNativeInputConnection.cut();
248 case ID_PASTE:
249 restartImmInput();
250 return QtNativeInputConnection.paste();
251 case ID_SWITCH_INPUT_METHOD:
252 if (m_imm != null)
253 m_imm.showInputMethodPicker();
254
255 return true;
256 case ID_ADD_TO_DICTIONARY:
257// TODO
258// String word = m_editable.subSequence(0, m_editable.length()).toString();
259// if (word != null) {
260// Intent i = new Intent("com.android.settings.USER_DICTIONARY_INSERT");
261// i.putExtra("word", word);
262// i.setFlags(i.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
263// m_view.getContext().startActivity(i);
264// }
265 return true;
266 }
267 return super.performContextMenuAction(id);
268 }
269
270 @Override
271 public boolean sendKeyEvent(KeyEvent event)
272 {
273 // QTBUG-85715
274 // If the sendKeyEvent was invoked, it means that the button not related with composingText was used
275 // In such case composing text (if it exists) should be finished immediately
276 finishComposingText();
277 if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER && m_view != null) {
278 KeyEvent fakeEvent;
279 switch (m_view.m_imeOptions) {
280 case android.view.inputmethod.EditorInfo.IME_ACTION_NEXT:
281 fakeEvent = new KeyEvent(event.getDownTime(),
282 event.getEventTime(),
283 event.getAction(),
284 KeyEvent.KEYCODE_TAB,
285 event.getRepeatCount(),
286 event.getMetaState());
287 return super.sendKeyEvent(fakeEvent);
288 case android.view.inputmethod.EditorInfo.IME_ACTION_PREVIOUS:
289 fakeEvent = new KeyEvent(event.getDownTime(),
290 event.getEventTime(),
291 event.getAction(),
292 KeyEvent.KEYCODE_TAB,
293 event.getRepeatCount(),
294 KeyEvent.META_SHIFT_ON);
295 return super.sendKeyEvent(fakeEvent);
296 case android.view.inputmethod.EditorInfo.IME_FLAG_NO_ENTER_ACTION:
297 restartImmInput();
298 break;
299 default:
300 m_qtInputConnectionListener.onSendKeyEventDefaultCase();
301 break;
302 }
303 }
304 return super.sendKeyEvent(event);
305 }
306
307 @Override
308 public boolean setComposingText(CharSequence text, int newCursorPosition)
309 {
310 setClosing(false);
311 return QtNativeInputConnection.setComposingText(text.toString(), newCursorPosition);
312 }
313
314 @Override
315 public boolean setComposingRegion(int start, int end)
316 {
317 setClosing(false);
318 return QtNativeInputConnection.setComposingRegion(start, end);
319 }
320
321 @Override
322 public boolean setSelection(int start, int end)
323 {
324 setClosing(false);
325 return QtNativeInputConnection.setSelection(start, end);
326 }
327}
QString text
void onHideKeyboardRunnableDone(boolean visibility, long hideTimeStamp)
Q_CORE_EXPORT QtJniTypes::Activity activity()
GLboolean r
[2]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLsizei GLenum const void GLuint GLsizei GLfloat * metrics
GLbitfield flags
GLuint start
struct _cl_event * event
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
QNetworkRequest request(url)