4package org.qtproject.qt.android;
6import android.app.Activity;
7import android.content.Context;
8import android.graphics.Rect;
9import android.os.Bundle;
10import android.os.Handler;
11import android.os.ResultReceiver;
12import android.text.method.MetaKeyKeyListener;
13import android.util.DisplayMetrics;
14import android.view.InputDevice;
15import android.view.KeyCharacterMap;
16import android.view.KeyEvent;
17import android.view.MotionEvent;
18import android.view.WindowManager;
19import android.view.inputmethod.InputMethodManager;
24class QtInputDelegate
implements QtInputConnection.QtInputConnectionListener {
27 public static native
void keyDown(
int key,
int unicode,
int modifier,
boolean autoRepeat);
28 public static native
void keyUp(
int key,
int unicode,
int modifier,
boolean autoRepeat);
29 public static native
void keyboardVisibilityChanged(
boolean visibility);
30 public static native
void keyboardGeometryChanged(
int x,
int y,
int width,
int height);
34 public static native
boolean dispatchGenericMotionEvent(MotionEvent
event);
35 public static native
boolean dispatchKeyEvent(
KeyEvent event);
39 public static native
void handleLocationChanged(
int id,
int x,
int y);
42 private QtEditText m_currentEditText =
null;
43 private final InputMethodManager m_imm;
45 private boolean m_keyboardIsVisible =
false;
46 private boolean m_isKeyboardHidingAnimationOngoing =
false;
47 private long m_showHideTimeStamp =
System.nanoTime();
48 private int m_portraitKeyboardHeight = 0;
49 private int m_landscapeKeyboardHeight = 0;
50 private int m_probeKeyboardHeightDelayMs = 50;
54 private EditPopupMenu m_editPopupMenu;
56 private int m_softInputMode = 0;
59 private static final int CursorHandleNotShown = 0;
60 private static final int CursorHandleShowNormal = 1;
61 private static final int CursorHandleShowSelection = 2;
62 private static final int CursorHandleShowEdit = 0x100;
65 public static final int IdCursorHandle = 1;
66 public static final int IdLeftHandle = 2;
67 public static final int IdRightHandle = 3;
69 private static Boolean m_tabletEventSupported =
null;
71 private static int m_oldX, m_oldY;
74 private long m_metaState;
75 private int m_lastChar = 0;
76 private boolean m_backKeyPressedSent =
false;
89 this.m_keyboardVisibilityListener = listener;
90 m_imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
95 public void onSetClosing(
boolean closing) {
97 setKeyboardVisibility(
true, System.nanoTime());
101 public void onHideKeyboardRunnableDone(
boolean visibility,
long hideTimeStamp) {
102 setKeyboardVisibility(visibility, hideTimeStamp);
106 public void onSendKeyEventDefaultCase() {
107 hideSoftwareKeyboard();
111 public boolean isKeyboardVisible()
113 return m_keyboardIsVisible;
118 public boolean isSoftwareKeyboardVisible()
120 return isKeyboardVisible() && !m_isKeyboardHidingAnimationOngoing;
123 void setSoftInputMode(
int inputMode)
125 m_softInputMode = inputMode;
128 QtEditText getCurrentQtEditText()
130 return m_currentEditText;
133 void setEditPopupMenu(EditPopupMenu editPopupMenu)
135 m_editPopupMenu = editPopupMenu;
138 private void keyboardVisibilityUpdated(
boolean visibility)
140 m_isKeyboardHidingAnimationOngoing =
false;
141 QtInputDelegate.keyboardVisibilityChanged(visibility);
144 public void setKeyboardVisibility(
boolean visibility,
long timeStamp)
146 if (m_showHideTimeStamp > timeStamp)
148 m_showHideTimeStamp = timeStamp;
150 if (m_keyboardIsVisible == visibility)
152 m_keyboardIsVisible = visibility;
153 keyboardVisibilityUpdated(m_keyboardIsVisible);
162 public void resetSoftwareKeyboard()
164 if (m_imm ==
null || m_currentEditText ==
null)
166 m_currentEditText.postDelayed(() -> {
167 m_imm.restartInput(m_currentEditText);
168 m_currentEditText.m_optionsChanged =
false;
172 void setFocusedView(QtEditText currentEditText)
174 m_currentEditText = currentEditText;
177 public void showSoftwareKeyboard(Activity activity, QtLayout
layout,
179 final int inputHints,
final int enterKeyType)
181 QtNative.runAction(() -> {
182 if (m_imm ==
null || m_currentEditText ==
null)
185 if (updateSoftInputMode(activity,
height))
188 m_currentEditText.setEditTextOptions(enterKeyType, inputHints);
190 m_currentEditText.postDelayed(() -> {
191 m_imm.showSoftInput(m_currentEditText, 0,
new ResultReceiver(
new Handler()) {
193 protected void onReceiveResult(
int resultCode,
Bundle resultData) {
194 switch (resultCode) {
195 case InputMethodManager.RESULT_SHOWN:
196 QtNativeInputConnection.updateCursorPosition();
198 case InputMethodManager.RESULT_UNCHANGED_SHOWN:
199 setKeyboardVisibility(
true,
System.nanoTime());
200 if (m_softInputMode == 0) {
201 probeForKeyboardHeight(
layout, activity,
205 case InputMethodManager.RESULT_HIDDEN:
206 case InputMethodManager.RESULT_UNCHANGED_HIDDEN:
207 setKeyboardVisibility(
false,
System.nanoTime());
212 if (m_currentEditText.m_optionsChanged) {
213 m_imm.restartInput(m_currentEditText);
214 m_currentEditText.m_optionsChanged =
false;
220 private boolean updateSoftInputMode(Activity activity,
int height)
222 DisplayMetrics
metrics =
new DisplayMetrics();
228 final int visibleHeight;
230 visibleHeight = m_portraitKeyboardHeight != 0 ?
231 m_portraitKeyboardHeight : metrics.heightPixels * 3 / 5;
233 visibleHeight = m_landscapeKeyboardHeight != 0 ?
234 m_landscapeKeyboardHeight : metrics.heightPixels / 3;
237 if (m_softInputMode != 0) {
238 activity.getWindow().setSoftInputMode(m_softInputMode);
239 int stateHidden = WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN;
240 return (m_softInputMode & stateHidden) != 0;
242 int stateUnchanged = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED;
243 if (
height > visibleHeight) {
244 int adjustResize = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
245 activity.getWindow().setSoftInputMode(stateUnchanged | adjustResize);
247 int adjustPan = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
248 activity.getWindow().setSoftInputMode(stateUnchanged | adjustPan);
254 private void probeForKeyboardHeight(QtLayout
layout, Activity activity,
int x,
int y,
255 int width,
int height,
int inputHints,
int enterKeyType)
257 layout.postDelayed(() -> {
258 if (!m_keyboardIsVisible)
260 DisplayMetrics
metrics =
new DisplayMetrics();
263 activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(
r);
264 if (
metrics.heightPixels !=
r.bottom) {
266 if (m_landscapeKeyboardHeight !=
r.bottom) {
267 m_landscapeKeyboardHeight =
r.bottom;
269 inputHints, enterKeyType);
272 if (m_portraitKeyboardHeight !=
r.bottom) {
273 m_portraitKeyboardHeight =
r.bottom;
275 inputHints, enterKeyType);
281 if (m_probeKeyboardHeightDelayMs < 1000)
282 m_probeKeyboardHeightDelayMs *= 2;
284 }, m_probeKeyboardHeightDelayMs);
287 public void hideSoftwareKeyboard()
289 m_isKeyboardHidingAnimationOngoing =
true;
290 QtNative.runAction(() -> {
291 if (m_imm ==
null || m_currentEditText ==
null)
294 m_imm.hideSoftInputFromWindow(m_currentEditText.getWindowToken(), 0,
295 new ResultReceiver(
new Handler()) {
297 protected void onReceiveResult(
int resultCode,
Bundle resultData) {
298 switch (resultCode) {
299 case InputMethodManager.RESULT_SHOWN:
300 case InputMethodManager.RESULT_UNCHANGED_SHOWN:
301 setKeyboardVisibility(
true,
System.nanoTime());
303 case InputMethodManager.RESULT_HIDDEN:
304 case InputMethodManager.RESULT_UNCHANGED_HIDDEN:
305 setKeyboardVisibility(
false,
System.nanoTime());
314 public void updateSelection(
final int selStart,
final int selEnd,
315 final int candidatesStart,
final int candidatesEnd)
317 QtNative.runAction(() -> {
321 m_imm.updateSelection(m_currentEditText, selStart, selEnd, candidatesStart, candidatesEnd);
326 public int getSelectHandleWidth()
329 if (m_leftSelectionHandle !=
null && m_rightSelectionHandle !=
null) {
330 width = Math.max(m_leftSelectionHandle.width(), m_rightSelectionHandle.width());
331 }
else if (m_cursorHandle !=
null) {
332 width = m_cursorHandle.width();
342 public void updateHandles(Activity activity, QtLayout
layout,
int mode,
343 int editX,
int editY,
int editButtons,
344 int x1,
int y1,
int x2,
int y2,
boolean rtl)
346 QtNative.runAction(() -> updateHandleImpl(activity,
layout,
mode, editX, editY, editButtons,
350 private void updateHandleImpl(Activity activity, QtLayout
layout,
int mode,
351 int editX,
int editY,
int editButtons,
352 int x1,
int y1,
int x2,
int y2,
boolean rtl)
356 case CursorHandleNotShown:
357 if (m_cursorHandle !=
null) {
358 m_cursorHandle.hide();
359 m_cursorHandle =
null;
361 if (m_rightSelectionHandle !=
null) {
362 m_rightSelectionHandle.hide();
363 m_leftSelectionHandle.hide();
364 m_rightSelectionHandle =
null;
365 m_leftSelectionHandle =
null;
367 if (m_editPopupMenu !=
null)
368 m_editPopupMenu.hide();
371 case CursorHandleShowNormal:
372 if (m_cursorHandle ==
null) {
374 android.R.attr.textSelectHandle,
false);
376 m_cursorHandle.setPosition(
x1,
y1);
377 if (m_rightSelectionHandle !=
null) {
378 m_rightSelectionHandle.hide();
379 m_leftSelectionHandle.hide();
380 m_rightSelectionHandle =
null;
381 m_leftSelectionHandle =
null;
385 case CursorHandleShowSelection:
386 if (m_rightSelectionHandle ==
null) {
388 !rtl ? android.R.attr.textSelectHandleLeft :
389 android.
R.attr.textSelectHandleRight,
392 !rtl ? android.R.attr.textSelectHandleRight :
393 android.
R.attr.textSelectHandleLeft,
396 m_leftSelectionHandle.setPosition(
x1,
y1);
397 m_rightSelectionHandle.setPosition(
x2,
y2);
398 if (m_cursorHandle !=
null) {
399 m_cursorHandle.hide();
400 m_cursorHandle =
null;
402 mode |= CursorHandleShowEdit;
406 if (!QtClipboardManager.hasClipboardText(activity))
407 editButtons &= ~EditContextView.PASTE_BUTTON;
409 if (m_editPopupMenu !=
null) {
410 if ((
mode & CursorHandleShowEdit) == CursorHandleShowEdit && editButtons != 0) {
411 m_editPopupMenu.setPosition(editX, editY, editButtons,
412 m_cursorHandle, m_leftSelectionHandle, m_rightSelectionHandle);
414 m_editPopupMenu.hide();
421 m_metaState = MetaKeyKeyListener.handleKeyDown(m_metaState, keyCode,
event);
422 int metaState = MetaKeyKeyListener.getMetaState(m_metaState) |
event.getMetaState();
423 int c =
event.getUnicodeChar(metaState);
425 m_metaState = MetaKeyKeyListener.adjustMetaAfterKeypress(m_metaState);
427 if ((
c & KeyCharacterMap.COMBINING_ACCENT) != 0) {
428 c =
c & KeyCharacterMap.COMBINING_ACCENT_MASK;
432 if ((keyCode ==
KeyEvent.KEYCODE_VOLUME_UP
433 || keyCode ==
KeyEvent.KEYCODE_VOLUME_DOWN
434 || keyCode ==
KeyEvent.KEYCODE_MUTE)
435 &&
System.getenv(
"QT_ANDROID_VOLUME_KEYS") ==
null) {
440 if (keyCode ==
KeyEvent.KEYCODE_BACK) {
441 m_backKeyPressedSent = !isKeyboardVisible();
442 if (!m_backKeyPressedSent)
446 QtInputDelegate.keyDown(keyCode,
c,
event.getMetaState(),
event.getRepeatCount() > 0);
453 if ((keyCode ==
KeyEvent.KEYCODE_VOLUME_UP
454 || keyCode ==
KeyEvent.KEYCODE_VOLUME_DOWN
455 || keyCode ==
KeyEvent.KEYCODE_MUTE)
456 &&
System.getenv(
"QT_ANDROID_VOLUME_KEYS") ==
null) {
460 if (keyCode ==
KeyEvent.KEYCODE_BACK && !m_backKeyPressedSent) {
461 hideSoftwareKeyboard();
462 setKeyboardVisibility(
false,
System.nanoTime());
466 m_metaState = MetaKeyKeyListener.handleKeyUp(m_metaState, keyCode,
event);
467 boolean autoRepeat =
event.getRepeatCount() > 0;
468 QtInputDelegate.keyUp(keyCode,
event.getUnicodeChar(),
event.getMetaState(), autoRepeat);
476 &&
event.getCharacters() !=
null
477 &&
event.getCharacters().length() == 1
478 &&
event.getKeyCode() == 0) {
479 keyDown(0,
event.getCharacters().charAt(0),
event.getMetaState(),
480 event.getRepeatCount() > 0);
481 keyUp(0,
event.getCharacters().charAt(0),
event.getMetaState(),
482 event.getRepeatCount() > 0);
485 return dispatchKeyEvent(
event);
488 public boolean handleDispatchGenericMotionEvent(MotionEvent
event)
490 return dispatchGenericMotionEvent(
event);
498 public static native
boolean isTabletEventSupported();
499 public static native
void tabletEvent(
int winId,
int deviceId,
long time,
int action,
505 public static native
void mouseDown(
int winId,
int x,
int y,
int mouseButtonState);
506 public static native
void mouseUp(
int winId,
int x,
int y,
int mouseButtonState);
507 public static native
void mouseMove(
int winId,
int x,
int y);
508 public static native
void mouseWheel(
int winId,
int x,
int y,
float hDelta,
float vDelta);
509 public static native
void touchBegin(
int winId);
510 public static native
void touchAdd(
int winId,
int pointerId,
int action,
boolean primary,
511 int x,
int y,
float major,
float minor,
float rotation,
513 public static native
void touchEnd(
int winId,
int action);
514 public static native
void touchCancel(
int winId);
515 public static native
void longPress(
int winId,
int x,
int y);
518 static private int getAction(
int index, MotionEvent
event)
520 int action =
event.getActionMasked();
521 if (action == MotionEvent.ACTION_MOVE) {
522 int hsz =
event.getHistorySize();
524 float x =
event.getX(
index);
525 float y =
event.getY(
index);
526 for (
int h = 0;
h < hsz; ++
h) {
535 if (action == MotionEvent.ACTION_DOWN
536 || action == MotionEvent.ACTION_POINTER_DOWN &&
index ==
event.getActionIndex()) {
538 }
else if (action == MotionEvent.ACTION_UP
539 || action == MotionEvent.ACTION_POINTER_UP &&
index ==
event.getActionIndex()) {
545 static public void sendTouchEvent(MotionEvent
event,
int id)
549 if (m_tabletEventSupported ==
null)
550 m_tabletEventSupported = isTabletEventSupported();
552 switch (
event.getToolType(0)) {
553 case MotionEvent.TOOL_TYPE_STYLUS:
556 case MotionEvent.TOOL_TYPE_ERASER:
561 if (
event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
562 sendMouseEvent(
event,
id);
563 }
else if (m_tabletEventSupported &&
pointerType != 0) {
564 tabletEvent(
id,
event.getDeviceId(),
event.getEventTime(),
event.getActionMasked(),
569 for (
int i = 0;
i <
event.getPointerCount(); ++
i) {
582 switch (
event.getAction()) {
583 case MotionEvent.ACTION_DOWN:
587 case MotionEvent.ACTION_UP:
591 case MotionEvent.ACTION_CANCEL:
601 static public void sendTrackballEvent(MotionEvent
event,
int id)
603 sendMouseEvent(
event,
id);
606 static public boolean sendGenericMotionEvent(MotionEvent
event,
int id)
608 int scrollOrHoverMove = MotionEvent.ACTION_SCROLL | MotionEvent.ACTION_HOVER_MOVE;
609 int pointerDeviceModifier = (
event.getSource() & InputDevice.SOURCE_CLASS_POINTER);
610 boolean isPointerDevice = pointerDeviceModifier == InputDevice.SOURCE_CLASS_POINTER;
612 if ((
event.getAction() & scrollOrHoverMove) == 0 || !isPointerDevice )
615 return sendMouseEvent(
event,
id);
618 static public boolean sendMouseEvent(MotionEvent
event,
int id)
620 switch (
event.getActionMasked()) {
621 case MotionEvent.ACTION_UP:
622 mouseUp(
id, (
int)
event.getX(), (
int)
event.getY(),
event.getButtonState());
625 case MotionEvent.ACTION_DOWN:
626 mouseDown(
id, (
int)
event.getX(), (
int)
event.getY(),
event.getButtonState());
627 m_oldX = (int)
event.getX();
628 m_oldY = (int)
event.getY();
630 case MotionEvent.ACTION_HOVER_MOVE:
631 case MotionEvent.ACTION_MOVE:
632 if (
event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
633 mouseMove(
id, (
int)
event.getX(), (
int)
event.getY());
635 int dx = (int) (
event.getX() - m_oldX);
636 int dy = (int) (
event.getY() - m_oldY);
637 if (Math.abs(dx) > 5 || Math.abs(dy) > 5) {
638 mouseMove(
id, (
int)
event.getX(), (
int)
event.getY());
639 m_oldX = (int)
event.getX();
640 m_oldY = (int)
event.getY();
644 case MotionEvent.ACTION_SCROLL:
645 mouseWheel(
id, (
int)
event.getX(), (
int)
event.getY(),
646 event.getAxisValue(MotionEvent.AXIS_HSCROLL),
647 event.getAxisValue(MotionEvent.AXIS_VSCROLL));
Q_CORE_EXPORT QtJniTypes::Activity activity()
GLint GLint GLint GLint GLint x
[0]
GLint GLsizei GLsizei height
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLuint GLfloat GLfloat GLfloat x1
GLsizei GLenum const void GLuint GLsizei GLfloat * metrics
GLfloat GLfloat GLfloat GLfloat h
GLfixed GLfixed GLfixed y2
static QPointingDevice::PointerType pointerType(unsigned currentCursor)