TraceInputArea.qml 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // Copyright (C) 2016 The Qt Company Ltd.
  2. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
  3. import QtQuick
  4. import QtQuick.Window
  5. import QtQuick.VirtualKeyboard
  6. /*!
  7. \qmltype TraceInputArea
  8. \inqmlmodule QtQuick.VirtualKeyboard.Components
  9. \ingroup qmlclass
  10. \ingroup qtvirtualkeyboard-components-qml
  11. \inherits MultiPointTouchArea
  12. \since QtQuick.VirtualKeyboard 2.0
  13. \brief A specialized MultiPointTouchArea for collecting touch input data.
  14. This type handles the trace interaction between the touch screen and the input engine.
  15. The traces are rendered using the delegate from the
  16. \l {KeyboardStyle::}{traceCanvasDelegate} property of the current
  17. \l KeyboardStyle.
  18. */
  19. MultiPointTouchArea {
  20. id: traceInputArea
  21. /*! Pattern recognition mode of this input area.
  22. The default value is \l {InputEngine::patternRecognitionModes} {InputEngine.PatternRecognitionMode.None}.
  23. */
  24. property int patternRecognitionMode: InputEngine.PatternRecognitionMode.None
  25. /*! List of horizontal rulers in the input area.
  26. The rulers are defined as a number of pixels from the top edge of the boundingBox.
  27. Here is an example that demonstrates how to define rulers:
  28. \code
  29. horizontalRulers: [boundingBox.height / 3, boundingBox.height / 3 * 2]
  30. verticalRulers: [boundingBox.width / 3, boundingBox.width / 3 * 2]
  31. \endcode
  32. */
  33. property var horizontalRulers
  34. /*! List of vertical rulers in the input area.
  35. The rulers are defined as a number of pixels from the left edge of the boundingBox.
  36. */
  37. property var verticalRulers
  38. /*! Bounding box for the trace input.
  39. This property is readonly and is automatically updated based on the item size
  40. and margins.
  41. */
  42. readonly property rect boundingBox: (width > 0 && height > 0) ?
  43. Qt.rect(traceInputArea.x + traceInputArea.anchors.leftMargin,
  44. traceInputArea.y + traceInputArea.anchors.topMargin,
  45. traceInputArea.width,
  46. traceInputArea.height) :
  47. Qt.rect(0, 0, 0, 0)
  48. /*! Canvas type of this trace input area.
  49. This property can be used to distinguish between different types of canvases.
  50. For example, in full screen handwriting mode this property is set to \c "fullscreen", and
  51. in keyboard handwriting mode this property is set to \c "keyboard".
  52. */
  53. property string canvasType
  54. property var __activeTraceCanvases: ({})
  55. property var __traceCanvasList: ([])
  56. property var __recycledTraceCanvasList: ([])
  57. Component.onCompleted: {
  58. for (var i = 0; i < 6; i++) {
  59. __recycledTraceCanvasList.push(__createTraceCanvas())
  60. }
  61. }
  62. function __getTraceCanvas() {
  63. while (__recycledTraceCanvasList.length == 0 &&
  64. __traceCanvasList.length >= 15 &&
  65. !__traceCanvasList.shift().recycle()) {}
  66. return __recycledTraceCanvasList.length > 0 ?
  67. __recycledTraceCanvasList.pop() :
  68. __createTraceCanvas()
  69. }
  70. function __createTraceCanvas() {
  71. var traceCanvas = keyboard.style.traceCanvasDelegate.createObject(traceInputArea)
  72. traceCanvas.onRecycle.connect(__onTraceCanvasRecycled)
  73. traceCanvas.anchors.fill = traceCanvas.parent
  74. return traceCanvas
  75. }
  76. function __onTraceCanvasRecycled(traceCanvas) {
  77. var index = __traceCanvasList.findIndex(function(otherCanvas) {
  78. return traceCanvas === otherCanvas
  79. })
  80. if (index !== -1) {
  81. __traceCanvasList.splice(index, index + 1)
  82. }
  83. __recycledTraceCanvasList.push(traceCanvas)
  84. }
  85. property var __traceCaptureDeviceInfo:
  86. ({
  87. channels: ['t'],
  88. sampleRate: 60,
  89. uniform: false,
  90. latency: 0.0,
  91. dpi: Screen.pixelDensity * 25.4
  92. })
  93. property var __traceScreenInfo:
  94. ({
  95. boundingBox: traceInputArea.boundingBox,
  96. horizontalRulers: traceInputArea.horizontalRulers,
  97. verticalRulers: traceInputArea.verticalRulers,
  98. canvasType: traceInputArea.canvasType
  99. })
  100. enabled: patternRecognitionMode !== InputEngine.PatternRecognitionMode.None && InputContext.inputEngine.patternRecognitionModes.indexOf(patternRecognitionMode) !== -1
  101. onPressed: (touchPoints) => {
  102. if (!keyboard.style.traceCanvasDelegate)
  103. return
  104. for (var i = 0; i < touchPoints.length; i++) {
  105. var traceId = touchPoints[i].pointId
  106. var trace = InputContext.inputEngine.traceBegin(traceId, patternRecognitionMode, __traceCaptureDeviceInfo, __traceScreenInfo)
  107. if (trace) {
  108. var traceCanvas = __getTraceCanvas()
  109. if (traceCanvas) {
  110. traceCanvas.trace = trace
  111. var index = trace.addPoint(Qt.point(touchPoints[i].x, touchPoints[i].y))
  112. if (trace.channels.indexOf('t') !== -1) {
  113. var dt = new Date()
  114. trace.setChannelData('t', index, dt.getTime())
  115. }
  116. __activeTraceCanvases[traceId] = traceCanvas
  117. } else {
  118. __activeTraceCanvases[traceId] = null
  119. }
  120. } else {
  121. __activeTraceCanvases[traceId] = null
  122. }
  123. }
  124. }
  125. onUpdated: (touchPoints) => {
  126. for (var i = 0; i < touchPoints.length; i++) {
  127. var traceId = touchPoints[i].pointId
  128. var traceCanvas = __activeTraceCanvases[traceId]
  129. if (traceCanvas) {
  130. var trace = traceCanvas.trace
  131. var index = trace.addPoint(Qt.point(touchPoints[i].x, touchPoints[i].y))
  132. if (trace.channels.indexOf('t') !== -1) {
  133. var dt = new Date()
  134. trace.setChannelData('t', index, dt.getTime())
  135. }
  136. }
  137. }
  138. }
  139. onReleased: (touchPoints) => {
  140. for (var i = 0; i < touchPoints.length; i++) {
  141. var traceId = touchPoints[i].pointId
  142. var traceCanvas = __activeTraceCanvases[traceId]
  143. if (traceCanvas) {
  144. if (traceCanvas.trace) {
  145. traceCanvas.trace.final = true
  146. InputContext.inputEngine.traceEnd(traceCanvas.trace)
  147. }
  148. __traceCanvasList.push(traceCanvas)
  149. __activeTraceCanvases[traceId] = null
  150. }
  151. }
  152. }
  153. onCanceled: (touchPoints) => {
  154. for (var i = 0; i < touchPoints.length; i++) {
  155. var traceId = touchPoints[i].pointId
  156. var traceCanvas = __activeTraceCanvases[traceId]
  157. if (traceCanvas) {
  158. if (traceCanvas.trace) {
  159. traceCanvas.trace.final = true
  160. traceCanvas.trace.canceled = true
  161. InputContext.inputEngine.traceEnd(traceCanvas.trace)
  162. }
  163. __traceCanvasList.push(traceCanvas)
  164. __activeTraceCanvases[traceId] = null
  165. }
  166. }
  167. }
  168. }