1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org> 4 ** Copyright (C) 2016 Olivier Goffart <ogoffart@woboq.com> 5 ** Contact: http://www.qt.io/licensing/ 6 ** 7 ** This file is part of the plugins of the Qt Toolkit. 8 ** 9 ** $QT_BEGIN_LICENSE:LGPL$ 10 ** Commercial License Usage 11 ** Licensees holding valid commercial Qt licenses may use this file in 12 ** accordance with the commercial license agreement provided with the 13 ** Software or, alternatively, in accordance with the terms contained in 14 ** a written agreement between you and The Qt Company. For licensing terms 15 ** and conditions see https://www.qt.io/terms-conditions. For further 16 ** information use the contact form at https://www.qt.io/contact-us. 17 ** 18 ** GNU Lesser General Public License Usage 19 ** Alternatively, this file may be used under the terms of the GNU Lesser 20 ** General Public License version 3 as published by the Free Software 21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the 22 ** packaging of this file. Please review the following information to 23 ** ensure the GNU Lesser General Public License version 3 requirements 24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 25 ** 26 ** GNU General Public License Usage 27 ** Alternatively, this file may be used under the terms of the GNU 28 ** General Public License version 2.0 or (at your option) the GNU General 29 ** Public license version 3 or any later version approved by the KDE Free 30 ** Qt Foundation. The licenses are as published by the Free Software 31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 32 ** included in the packaging of this file. Please review the following 33 ** information to ensure the GNU General Public License requirements will 34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and 35 ** https://www.gnu.org/licenses/gpl-3.0.html. 36 ** 37 ** $QT_END_LICENSE$ 38 ** 39 ****************************************************************************/ 40 41 #include <QtGui/qtguiglobal.h> 42 43 #include "androidjniinput.h" 44 #include "androidjnimain.h" 45 #include "qandroidplatformintegration.h" 46 47 #include <qpa/qwindowsysteminterface.h> 48 #include <QTouchEvent> 49 #include <QPointer> 50 51 #include <QGuiApplication> 52 #include <QDebug> 53 #include <QtMath> 54 55 QT_BEGIN_NAMESPACE 56 57 using namespace QtAndroid; 58 59 namespace QtAndroidInput 60 { 61 static bool m_ignoreMouseEvents = false; 62 static bool m_softwareKeyboardVisible = false; 63 static QRect m_softwareKeyboardRect; 64 65 static QList<QWindowSystemInterface::TouchPoint> m_touchPoints; 66 67 static QPointer<QWindow> m_mouseGrabber; 68 updateSelection(int selStart,int selEnd,int candidatesStart,int candidatesEnd)69 void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd) 70 { 71 #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL 72 qDebug() << ">>> UPDATESELECTION" << selStart << selEnd << candidatesStart << candidatesEnd; 73 #endif 74 QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), 75 "updateSelection", 76 "(IIII)V", 77 selStart, 78 selEnd, 79 candidatesStart, 80 candidatesEnd); 81 } 82 showSoftwareKeyboard(int left,int top,int width,int height,int inputHints,int enterKeyType)83 void showSoftwareKeyboard(int left, int top, int width, int height, int inputHints, int enterKeyType) 84 { 85 QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), 86 "showSoftwareKeyboard", 87 "(IIIIII)V", 88 left, 89 top, 90 width, 91 height, 92 inputHints, 93 enterKeyType 94 ); 95 #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL 96 qDebug() << "@@@ SHOWSOFTWAREKEYBOARD" << left << top << width << height << inputHints << enterKeyType; 97 #endif 98 } 99 resetSoftwareKeyboard()100 void resetSoftwareKeyboard() 101 { 102 QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "resetSoftwareKeyboard"); 103 #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL 104 qDebug("@@@ RESETSOFTWAREKEYBOARD"); 105 #endif 106 } 107 hideSoftwareKeyboard()108 void hideSoftwareKeyboard() 109 { 110 QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "hideSoftwareKeyboard"); 111 #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL 112 qDebug("@@@ HIDESOFTWAREKEYBOARD"); 113 #endif 114 } 115 isSoftwareKeyboardVisible()116 bool isSoftwareKeyboardVisible() 117 { 118 return m_softwareKeyboardVisible; 119 } 120 softwareKeyboardRect()121 QRect softwareKeyboardRect() 122 { 123 return m_softwareKeyboardRect; 124 } 125 updateHandles(int mode,QPoint editMenuPos,uint32_t editButtons,QPoint cursor,QPoint anchor,bool rtl)126 void updateHandles(int mode, QPoint editMenuPos, uint32_t editButtons, QPoint cursor, QPoint anchor, bool rtl) 127 { 128 QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "updateHandles", "(IIIIIIIIZ)V", 129 mode, editMenuPos.x(), editMenuPos.y(), editButtons, 130 cursor.x(), cursor.y(), 131 anchor.x(), anchor.y(), rtl); 132 } 133 mouseDown(JNIEnv *,jobject,jint,jint x,jint y)134 static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y) 135 { 136 if (m_ignoreMouseEvents) 137 return; 138 139 QPoint globalPos(x,y); 140 QWindow *tlw = topLevelWindowAt(globalPos); 141 m_mouseGrabber = tlw; 142 QPoint localPos = tlw ? (globalPos - tlw->position()) : globalPos; 143 QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos, 144 Qt::MouseButtons(Qt::LeftButton), 145 Qt::LeftButton, QEvent::MouseButtonPress); 146 } 147 mouseUp(JNIEnv *,jobject,jint,jint x,jint y)148 static void mouseUp(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y) 149 { 150 QPoint globalPos(x,y); 151 QWindow *tlw = m_mouseGrabber.data(); 152 if (!tlw) 153 tlw = topLevelWindowAt(globalPos); 154 QPoint localPos = tlw ? (globalPos -tlw->position()) : globalPos; 155 QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos, 156 Qt::MouseButtons(Qt::NoButton), 157 Qt::LeftButton, QEvent::MouseButtonRelease); 158 m_ignoreMouseEvents = false; 159 m_mouseGrabber = 0; 160 } 161 mouseMove(JNIEnv *,jobject,jint,jint x,jint y)162 static void mouseMove(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y) 163 { 164 165 if (m_ignoreMouseEvents) 166 return; 167 168 QPoint globalPos(x,y); 169 QWindow *tlw = m_mouseGrabber.data(); 170 if (!tlw) 171 tlw = topLevelWindowAt(globalPos); 172 QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos; 173 QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos, 174 Qt::MouseButtons(m_mouseGrabber ? Qt::LeftButton : Qt::NoButton), 175 Qt::NoButton, QEvent::MouseMove); 176 } 177 mouseWheel(JNIEnv *,jobject,jint,jint x,jint y,jfloat hdelta,jfloat vdelta)178 static void mouseWheel(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y, jfloat hdelta, jfloat vdelta) 179 { 180 if (m_ignoreMouseEvents) 181 return; 182 183 QPoint globalPos(x,y); 184 QWindow *tlw = m_mouseGrabber.data(); 185 if (!tlw) 186 tlw = topLevelWindowAt(globalPos); 187 QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos; 188 QPoint angleDelta(hdelta * 120, vdelta * 120); 189 190 QWindowSystemInterface::handleWheelEvent(tlw, 191 localPos, 192 globalPos, 193 QPoint(), 194 angleDelta); 195 } 196 longPress(JNIEnv *,jobject,jint,jint x,jint y)197 static void longPress(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y) 198 { 199 QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext(); 200 if (inputContext && qGuiApp) 201 QMetaObject::invokeMethod(inputContext, "longPress", Q_ARG(int, x), Q_ARG(int, y)); 202 203 //### TODO: add proper API for Qt 5.2 204 static bool rightMouseFromLongPress = qEnvironmentVariableIntValue("QT_ANDROID_ENABLE_RIGHT_MOUSE_FROM_LONG_PRESS"); 205 if (!rightMouseFromLongPress) 206 return; 207 m_ignoreMouseEvents = true; 208 QPoint globalPos(x,y); 209 QWindow *tlw = topLevelWindowAt(globalPos); 210 QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos; 211 212 // Click right button if no other button is already pressed. 213 if (!m_mouseGrabber) { 214 QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos, 215 Qt::MouseButtons(Qt::RightButton), Qt::RightButton, 216 QEvent::MouseButtonPress); 217 QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos, 218 Qt::MouseButtons(Qt::NoButton), Qt::RightButton, 219 QEvent::MouseButtonRelease); 220 } 221 } 222 touchBegin(JNIEnv *,jobject,jint)223 static void touchBegin(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/) 224 { 225 m_touchPoints.clear(); 226 } 227 touchAdd(JNIEnv *,jobject,jint,jint id,jint action,jboolean,jint x,jint y,jfloat major,jfloat minor,jfloat rotation,jfloat pressure)228 static void touchAdd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint id, jint action, jboolean /*primary*/, jint x, jint y, 229 jfloat major, jfloat minor, jfloat rotation, jfloat pressure) 230 { 231 Qt::TouchPointState state = Qt::TouchPointStationary; 232 switch (action) { 233 case 0: 234 state = Qt::TouchPointPressed; 235 break; 236 case 1: 237 state = Qt::TouchPointMoved; 238 break; 239 case 2: 240 state = Qt::TouchPointStationary; 241 break; 242 case 3: 243 state = Qt::TouchPointReleased; 244 break; 245 } 246 247 const int dw = desktopWidthPixels(); 248 const int dh = desktopHeightPixels(); 249 QWindowSystemInterface::TouchPoint touchPoint; 250 touchPoint.id = id; 251 touchPoint.pressure = pressure; 252 touchPoint.rotation = qRadiansToDegrees(rotation); 253 touchPoint.normalPosition = QPointF(double(x / dw), double(y / dh)); 254 touchPoint.state = state; 255 touchPoint.area = QRectF(x - double(minor), 256 y - double(major), 257 double(minor * 2), 258 double(major * 2)); 259 m_touchPoints.push_back(touchPoint); 260 261 if (state == Qt::TouchPointPressed) { 262 QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext(); 263 if (inputContext && qGuiApp) 264 QMetaObject::invokeMethod(inputContext, "touchDown", Q_ARG(int, x), Q_ARG(int, y)); 265 } 266 } 267 touchEnd(JNIEnv *,jobject,jint,jint)268 static void touchEnd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint /*action*/) 269 { 270 if (m_touchPoints.isEmpty()) 271 return; 272 273 QMutexLocker lock(QtAndroid::platformInterfaceMutex()); 274 QAndroidPlatformIntegration *platformIntegration = QtAndroid::androidPlatformIntegration(); 275 if (!platformIntegration) 276 return; 277 278 QTouchDevice *touchDevice = platformIntegration->touchDevice(); 279 if (touchDevice == 0) { 280 touchDevice = new QTouchDevice; 281 touchDevice->setType(QTouchDevice::TouchScreen); 282 touchDevice->setCapabilities(QTouchDevice::Position 283 | QTouchDevice::Area 284 | QTouchDevice::Pressure 285 | QTouchDevice::NormalizedPosition); 286 QWindowSystemInterface::registerTouchDevice(touchDevice); 287 platformIntegration->setTouchDevice(touchDevice); 288 } 289 290 QWindow *window = QtAndroid::topLevelWindowAt(m_touchPoints.at(0).area.center().toPoint()); 291 QWindowSystemInterface::handleTouchEvent(window, touchDevice, m_touchPoints); 292 } 293 isTabletEventSupported(JNIEnv *,jobject)294 static bool isTabletEventSupported(JNIEnv */*env*/, jobject /*thiz*/) 295 { 296 #if QT_CONFIG(tabletevent) 297 return true; 298 #else 299 return false; 300 #endif // QT_CONFIG(tabletevent) 301 } 302 tabletEvent(JNIEnv *,jobject,jint,jint deviceId,jlong time,jint action,jint pointerType,jint buttonState,jfloat x,jfloat y,jfloat pressure)303 static void tabletEvent(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint deviceId, jlong time, jint action, 304 jint pointerType, jint buttonState, jfloat x, jfloat y, jfloat pressure) 305 { 306 #if QT_CONFIG(tabletevent) 307 QPointF globalPosF(x, y); 308 QPoint globalPos((int)x, (int)y); 309 QWindow *tlw = topLevelWindowAt(globalPos); 310 QPointF localPos = tlw ? (globalPosF - tlw->position()) : globalPosF; 311 312 // Galaxy Note with plain Android: 313 // 0 1 0 stylus press 314 // 2 1 0 stylus drag 315 // 1 1 0 stylus release 316 // 0 1 2 stylus press with side-button held 317 // 2 1 2 stylus drag with side-button held 318 // 1 1 2 stylus release with side-button held 319 // Galaxy Note 4 with Samsung firmware: 320 // 0 1 0 stylus press 321 // 2 1 0 stylus drag 322 // 1 1 0 stylus release 323 // 211 1 2 stylus press with side-button held 324 // 213 1 2 stylus drag with side-button held 325 // 212 1 2 stylus release with side-button held 326 // when action == ACTION_UP (1) it's a release; otherwise we say which button is pressed 327 Qt::MouseButtons buttons = Qt::NoButton; 328 switch (action) { 329 case 1: // ACTION_UP 330 case 212: // stylus release while side-button held on Galaxy Note 4 331 buttons = Qt::NoButton; 332 break; 333 default: // action is press or drag 334 if (buttonState == 0) 335 buttons = Qt::LeftButton; 336 else // 2 means RightButton 337 buttons = Qt::MouseButtons(buttonState); 338 break; 339 } 340 341 #ifdef QT_DEBUG_ANDROID_STYLUS 342 qDebug() << action << pointerType << buttonState << '@' << x << y << "pressure" << pressure << ": buttons" << buttons; 343 #endif 344 345 QWindowSystemInterface::handleTabletEvent(tlw, ulong(time), 346 localPos, globalPosF, QTabletEvent::Stylus, pointerType, 347 buttons, pressure, 0, 0, 0., 0., 0, deviceId, Qt::NoModifier); 348 #endif // QT_CONFIG(tabletevent) 349 } 350 mapAndroidKey(int key)351 static int mapAndroidKey(int key) 352 { 353 // 0--9 0x00000007 -- 0x00000010 354 if (key >= 0x00000007 && key <= 0x00000010) 355 return Qt::Key_0 + key - 0x00000007; 356 357 // A--Z 0x0000001d -- 0x00000036 358 if (key >= 0x0000001d && key <= 0x00000036) 359 return Qt::Key_A + key - 0x0000001d; 360 361 // F1--F12 0x00000083 -- 0x0000008e 362 if (key >= 0x00000083 && key <= 0x0000008e) 363 return Qt::Key_F1 + key - 0x00000083; 364 365 // NUMPAD_0--NUMPAD_9 0x00000090 -- 0x00000099 366 if (key >= 0x00000090 && key <= 0x00000099) 367 return Qt::KeypadModifier + Qt::Key_0 + key - 0x00000090; 368 369 // BUTTON_1--KEYCODE_BUTTON_16 0x000000bc -- 0x000000cb 370 371 switch (key) { 372 case 0x00000000: // KEYCODE_UNKNOWN 373 return Qt::Key_unknown; 374 375 case 0x00000001: // KEYCODE_SOFT_LEFT 376 return Qt::Key_Left; 377 378 case 0x00000002: // KEYCODE_SOFT_RIGHT 379 return Qt::Key_Right; 380 381 // 0x00000003: // KEYCODE_HOME is never delivered to applications. 382 383 case 0x00000004: // KEYCODE_BACK 384 return Qt::Key_Back; 385 386 case 0x00000005: // KEYCODE_CALL 387 return Qt::Key_Call; 388 389 case 0x00000006: // KEYCODE_ENDCALL 390 return Qt::Key_Hangup; 391 392 // 0--9 0x00000007 -- 0x00000010 393 394 case 0x00000011: // KEYCODE_STAR 395 return Qt::Key_Asterisk; 396 397 case 0x00000012: // KEYCODE_POUND 398 return Qt::Key_NumberSign; 399 400 case 0x00000013: //KEYCODE_DPAD_UP 401 return Qt::Key_Up; 402 403 case 0x00000014: // KEYCODE_DPAD_DOWN 404 return Qt::Key_Down; 405 406 case 0x00000015: //KEYCODE_DPAD_LEFT 407 return Qt::Key_Left; 408 409 case 0x00000016: //KEYCODE_DPAD_RIGHT 410 return Qt::Key_Right; 411 412 case 0x00000017: // KEYCODE_DPAD_CENTER 413 return Qt::Key_Enter; 414 415 case 0x00000018: // KEYCODE_VOLUME_UP 416 return Qt::Key_VolumeUp; 417 418 case 0x00000019: // KEYCODE_VOLUME_DOWN 419 return Qt::Key_VolumeDown; 420 421 case 0x0000001a: 422 return Qt::Key_PowerOff; 423 424 case 0x0000001b: // KEYCODE_CAMERA 425 return Qt::Key_Camera; 426 427 case 0x0000001c: // KEYCODE_CLEAR 428 return Qt::Key_Clear; 429 430 // A--Z 0x0000001d -- 0x00000036 431 432 case 0x00000037: // KEYCODE_COMMA 433 return Qt::Key_Comma; 434 435 case 0x00000038: // KEYCODE_PERIOD 436 return Qt::Key_Period; 437 438 case 0x00000039: // KEYCODE_ALT_LEFT 439 case 0x0000003a: // KEYCODE_ALT_RIGHT 440 return Qt::Key_Alt; 441 442 case 0x0000003b: // KEYCODE_SHIFT_LEFT 443 case 0x0000003c: // KEYCODE_SHIFT_RIGHT 444 return Qt::Key_Shift; 445 446 case 0x0000003d: // KEYCODE_TAB 447 return Qt::Key_Tab; 448 449 case 0x0000003e: // KEYCODE_SPACE 450 return Qt::Key_Space; 451 452 case 0x0000003f: // KEYCODE_SYM 453 return Qt::Key_Meta; 454 455 case 0x00000040: // KEYCODE_EXPLORER 456 return Qt::Key_Explorer; 457 458 case 0x00000041: //KEYCODE_ENVELOPE 459 return Qt::Key_LaunchMail; 460 461 case 0x00000042: // KEYCODE_ENTER 462 return Qt::Key_Return; 463 464 case 0x00000043: // KEYCODE_DEL 465 return Qt::Key_Backspace; 466 467 case 0x00000044: // KEYCODE_GRAVE 468 return Qt::Key_QuoteLeft; 469 470 case 0x00000045: // KEYCODE_MINUS 471 return Qt::Key_Minus; 472 473 case 0x00000046: // KEYCODE_EQUALS 474 return Qt::Key_Equal; 475 476 case 0x00000047: // KEYCODE_LEFT_BRACKET 477 return Qt::Key_BracketLeft; 478 479 case 0x00000048: // KEYCODE_RIGHT_BRACKET 480 return Qt::Key_BracketRight; 481 482 case 0x00000049: // KEYCODE_BACKSLASH 483 return Qt::Key_Backslash; 484 485 case 0x0000004a: // KEYCODE_SEMICOLON 486 return Qt::Key_Semicolon; 487 488 case 0x0000004b: // KEYCODE_APOSTROPHE 489 return Qt::Key_Apostrophe; 490 491 case 0x0000004c: // KEYCODE_SLASH 492 return Qt::Key_Slash; 493 494 case 0x0000004d: // KEYCODE_AT 495 return Qt::Key_At; 496 497 case 0x0000004e: // KEYCODE_NUM 498 return Qt::Key_Alt; 499 500 case 0x0000004f: // KEYCODE_HEADSETHOOK 501 return 0; 502 503 case 0x00000050: // KEYCODE_FOCUS 504 return Qt::Key_CameraFocus; 505 506 case 0x00000051: // KEYCODE_PLUS 507 return Qt::Key_Plus; 508 509 case 0x00000052: // KEYCODE_MENU 510 return Qt::Key_Menu; 511 512 case 0x00000053: // KEYCODE_NOTIFICATION 513 return 0; 514 515 case 0x00000054: // KEYCODE_SEARCH 516 return Qt::Key_Search; 517 518 case 0x00000055: // KEYCODE_MEDIA_PLAY_PAUSE 519 return Qt::Key_MediaPlay; 520 521 case 0x00000056: // KEYCODE_MEDIA_STOP 522 return Qt::Key_MediaStop; 523 524 case 0x00000057: // KEYCODE_MEDIA_NEXT 525 return Qt::Key_MediaNext; 526 527 case 0x00000058: // KEYCODE_MEDIA_PREVIOUS 528 return Qt::Key_MediaPrevious; 529 530 case 0x00000059: // KEYCODE_MEDIA_REWIND 531 return Qt::Key_AudioRewind; 532 533 case 0x0000005a: // KEYCODE_MEDIA_FAST_FORWARD 534 return Qt::Key_AudioForward; 535 536 case 0x0000005b: // KEYCODE_MUTE 537 return Qt::Key_MicMute; 538 539 case 0x0000005c: // KEYCODE_PAGE_UP 540 return Qt::Key_PageUp; 541 542 case 0x0000005d: // KEYCODE_PAGE_DOWN 543 return Qt::Key_PageDown; 544 545 case 0x0000005e: // KEYCODE_PICTSYMBOLS 546 return 0; 547 548 case 0x00000060: // KEYCODE_BUTTON_A 549 case 0x00000061: // KEYCODE_BUTTON_B 550 case 0x00000062: // KEYCODE_BUTTON_B 551 case 0x00000063: // KEYCODE_BUTTON_X 552 case 0x00000064: // KEYCODE_BUTTON_Y 553 case 0x00000065: // KEYCODE_BUTTON_Z 554 case 0x00000066: // KEYCODE_BUTTON_L1 555 case 0x00000067: // KEYCODE_BUTTON_R1 556 case 0x00000068: // KEYCODE_BUTTON_L2 557 case 0x00000069: // KEYCODE_BUTTON_R2 558 case 0x0000006a: // KEYCODE_BUTTON_THUMBL 559 case 0x0000006b: // KEYCODE_BUTTON_THUMBR 560 case 0x0000006c: // KEYCODE_BUTTON_START 561 case 0x0000006d: // KEYCODE_BUTTON_SELECT 562 case 0x0000006e: // KEYCODE_BUTTON_MODE 563 return 0; 564 565 case 0x0000006f: // KEYCODE_ESCAPE 566 return Qt::Key_Escape; 567 568 case 0x00000070: // KEYCODE_FORWARD_DEL 569 return Qt::Key_Delete; 570 571 case 0x00000071: // KEYCODE_CTRL_LEFT 572 case 0x00000072: // KEYCODE_CTRL_RIGHT 573 return Qt::Key_Control; 574 575 case 0x00000073: // KEYCODE_CAPS_LOCK 576 return Qt::Key_CapsLock; 577 578 case 0x00000074: // KEYCODE_SCROLL_LOCK 579 return Qt::Key_ScrollLock; 580 581 case 0x00000075: // KEYCODE_META_LEFT 582 case 0x00000076: // KEYCODE_META_RIGHT 583 return Qt::Key_Meta; 584 585 case 0x00000077: // KEYCODE_FUNCTION 586 return 0; 587 588 case 0x00000078: // KEYCODE_SYSRQ 589 return Qt::Key_Print; 590 591 case 0x00000079: // KEYCODE_BREAK 592 return Qt::Key_Pause; 593 594 case 0x0000007a: // KEYCODE_MOVE_HOME 595 return Qt::Key_Home; 596 597 case 0x0000007b: // KEYCODE_MOVE_END 598 return Qt::Key_End; 599 600 case 0x0000007c: // KEYCODE_MOVE_INSERT 601 return Qt::Key_Insert; 602 603 case 0x0000007d: // KEYCODE_FORWARD 604 return Qt::Key_Forward; 605 606 case 0x0000007e: // KEYCODE_MEDIA_PLAY 607 return Qt::Key_MediaPlay; 608 609 case 0x0000007f: // KEYCODE_MEDIA_PAUSE 610 return Qt::Key_MediaPause; 611 612 case 0x00000080: // KEYCODE_MEDIA_CLOSE 613 case 0x00000081: // KEYCODE_MEDIA_EJECT 614 return Qt::Key_Eject; 615 616 case 0x00000082: // KEYCODE_MEDIA_RECORD 617 return Qt::Key_MediaRecord; 618 619 // F1--F12 0x00000083 -- 0x0000008e 620 621 case 0x0000008f: // KEYCODE_NUM_LOCK 622 return Qt::Key_NumLock; 623 624 // NUMPAD_0--NUMPAD_9 0x00000090 -- 0x00000099 625 626 case 0x0000009a: // KEYCODE_NUMPAD_DIVIDE 627 return Qt::KeypadModifier + Qt::Key_Slash; 628 629 case 0x0000009b: // KEYCODE_NUMPAD_MULTIPLY 630 return Qt::KeypadModifier + Qt::Key_Asterisk; 631 632 case 0x0000009c: // KEYCODE_NUMPAD_SUBTRACT 633 return Qt::KeypadModifier + Qt::Key_Minus; 634 635 case 0x0000009d: // KEYCODE_NUMPAD_ADD 636 return Qt::KeypadModifier + Qt::Key_Plus; 637 638 case 0x0000009e: // KEYCODE_NUMPAD_DOT 639 return Qt::KeypadModifier + Qt::Key_Period; 640 641 case 0x0000009f: // KEYCODE_NUMPAD_COMMA 642 return Qt::KeypadModifier + Qt::Key_Comma; 643 644 case 0x000000a0: // KEYCODE_NUMPAD_ENTER 645 return Qt::Key_Enter; 646 647 case 0x000000a1: // KEYCODE_NUMPAD_EQUALS 648 return Qt::KeypadModifier + Qt::Key_Equal; 649 650 case 0x000000a2: // KEYCODE_NUMPAD_LEFT_PAREN 651 return Qt::Key_ParenLeft; 652 653 case 0x000000a3: // KEYCODE_NUMPAD_RIGHT_PAREN 654 return Qt::Key_ParenRight; 655 656 case 0x000000a4: // KEYCODE_VOLUME_MUTE 657 return Qt::Key_VolumeMute; 658 659 case 0x000000a5: // KEYCODE_INFO 660 return Qt::Key_Info; 661 662 case 0x000000a6: // KEYCODE_CHANNEL_UP 663 return Qt::Key_ChannelUp; 664 665 case 0x000000a7: // KEYCODE_CHANNEL_DOWN 666 return Qt::Key_ChannelDown; 667 668 case 0x000000a8: // KEYCODE_ZOOM_IN 669 return Qt::Key_ZoomIn; 670 671 case 0x000000a9: // KEYCODE_ZOOM_OUT 672 return Qt::Key_ZoomOut; 673 674 case 0x000000aa: // KEYCODE_TV 675 case 0x000000ab: // KEYCODE_WINDOW 676 return 0; 677 678 case 0x000000ac: // KEYCODE_GUIDE 679 return Qt::Key_Guide; 680 681 case 0x000000ad: // KEYCODE_DVR 682 return 0; 683 684 case 0x000000ae: // KEYCODE_BOOKMARK 685 return Qt::Key_AddFavorite; 686 687 case 0x000000af: // KEYCODE_CAPTIONS 688 return Qt::Key_Subtitle; 689 690 case 0x000000b0: // KEYCODE_SETTINGS 691 return Qt::Key_Settings; 692 693 case 0x000000b1: // KEYCODE_TV_POWER 694 case 0x000000b2: // KEYCODE_TV_INPUT 695 case 0x000000b3: // KEYCODE_STB_POWER 696 case 0x000000b4: // KEYCODE_STB_INPUT 697 case 0x000000b5: // KEYCODE_AVR_POWER 698 case 0x000000b6: // KEYCODE_AVR_INPUT 699 return 0; 700 701 case 0x000000b7: // KEYCODE_PROG_RED 702 return Qt::Key_Red; 703 704 case 0x000000b8: // KEYCODE_PROG_GREEN 705 return Qt::Key_Green; 706 707 case 0x000000b9: // KEYCODE_PROG_YELLOW 708 return Qt::Key_Yellow; 709 710 case 0x000000ba: // KEYCODE_PROG_BLUE 711 return Qt::Key_Blue; 712 713 // 0x000000bb: // KEYCODE_APP_SWITCH is not sent by the Android O.S. 714 715 // BUTTON_1--KEYCODE_BUTTON_16 0x000000bc -- 0x000000cb 716 717 case 0x000000cc: // KEYCODE_LANGUAGE_SWITCH 718 case 0x000000cd: // KEYCODE_MANNER_MODE do we need such a thing? 719 case 0x000000ce: // KEYCODE_3D_MODE 720 case 0x000000cf: // KEYCODE_CONTACTS 721 return 0; 722 723 case 0x000000d0: // KEYCODE_CALENDAR 724 return Qt::Key_Calendar; 725 726 case 0x000000d1: // KEYCODE_MUSIC 727 return Qt::Key_Music; 728 729 case 0x000000d2: // KEYCODE_CALCULATOR 730 return Qt::Key_Calculator; 731 732 // 0x000000d3 -- 0x000000da some japanese specific keys, someone who understand what is about should check ! 733 734 // 0x000000db: // KEYCODE_ASSIST not delivered to applications. 735 736 case 0x000000dc: // KEYCODE_BRIGHTNESS_DOWN 737 return Qt::Key_KeyboardBrightnessDown; 738 739 case 0x000000dd: // KEYCODE_BRIGHTNESS_UP 740 return Qt::Key_KeyboardBrightnessUp; 741 742 case 0x000000de: // KEYCODE_MEDIA_AUDIO_TRACK 743 return Qt::Key_AudioCycleTrack; 744 745 default: 746 qWarning() << "Unhandled key code " << key << '!'; 747 return 0; 748 } 749 } 750 mapAndroidModifiers(jint modifiers)751 static Qt::KeyboardModifiers mapAndroidModifiers(jint modifiers) 752 { 753 Qt::KeyboardModifiers qmodifiers; 754 755 if (modifiers & 0x00000001) // META_SHIFT_ON 756 qmodifiers |= Qt::ShiftModifier; 757 758 if (modifiers & 0x00000002) // META_ALT_ON 759 qmodifiers |= Qt::AltModifier; 760 761 if (modifiers & 0x00000004) // META_SYM_ON 762 qmodifiers |= Qt::MetaModifier; 763 764 if (modifiers & 0x00001000) // META_CTRL_ON 765 qmodifiers |= Qt::ControlModifier; 766 767 return qmodifiers; 768 } 769 770 // maps 0 to the empty string, and anything else to a single-character string toString(jint unicode)771 static inline QString toString(jint unicode) 772 { 773 return unicode ? QString(QChar(unicode)) : QString(); 774 } 775 keyDown(JNIEnv *,jobject,jint key,jint unicode,jint modifier,jboolean autoRepeat)776 static void keyDown(JNIEnv */*env*/, jobject /*thiz*/, jint key, jint unicode, jint modifier, jboolean autoRepeat) 777 { 778 QWindowSystemInterface::handleKeyEvent(0, 779 QEvent::KeyPress, 780 mapAndroidKey(key), 781 mapAndroidModifiers(modifier), 782 toString(unicode), 783 autoRepeat); 784 } 785 keyUp(JNIEnv *,jobject,jint key,jint unicode,jint modifier,jboolean autoRepeat)786 static void keyUp(JNIEnv */*env*/, jobject /*thiz*/, jint key, jint unicode, jint modifier, jboolean autoRepeat) 787 { 788 QWindowSystemInterface::handleKeyEvent(0, 789 QEvent::KeyRelease, 790 mapAndroidKey(key), 791 mapAndroidModifiers(modifier), 792 toString(unicode), 793 autoRepeat); 794 } 795 keyboardVisibilityChanged(JNIEnv *,jobject,jboolean visibility)796 static void keyboardVisibilityChanged(JNIEnv */*env*/, jobject /*thiz*/, jboolean visibility) 797 { 798 m_softwareKeyboardVisible = visibility; 799 if (!visibility) 800 m_softwareKeyboardRect = QRect(); 801 802 QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext(); 803 if (inputContext && qGuiApp) { 804 inputContext->emitInputPanelVisibleChanged(); 805 if (!visibility) { 806 inputContext->emitKeyboardRectChanged(); 807 QMetaObject::invokeMethod(inputContext, "hideSelectionHandles", Qt::QueuedConnection); 808 } 809 } 810 #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL 811 qDebug() << "@@@ KEYBOARDVISIBILITYCHANGED" << inputContext; 812 #endif 813 } 814 keyboardGeometryChanged(JNIEnv *,jobject,jint x,jint y,jint w,jint h)815 static void keyboardGeometryChanged(JNIEnv */*env*/, jobject /*thiz*/, jint x, jint y, jint w, jint h) 816 { 817 QRect r = QRect(x, y, w, h); 818 if (r == m_softwareKeyboardRect) 819 return; 820 m_softwareKeyboardRect = r; 821 QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext(); 822 if (inputContext && qGuiApp) 823 inputContext->emitKeyboardRectChanged(); 824 825 #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL 826 qDebug() << "@@@ KEYBOARDRECTCHANGED" << m_softwareKeyboardRect; 827 #endif 828 } 829 handleLocationChanged(JNIEnv *,jobject,int id,int x,int y)830 static void handleLocationChanged(JNIEnv */*env*/, jobject /*thiz*/, int id, int x, int y) 831 { 832 #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL 833 qDebug() << "@@@ handleLocationChanged" << id << x << y; 834 #endif 835 QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext(); 836 if (inputContext && qGuiApp) 837 QMetaObject::invokeMethod(inputContext, "handleLocationChanged", Qt::BlockingQueuedConnection, 838 Q_ARG(int, id), Q_ARG(int, x), Q_ARG(int, y)); 839 840 } 841 842 static JNINativeMethod methods[] = { 843 {"touchBegin","(I)V",(void*)touchBegin}, 844 {"touchAdd","(IIIZIIFFFF)V",(void*)touchAdd}, 845 {"touchEnd","(II)V",(void*)touchEnd}, 846 {"mouseDown", "(III)V", (void *)mouseDown}, 847 {"mouseUp", "(III)V", (void *)mouseUp}, 848 {"mouseMove", "(III)V", (void *)mouseMove}, 849 {"mouseWheel", "(IIIFF)V", (void *)mouseWheel}, 850 {"longPress", "(III)V", (void *)longPress}, 851 {"isTabletEventSupported", "()Z", (void *)isTabletEventSupported}, 852 {"tabletEvent", "(IIJIIIFFF)V", (void *)tabletEvent}, 853 {"keyDown", "(IIIZ)V", (void *)keyDown}, 854 {"keyUp", "(IIIZ)V", (void *)keyUp}, 855 {"keyboardVisibilityChanged", "(Z)V", (void *)keyboardVisibilityChanged}, 856 {"keyboardGeometryChanged", "(IIII)V", (void *)keyboardGeometryChanged}, 857 {"handleLocationChanged", "(III)V", (void *)handleLocationChanged} 858 }; 859 registerNatives(JNIEnv * env)860 bool registerNatives(JNIEnv *env) 861 { 862 jclass appClass = QtAndroid::applicationClass(); 863 864 if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) { 865 __android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed"); 866 return false; 867 } 868 869 return true; 870 } 871 } 872 873 QT_END_NAMESPACE 874