Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
QtInputDelegate.java
Go to the documentation of this file.
1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4package org.qtproject.qt.android;
5
6import java.util.List;
7import android.app.Activity;
8import android.content.Context;
9import android.graphics.Rect;
10import android.os.Build;
11import android.os.Bundle;
12import android.os.Handler;
13import android.os.Looper;
14import android.os.ResultReceiver;
15import android.text.method.MetaKeyKeyListener;
16import android.util.DisplayMetrics;
17import android.util.Log;
18import android.view.InputDevice;
19import android.view.KeyCharacterMap;
20import android.view.KeyEvent;
21import android.view.MotionEvent;
22import android.view.WindowInsets;
23import android.view.WindowInsets.Type;
24import android.view.Window;
25import android.view.WindowInsetsAnimation;
26import android.view.WindowInsetsAnimation.Callback;
27import android.view.WindowManager;
28import android.view.View;
29import android.view.ViewTreeObserver;
30import android.view.inputmethod.InputMethodManager;
31import android.window.OnBackInvokedCallback;
32import android.window.OnBackInvokedDispatcher;
33
34class QtInputDelegate implements QtInputConnection.QtInputConnectionListener, QtInputInterface
35{
36
37 private static final String TAG = "QtInputDelegate";
38 // keyboard methods
39 static native void keyDown(int key, int unicode, int modifier, boolean autoRepeat);
40 static native void keyUp(int key, int unicode, int modifier, boolean autoRepeat);
41 static native void keyboardVisibilityChanged(boolean visibility);
42 static native void keyboardGeometryChanged(int x, int y, int width, int height);
43 // keyboard methods
44
45 // dispatch events methods
46 static native boolean dispatchGenericMotionEvent(MotionEvent event);
47 static native boolean dispatchKeyEvent(KeyEvent event);
48 // dispatch events methods
49
50 // handle methods
51 static native void handleLocationChanged(int id, int x, int y);
52 // handle methods
53
54 private QtEditText m_currentEditText = null;
55 private InputMethodManager m_imm;
56
57 // We can't rely on a hardcoded value, because screens have different resolutions.
58 // That is why we assume that the keyboard should be higher than 0.15 of the screen.
59 private static final float KEYBOARD_TO_SCREEN_RATIO = 0.15f;
60
61 private boolean m_keyboardTransitionInProgress = false;
62 private boolean m_keyboardIsVisible = false;
63 private boolean m_isKeyboardHidingAnimationOngoing = false;
64 private long m_showHideTimeStamp = System.nanoTime();
65 private int m_portraitKeyboardHeight = 0;
66 private int m_landscapeKeyboardHeight = 0;
67 private int m_probeKeyboardHeightDelayMs = 50;
68
69 private int m_softInputMode = 0;
70
71 private static Boolean m_tabletEventSupported = null;
72
73 private static int m_oldX, m_oldY;
74
75
76 private long m_metaState;
77 private int m_lastChar = 0;
78 private boolean m_backKeyPressedSent = false;
79
80 private final OnBackInvokedCallback m_backInvokeCallback;
81
82 // Note: because of the circular call to updateFullScreen() from the delegate, we need
83 // a listener to be able to do that call from the delegate, because that's where that
84 // logic lives
88
89 private final KeyboardVisibilityListener m_keyboardVisibilityListener;
90
91 QtInputDelegate(KeyboardVisibilityListener listener)
92 {
93 m_keyboardVisibilityListener = listener;
94 m_backInvokeCallback = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
95 ? () -> {
96 onKeyDown(KeyEvent.KEYCODE_BACK,
97 new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
98 onKeyUp(KeyEvent.KEYCODE_BACK,
99 new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK));
100 }
101 : null;
102 }
103
104 void initInputMethodManager(Activity activity)
105 {
106 m_imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
107 if (m_imm == null)
108 Log.w(TAG, "getSystemService() returned a null InputMethodManager instance");
109
110 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
111 View rootView = activity.getWindow().getDecorView();
112 ViewTreeObserver observer = rootView.getViewTreeObserver();
113 observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
114 private boolean m_lastImeVisibility = false;
115
116 @Override
117 public void onGlobalLayout() {
118 WindowInsets windowInsets = rootView.getRootWindowInsets();
119 if (windowInsets == null)
120 return;
121
122 boolean imeVisible = windowInsets.isVisible(WindowInsets.Type.ime());
123 if (m_lastImeVisibility != imeVisible) {
124 m_lastImeVisibility = imeVisible;
125 setKeyboardVisibility_internal(imeVisible, System.nanoTime());
126 }
127
128 if (!isKeyboardHidden())
129 setKeyboardTransitionInProgress(false);
130 }
131 });
132 }
133 }
134
135 private void setKeyboardTransitionInProgress(boolean state)
136 {
137 if (m_currentEditText == null || m_keyboardTransitionInProgress == state)
138 return;
139
140 m_keyboardTransitionInProgress = state;
141 }
142
143 // QtInputInterface implementation begin
144 @Override
145 public void updateSelection(final int selStart, final int selEnd,
146 final int candidatesStart, final int candidatesEnd)
147 {
148 if (m_imm != null) {
149 QtNative.runAction(() -> {
150 if (m_imm != null) {
151 m_imm.updateSelection(m_currentEditText, selStart, selEnd,
152 candidatesStart, candidatesEnd);
153 }
154 });
155 }
156 }
157
158 private void showKeyboard(Activity activity,
159 final int x, final int y, final int width, final int height,
160 final int inputHints, final int enterKeyType)
161 {
162 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
163 Window window = activity.getWindow();
164 View decorView = window.getDecorView();
165 decorView.setWindowInsetsAnimationCallback(
166 new WindowInsetsAnimation.Callback(
167 WindowInsetsAnimation.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE) {
168 @Override
169 public WindowInsets onProgress(
170 WindowInsets insets, List<WindowInsetsAnimation> animationList) {
171 return insets;
172 }
173 @Override
174 public void onEnd(WindowInsetsAnimation animation) {
175 decorView.setWindowInsetsAnimationCallback(null);
176 if ((animation.getTypeMask() & WindowInsets.Type.ime()) == 0) {
177 QtNativeInputConnection.updateCursorPosition();
178 if (m_softInputMode == 0) {
179 probeForKeyboardHeight(activity, x, y, width, height,
180 inputHints, enterKeyType);
181 }
182 }
183 }
184 });
185 window.getInsetsController().show(Type.ime());
186 } else {
187 if (m_imm == null)
188 return;
189 m_imm.showSoftInput(m_currentEditText, 0, new ResultReceiver(new Handler(Looper.getMainLooper())) {
190 @Override
191 @SuppressWarnings("fallthrough")
192 protected void onReceiveResult(int resultCode, Bundle resultData) {
193 switch (resultCode) {
194 case InputMethodManager.RESULT_SHOWN:
195 QtNativeInputConnection.updateCursorPosition();
196 //FALLTHROUGH
197 case InputMethodManager.RESULT_UNCHANGED_SHOWN:
198 setKeyboardVisibility(true, System.nanoTime());
199 if (m_softInputMode == 0) {
200 probeForKeyboardHeight(activity,
201 x, y, width, height, inputHints, enterKeyType);
202 }
203 break;
204 case InputMethodManager.RESULT_HIDDEN:
205 case InputMethodManager.RESULT_UNCHANGED_HIDDEN:
206 setKeyboardVisibility(false, System.nanoTime());
207 break;
208 }
209 }
210 });
211 }
212 }
213
214 @Override
215 public void showSoftwareKeyboard(Activity activity,
216 final int x, final int y, final int width, final int height,
217 final int inputHints, final int enterKeyType)
218 {
219 if (m_imm == null)
220 return;
221
222 QtNative.runAction(() -> {
223 if (m_imm == null || m_currentEditText == null)
224 return;
225
226 if (updateSoftInputMode(activity, height))
227 return;
228
229 m_currentEditText.setEditTextOptions(enterKeyType, inputHints);
230 m_currentEditText.setLayoutParams(new QtLayout.LayoutParams(width, height, x, y));
231 m_currentEditText.requestFocus();
232 m_currentEditText.postDelayed(() -> {
233 showKeyboard(activity, x, y, width, height, inputHints, enterKeyType);
234 if (m_currentEditText.m_optionsChanged) {
235 m_imm.restartInput(m_currentEditText);
236 m_currentEditText.m_optionsChanged = false;
237 }
238 }, 15);
239 });
240 }
241
242 @Override
243 public int getSelectionHandleWidth()
244 {
245 return m_currentEditText == null ? 0 : m_currentEditText.getSelectionHandleWidth();
246 }
247
248 /* called from the C++ code when the position of the cursor or selection handles needs to
249 be adjusted.
250 mode is one of QAndroidInputContext::CursorHandleShowMode
251 */
252 @Override
253 public void updateHandles(int mode, int editX, int editY, int editButtons,
254 int x1, int y1, int x2, int y2, boolean rtl)
255 {
256 QtNative.runAction(() -> {
257 if (m_currentEditText != null)
258 m_currentEditText.updateHandles(mode, editX, editY, editButtons, x1, y1, x2, y2, rtl);
259 });
260 }
261
262 @Override
263 public QtInputConnection.QtInputConnectionListener getInputConnectionListener()
264 {
265 return this;
266 }
267
268 @Override
269 public void resetSoftwareKeyboard()
270 {
271 if (m_imm == null || m_currentEditText == null)
272 return;
273 m_currentEditText.postDelayed(() -> {
274 if (m_imm == null || m_currentEditText == null)
275 return;
276 m_imm.restartInput(m_currentEditText);
277 m_currentEditText.m_optionsChanged = false;
278 }, 5);
279 }
280
281 @Override
282 public void hideSoftwareKeyboard()
283 {
284 if (m_imm == null || m_currentEditText == null)
285 return;
286
287 m_isKeyboardHidingAnimationOngoing = true;
288 QtNative.runAction(() -> {
289 if (m_imm == null || m_currentEditText == null)
290 return;
291
292 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
293 Activity activity = QtNative.activity();
294 if (activity == null) {
295 Log.w(TAG, "hideSoftwareKeyboard: The activity reference is null");
296 return;
297 }
298 activity.getWindow().getInsetsController().hide(Type.ime());
299 } else {
300 m_imm.hideSoftInputFromWindow(m_currentEditText.getWindowToken(), 0,
301 new ResultReceiver(new Handler(Looper.getMainLooper())) {
302 @Override
303 protected void onReceiveResult(int resultCode, Bundle resultData) {
304 switch (resultCode) {
305 case InputMethodManager.RESULT_SHOWN:
306 case InputMethodManager.RESULT_UNCHANGED_SHOWN:
307 setKeyboardVisibility(true, System.nanoTime());
308 break;
309 case InputMethodManager.RESULT_HIDDEN:
310 case InputMethodManager.RESULT_UNCHANGED_HIDDEN:
311 setKeyboardVisibility(false, System.nanoTime());
312 break;
313 }
314 }
315 });
316 }
317 });
318 }
319
320 // Is the keyboard fully visible i.e. visible and no ongoing animation
321 @Override
322 public boolean isSoftwareKeyboardVisible()
323 {
324 return isKeyboardVisible() && !m_isKeyboardHidingAnimationOngoing;
325 }
326 // QtInputInterface implementation end
327
328 // QtInputConnectionListener methods
329 @Override
330 public boolean keyboardTransitionInProgress() {
331 return m_keyboardTransitionInProgress;
332 }
333
334 @Override
335 public boolean isKeyboardHidden() {
336 Activity activity = QtNative.activity();
337 if (activity == null) {
338 Log.w(TAG, "isKeyboardHidden: The activity reference is null");
339 return true;
340 }
341
342 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
343 Rect r = new Rect();
344 activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
345 DisplayMetrics metrics = new DisplayMetrics();
346 QtDisplayManager.getDisplay(activity).getMetrics(metrics);
347 int screenHeight = metrics.heightPixels;
348 final int kbHeight = screenHeight - r.bottom;
349 return kbHeight < screenHeight * KEYBOARD_TO_SCREEN_RATIO;
350 }
351
352 return !m_keyboardIsVisible;
353 }
354
355 @Override
356 public void onSetClosing(boolean closing) {
357 if (!closing)
358 setKeyboardVisibility(true, System.nanoTime());
359 }
360
361 @Override
362 public void onHideKeyboardRunnableDone(boolean visibility, long hideTimeStamp) {
363 setKeyboardVisibility(visibility, hideTimeStamp);
364 }
365
366 @Override
367 public void onSendKeyEventDefaultCase() {
369 }
370
371 @Override
372 public void onEditTextChanged(QtEditText editText) {
373 setFocusedView(editText);
374 }
375 // QtInputConnectionListener methods
376
377 boolean isKeyboardVisible()
378 {
379 return m_keyboardIsVisible;
380 }
381
382 void setSoftInputMode(int inputMode)
383 {
384 m_softInputMode = inputMode;
385 }
386
387 QtEditText getCurrentQtEditText()
388 {
389 return m_currentEditText;
390 }
391
392 private void keyboardVisibilityUpdated(boolean visibility)
393 {
394 m_isKeyboardHidingAnimationOngoing = false;
395 QtInputDelegate.keyboardVisibilityChanged(visibility);
396 }
397
398 void setKeyboardVisibility(boolean visibility, long timeStamp)
399 {
400 // Since API 30 keyboard visibility changes are tracked by the global layout listener
401 // observing root window insets. There are no manual changes anymore
402 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
403 setKeyboardVisibility_internal(visibility, timeStamp);
404 }
405
406 private void setKeyboardVisibility_internal(boolean visibility, long timeStamp)
407 {
408 if (m_showHideTimeStamp > timeStamp)
409 return;
410 m_showHideTimeStamp = timeStamp;
411
412 if (m_keyboardIsVisible == visibility)
413 return;
414 m_keyboardIsVisible = visibility;
415 keyboardVisibilityUpdated(m_keyboardIsVisible);
416 setKeyboardTransitionInProgress(visibility);
417
418 if (!visibility) {
419 // Hiding the keyboard clears the immersive mode, so we need to set it again.
420 m_keyboardVisibilityListener.onKeyboardVisibilityChange();
421 if (m_currentEditText != null)
422 m_currentEditText.clearFocus();
423 }
424 }
425
426 void setFocusedView(QtEditText currentEditText)
427 {
428 setKeyboardTransitionInProgress(false);
429 m_currentEditText = currentEditText;
430 }
431
432 private boolean updateSoftInputMode(Activity activity, int height)
433 {
434 DisplayMetrics metrics = new DisplayMetrics();
435 QtDisplayManager.getDisplay(activity).getMetrics(metrics);
436
437 // If the screen is in portrait mode than we estimate that keyboard height
438 // will not be higher than 2/5 of the screen. Otherwise we estimate that keyboard height
439 // will not be higher than 2/3 of the screen
440 final int visibleHeight;
441 if (metrics.widthPixels < metrics.heightPixels) {
442 visibleHeight = m_portraitKeyboardHeight != 0 ?
443 m_portraitKeyboardHeight : metrics.heightPixels * 3 / 5;
444 } else {
445 visibleHeight = m_landscapeKeyboardHeight != 0 ?
446 m_landscapeKeyboardHeight : metrics.heightPixels / 3;
447 }
448
449 if (m_softInputMode != 0) {
450 activity.getWindow().setSoftInputMode(m_softInputMode);
451 int stateHidden = WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN;
452 return (m_softInputMode & stateHidden) != 0;
453 } else {
454 int stateUnchanged = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED;
455 if (height > visibleHeight) {
456 int adjustResize = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
457 activity.getWindow().setSoftInputMode(stateUnchanged | adjustResize);
458 } else {
459 int adjustPan = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
460 activity.getWindow().setSoftInputMode(stateUnchanged | adjustPan);
461 }
462 }
463 return false;
464 }
465
466 private void probeForKeyboardHeight(Activity activity, int x, int y,
467 int width, int height, int inputHints, int enterKeyType)
468 {
469 if (m_currentEditText == null) {
470 Log.w(TAG, "probeForKeyboardHeight: null QtEditText");
471 return;
472 }
473 m_currentEditText.postDelayed(() -> {
474 if (!m_keyboardIsVisible)
475 return;
476 DisplayMetrics metrics = new DisplayMetrics();
477 QtDisplayManager.getDisplay(activity).getMetrics(metrics);
478 Rect r = new Rect();
479 activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
480 if (metrics.heightPixels != r.bottom) {
481 if (metrics.widthPixels > metrics.heightPixels) { // landscape
482 if (m_landscapeKeyboardHeight != r.bottom) {
483 m_landscapeKeyboardHeight = r.bottom;
484 showSoftwareKeyboard(activity, x, y, width, height,
485 inputHints, enterKeyType);
486 }
487 } else {
488 if (m_portraitKeyboardHeight != r.bottom) {
489 m_portraitKeyboardHeight = r.bottom;
490 showSoftwareKeyboard(activity, x, y, width, height,
491 inputHints, enterKeyType);
492 }
493 }
494 } else {
495 // no luck ?
496 // maybe the delay was too short, so let's make it longer
497 if (m_probeKeyboardHeightDelayMs < 1000)
498 m_probeKeyboardHeightDelayMs *= 2;
499 }
500 }, m_probeKeyboardHeightDelayMs);
501 }
502
503 boolean onKeyDown(int keyCode, KeyEvent event)
504 {
505 m_metaState = MetaKeyKeyListener.handleKeyDown(m_metaState, keyCode, event);
506 int metaState = MetaKeyKeyListener.getMetaState(m_metaState) | event.getMetaState();
507 int c = event.getUnicodeChar(metaState);
508 int lc = c;
509 m_metaState = MetaKeyKeyListener.adjustMetaAfterKeypress(m_metaState);
510
511 if ((c & KeyCharacterMap.COMBINING_ACCENT) != 0) {
512 c = c & KeyCharacterMap.COMBINING_ACCENT_MASK;
513 c = KeyEvent.getDeadChar(m_lastChar, c);
514 }
515
516 if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP
517 || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
518 || keyCode == KeyEvent.KEYCODE_MUTE)
519 && System.getenv("QT_ANDROID_VOLUME_KEYS") == null) {
520 return false;
521 }
522
523 m_lastChar = lc;
524 if (keyCode == KeyEvent.KEYCODE_BACK) {
525 m_backKeyPressedSent = !isKeyboardVisible();
526 if (!m_backKeyPressedSent)
527 return true;
528 }
529
530 QtInputDelegate.keyDown(keyCode, c, event.getMetaState(), event.getRepeatCount() > 0);
531
532 return true;
533 }
534
535 boolean onKeyUp(int keyCode, KeyEvent event)
536 {
537 if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP
538 || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
539 || keyCode == KeyEvent.KEYCODE_MUTE)
540 && System.getenv("QT_ANDROID_VOLUME_KEYS") == null) {
541 return false;
542 }
543
544 if (keyCode == KeyEvent.KEYCODE_BACK && !m_backKeyPressedSent) {
546 setKeyboardVisibility(false, System.nanoTime());
547 return true;
548 }
549
550 m_metaState = MetaKeyKeyListener.handleKeyUp(m_metaState, keyCode, event);
551 boolean autoRepeat = event.getRepeatCount() > 0;
552 QtInputDelegate.keyUp(keyCode, event.getUnicodeChar(), event.getMetaState(), autoRepeat);
553
554 return true;
555 }
556
557 boolean handleDispatchKeyEvent(KeyEvent event)
558 {
559 if (event.getAction() == KeyEvent.ACTION_MULTIPLE
560 && event.getCharacters() != null
561 && event.getCharacters().length() == 1
562 && event.getKeyCode() == 0) {
563 keyDown(0, event.getCharacters().charAt(0), event.getMetaState(),
564 event.getRepeatCount() > 0);
565 keyUp(0, event.getCharacters().charAt(0), event.getMetaState(),
566 event.getRepeatCount() > 0);
567 }
568
569 return dispatchKeyEvent(event);
570 }
571
572 boolean handleDispatchGenericMotionEvent(MotionEvent event)
573 {
575 }
576
577 void registerBackGestureCallback(Activity activity)
578 {
579 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU)
580 return;
581 try {
582 activity.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
583 OnBackInvokedDispatcher.PRIORITY_SYSTEM_NAVIGATION_OBSERVER,
584 m_backInvokeCallback);
585 } catch (IllegalStateException ise) {
586 Log.e(TAG, "Failed to register OnBackInvokedCallback: " + ise.getMessage());
587 }
588 }
589
590 void unregisterBackGestureCallback(Activity activity)
591 {
592 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU)
593 return;
594 try {
595 activity.getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(
596 m_backInvokeCallback);
597 } catch (IllegalStateException ise) {
598 Log.e(TAG, "Failed to unregister OnBackInvokedCallback: " + ise.getMessage());
599 }
600 }
601
603 // Mouse and Touch Input //
605
606 // tablet methods
607 static native boolean isTabletEventSupported();
608 static native void tabletEvent(int winId, int deviceId, long time, int action,
609 int pointerType, int buttonState, float x, float y,
610 float pressure);
611 // tablet methods
612
613 // pointer methods
614 static native void mouseDown(int winId, int x, int y, int mouseButtonState);
615 static native void mouseUp(int winId, int x, int y, int mouseButtonState);
616 static native void mouseMove(int winId, int x, int y, int mouseButtonState);
617 static native void mouseWheel(int winId, int x, int y, float hDelta, float vDelta);
618 static native void touchBegin(int winId);
619 static native void touchAdd(int winId, int pointerId, int action, boolean primary,
620 int x, int y, float major, float minor, float rotation,
621 float pressure);
622 static native void touchEnd(int winId, int action);
623 static native void touchCancel(int winId);
624 static native void longPress(int winId, int x, int y);
625 // pointer methods
626
627 static private int getAction(int index, MotionEvent event)
628 {
629 int action = event.getActionMasked();
630 if (action == MotionEvent.ACTION_MOVE) {
631 int hsz = event.getHistorySize();
632 if (hsz > 0) {
633 float x = event.getX(index);
634 float y = event.getY(index);
635 for (int h = 0; h < hsz; ++h) {
636 if ( event.getHistoricalX(index, h) != x ||
637 event.getHistoricalY(index, h) != y )
638 return 1;
639 }
640 return 2;
641 }
642 return 1;
643 }
644 if (action == MotionEvent.ACTION_DOWN
645 || action == MotionEvent.ACTION_POINTER_DOWN && index == event.getActionIndex()) {
646 return 0;
647 } else if (action == MotionEvent.ACTION_UP
648 || action == MotionEvent.ACTION_POINTER_UP && index == event.getActionIndex()) {
649 return 3;
650 }
651 return 2;
652 }
653
654 static void sendTouchEvent(MotionEvent event, int id)
655 {
656 int pointerType = 0;
657
658 if (m_tabletEventSupported == null)
659 m_tabletEventSupported = isTabletEventSupported();
660
661 switch (event.getToolType(0)) {
662 case MotionEvent.TOOL_TYPE_STYLUS:
663 pointerType = 1; // QTabletEvent::Pen
664 break;
665 case MotionEvent.TOOL_TYPE_ERASER:
666 pointerType = 3; // QTabletEvent::Eraser
667 break;
668 }
669
670 if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
671 sendMouseEvent(event, id);
672 } else if (m_tabletEventSupported && pointerType != 0) {
673 tabletEvent(id, event.getDeviceId(), event.getEventTime(), event.getActionMasked(),
674 pointerType, event.getButtonState(),
675 event.getX(), event.getY(), event.getPressure());
676 } else {
677 touchBegin(id);
678 for (int i = 0; i < event.getPointerCount(); ++i) {
679 touchAdd(id,
680 event.getPointerId(i),
681 getAction(i, event),
682 i == 0,
683 (int)event.getX(i),
684 (int)event.getY(i),
685 event.getTouchMajor(i),
686 event.getTouchMinor(i),
687 event.getOrientation(i),
688 event.getPressure(i));
689 }
690
691 switch (event.getAction()) {
692 case MotionEvent.ACTION_DOWN:
693 touchEnd(id, 0);
694 break;
695
696 case MotionEvent.ACTION_UP:
697 touchEnd(id, 2);
698 break;
699
700 case MotionEvent.ACTION_CANCEL:
701 touchCancel(id);
702 break;
703
704 default:
705 touchEnd(id, 1);
706 }
707 }
708 }
709
710 static void sendTrackballEvent(MotionEvent event, int id)
711 {
712 sendMouseEvent(event,id);
713 }
714
715 static boolean sendGenericMotionEvent(MotionEvent event, int id)
716 {
717 int scrollOrHoverMove = MotionEvent.ACTION_SCROLL | MotionEvent.ACTION_HOVER_MOVE;
718 int pointerDeviceModifier = (event.getSource() & InputDevice.SOURCE_CLASS_POINTER);
719 boolean isPointerDevice = pointerDeviceModifier == InputDevice.SOURCE_CLASS_POINTER;
720
721 if ((event.getAction() & scrollOrHoverMove) == 0 || !isPointerDevice )
722 return false;
723
724 return sendMouseEvent(event, id);
725 }
726
727 static boolean sendMouseEvent(MotionEvent event, int id)
728 {
729 switch (event.getActionMasked()) {
730 case MotionEvent.ACTION_UP:
731 mouseUp(id, (int) event.getX(), (int) event.getY(), event.getButtonState());
732 break;
733
734 case MotionEvent.ACTION_DOWN:
735 mouseDown(id, (int) event.getX(), (int) event.getY(), event.getButtonState());
736 m_oldX = (int) event.getX();
737 m_oldY = (int) event.getY();
738 break;
739 case MotionEvent.ACTION_HOVER_MOVE:
740 case MotionEvent.ACTION_MOVE:
741 if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
742 mouseMove(id, (int) event.getX(), (int) event.getY(), event.getButtonState());
743 } else {
744 int dx = (int) (event.getX() - m_oldX);
745 int dy = (int) (event.getY() - m_oldY);
746 if (Math.abs(dx) > 5 || Math.abs(dy) > 5) {
747 mouseMove(id, (int) event.getX(), (int) event.getY(), event.getButtonState());
748 m_oldX = (int) event.getX();
749 m_oldY = (int) event.getY();
750 }
751 }
752 break;
753 case MotionEvent.ACTION_SCROLL:
754 mouseWheel(id, (int) event.getX(), (int) event.getY(),
755 event.getAxisValue(MotionEvent.AXIS_HSCROLL),
756 event.getAxisValue(MotionEvent.AXIS_VSCROLL));
757 break;
758 default:
759 return false;
760 }
761 return true;
762 }
763}
PeripheralState state
QPainter Context
void mouseMove(QWindow *window, QPoint pos=QPoint(), int delay=-1)
Definition qtestmouse.h:147
void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd)
void showSoftwareKeyboard(int left, int top, int width, int height, int inputHints, int enterKeyType)
bool isSoftwareKeyboardVisible()
void updateHandles(int mode, QPoint editMenuPos, uint32_t editButtons, QPoint cursor, QPoint anchor, bool rtl)
Q_CORE_EXPORT QtJniTypes::Activity activity()
self window
[2]
#define TAG(x)
static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, QtJniTypes::MotionEvent event)
static jboolean dispatchKeyEvent(JNIEnv *, jclass, QtJniTypes::KeyEvent event)
GLint GLint GLint GLint GLint x
GLenum mode
GLuint64 key
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLboolean r
GLuint GLfloat GLfloat GLfloat x1
GLsizei GLenum const void GLuint GLsizei GLfloat * metrics
GLuint index
GLint GLsizei width
GLint y
GLfloat GLfloat GLfloat GLfloat h
struct _cl_event * event
const GLubyte * c
GLfixed GLfixed GLfixed y2
GLfixed GLfixed x2
@ Handler
Type
[0]
static QPointingDevice::PointerType pointerType(unsigned currentCursor)
Definition moc.h:33