Warning, /education/gcompris/src/core/VirtualKeyboard.qml is written in an unsupported language. File is not indexed.

0001 /* GCompris - VirtualKeyboard.qml
0002  *
0003  * SPDX-FileCopyrightText: 2014 Holger Kaelberer <holger.k@elberer.de>
0004  *
0005  * Authors:
0006  *   Holger Kaelberer <holger.k@elberer.de>
0007  *
0008  *   SPDX-License-Identifier: GPL-3.0-or-later
0009  */
0010 import QtQuick 2.12
0011 import GCompris 1.0
0012 
0013 /**
0014  * A QML component providing an on screen keyboard.
0015  * @ingroup components
0016  *
0017  * VirtualKeyboard displays a virtual on screen keyboard that can be used
0018  * in applications that need keyboard support, especially on mobile devices.
0019  *
0020  * The component itself does not provide builtin localized keyboard layouts,
0021  * the user has to define the keyboard-layout dynamically.
0022  *
0023  * @inherit QtQuick.Item
0024  */
0025 Item {
0026     id: keyboard
0027 
0028     /* Public interface: */
0029 
0030     /**
0031      * type:list
0032      *
0033      * Default basic qwerty-layout used unless the user provides another.
0034      * @sa layout.
0035      */
0036     readonly property var qwertyLayout:
0037                       [  [ { label: "1", shiftLabel: "!" },
0038                            { label: "2", shiftLabel: "@" },
0039                            { label: "3", shiftLabel: "#" },
0040                            { label: "4", shiftLabel: "$" },
0041                            { label: "5", shiftLabel: "%" },
0042                            { label: "6", shiftLabel: "^" },
0043                            { label: "7", shiftLabel: "&" },
0044                            { label: "8", shiftLabel: "*" },
0045                            { label: "9", shiftLabel: "(" },
0046                            { label: "0", shiftLabel: ")" },
0047                            { label: "-", shiftLabel: "_" },
0048                            { label: "=", shiftLabel: "+" } ],
0049 
0050                          [ { label: "q", shiftLabel: "Q" },
0051                            { label: "w", shiftLabel: "W" },
0052                            { label: "e", shiftLabel: "E" },
0053                            { label: "r", shiftLabel: "R" },
0054                            { label: "t", shiftLabel: "T" },
0055                            { label: "y", shiftLabel: "Y" },
0056                            { label: "u", shiftLabel: "U" },
0057                            { label: "i", shiftLabel: "I" },
0058                            { label: "o", shiftLabel: "O" },
0059                            { label: "p", shiftLabel: "P" } ],
0060 
0061                          [ { label: "a", shiftLabel: "A" },
0062                            { label: "s", shiftLabel: "S" },
0063                            { label: "d", shiftLabel: "D" },
0064                            { label: "f", shiftLabel: "F" },
0065                            { label: "g", shiftLabel: "G" },
0066                            { label: "h", shiftLabel: "H" },
0067                            { label: "j", shiftLabel: "J" },
0068                            { label: "k", shiftLabel: "K" },
0069                            { label: "l", shiftLabel: "L" } ],
0070 
0071                          [ { label: "z", shiftLabel: "Z" },
0072                            { label: "x", shiftLabel: "X" },
0073                            { label: "c", shiftLabel: "C" },
0074                            { label: "v", shiftLabel: "V" },
0075                            { label: "b", shiftLabel: "B" },
0076                            { label: "n", shiftLabel: "N" },
0077                            { label: "m", shiftLabel: "M" } ]]
0078 
0079 
0080     /**
0081      * type:string
0082      * Symbol that can be used for the space key.
0083     */
0084     readonly property string space: "\u2423"
0085 
0086     /**
0087      * type:string
0088      * Symbol that can be used for the backspace key.
0089      */
0090     readonly property string backspace: "\u2190"
0091 
0092     /**
0093      * type:string
0094      * Symbol for the shift-up key.
0095      */
0096     readonly property string shiftUpSymbol:   "\u21E7"
0097 
0098     /**
0099      * type:string
0100      * Symbol for the shift-down key.
0101      */
0102     readonly property string shiftDownSymbol: "\u21E9"
0103 
0104     /**
0105      * type:list
0106      * Keyboard layout.
0107      *
0108      * The layout should be provided by the user. It can contain
0109      * unicode characters, and can be set dynamically also on a per-level
0110      * basis.
0111      *
0112      * The expected format of the @ref layout property is a list of row lists.
0113      * Example:
0114      *
0115      * @code
0116      * [
0117      *    [                                    <-- start of the first row
0118      *      { label: "1", shiftLabel: "!" },   <-- first key of the first row
0119      *      { label: "2", shiftLabel: "@" },
0120      *      ...
0121      *    ],
0122      *    [
0123      *      { label: "q", shiftLabel: "Q" },
0124      *      { label: "w", shiftLabel: "W" },
0125      *      ...
0126      *    ],
0127      *    ...
0128      * ]
0129      * @endcode
0130      *
0131      * The order passed in layout will not be altered.
0132      *
0133      * Use the @ref shiftKey property to activate a shift button which allows
0134      * to assign 2 letters on one key. You can define an additional shiftLabel
0135      * per key, or leave it undefined, in which case VirtualKeyboard
0136      * automatically defines the shift-label (using
0137      * String.toLocaleUpperCase()).
0138      *
0139      * Default is to use the qwertyLayout.
0140      *
0141      * @sa qwertyLayout shiftKey
0142      */
0143     property var layout: null
0144 
0145     /**
0146      * type:bool
0147      * Whether a shift key should be used.
0148      */
0149     property bool shiftKey: false
0150 
0151     // property bool ctrlKey: false;
0152     // ...
0153 
0154     /**
0155      * type:int
0156      * Vertical spacing between rows in pixel.
0157      * Default: 5 * ApplicationInfo.ratio
0158      */
0159     property int rowSpacing: 5 * ApplicationInfo.ratio
0160 
0161     /**
0162      * type:int
0163      * Horizontal spacing between keys in pixel.
0164      * Default: 3 * ApplicationInfo.ratio
0165      */
0166     property int keySpacing: 3 * ApplicationInfo.ratio
0167 
0168     /**
0169      * type:int
0170      * Height of the keys in pixel.
0171      * Default: 45 * ApplicationInfo.ratio
0172      */
0173     property int keyHeight: 45 * ApplicationInfo.ratio
0174 
0175     /**
0176      * type:int
0177      * Margin around the keyboard in pixel.
0178      * Default: 5 * ApplicationInfo.ratio
0179      */
0180     property int margin: 5 * ApplicationInfo.ratio
0181 
0182     /**
0183      * type:bool
0184      * Whether the keyboard should be hidden.
0185      *
0186      * Besides this property the visibility of the virtual keyboard also
0187      * depends on the setting ApplicationSettings.isVirtualKeyboard and
0188      * its successful initialization.
0189      */
0190     property bool hide
0191 
0192     /**
0193      * Emitted for every keypress.
0194      *
0195      * @param text The label of the pressed key.
0196      */
0197     signal keypress(string text)
0198 
0199     /**
0200      * Emitted upon error.
0201      *
0202      * @param msg Error message.
0203      */
0204     signal error(string msg)
0205 
0206     /// @cond INTERNAL_DOCS
0207 
0208     opacity: 0.9
0209 
0210     visible: !hide && ApplicationSettings.isVirtualKeyboard && priv.initialized
0211     enabled: visible
0212 
0213     z: 9999
0214     width: parent.width
0215     height: visible ? priv.cHeight : 0
0216     anchors.horizontalCenter: parent.horizontalCenter
0217 
0218     property int modifiers: Qt.NoModifier;  // currently active key modifiers, internal only
0219 
0220     // private properties:
0221     QtObject {
0222         id: priv
0223 
0224         readonly property int cHeight: numRows * keyboard.keyHeight +
0225                                        (numRows + 1) * keyboard.rowSpacing
0226         property int numRows: 0
0227         property bool initialized: false
0228     }
0229 
0230     WorkerScript {
0231         id: keyboardWorker
0232 
0233         source: "virtualkeyboard_worker.js"
0234         onMessage: {
0235             // worker finished
0236             activity.loading.stop();
0237             if (messageObject.error !== "") {
0238                 error(messageObject.error);
0239             } else {
0240                 // update all changed values (except the model):
0241                 priv.numRows = messageObject.numRows;
0242                 priv.initialized = messageObject.initialized;
0243             }
0244         }
0245     }
0246 
0247     function populateKeyboard(a) {
0248         activity.loading.start();
0249         // populate asynchronously in a worker thread:
0250         keyboardWorker.sendMessage({
0251                                        shiftKey: keyboard.shiftKey,
0252                                        shiftUpSymbol: keyboard.shiftUpSymbol,
0253                                        shiftDownSymbol: keyboard.shiftDownSymbol,
0254                                        a: a,
0255                                        rowListModel: rowListModel
0256                                    });
0257     }
0258 
0259     function handleVirtualKeyPress(virtualKey) {
0260         if (virtualKey.specialKey === Qt.Key_Shift)
0261             keyboard.modifiers ^= Qt.ShiftModifier;
0262 //      else if (virtualKey.specialKey == Qt.Key_Alt)
0263 //          keyboard.modifiers ^= Qt.AltModifier;
0264         else
0265             keyboard.keypress(virtualKey.text);
0266     }
0267 
0268     onLayoutChanged: {
0269         priv.initialized = false;
0270         if (layout != null)
0271             populateKeyboard(layout);
0272     }
0273 
0274     ListModel {
0275         id: rowListModel
0276         /* Currently expects the following
0277          * ListElement {
0278          *   rowNum: 1
0279          *   keys: [ { label: "a", shiftLabel: "A" },
0280          *           { label: "b", shiftLabel: "B" },
0281          *           { label: "Shift", shiftLabel: "Shift", special },
0282          *             ...}
0283          *         ]
0284          * }
0285          */
0286     }
0287 
0288     Behavior on height {
0289         NumberAnimation {
0290             duration: 500
0291             easing.type: Easing.OutCubic
0292         }
0293     }
0294 
0295     Rectangle {
0296         id: keyboardBackground
0297 
0298         width: parent.width
0299         height: keyboard.height
0300         color: "#8C8F8C"
0301         opacity: keyboard.opacity
0302 
0303         ListView {
0304             id: rowList
0305 
0306             anchors.top: parent.top
0307             anchors.topMargin: keyboard.margin
0308             anchors.left: parent.left
0309             anchors.margins: keyboard.margin
0310             width: parent.width
0311             height: parent.height - keyboard.margin * 2
0312             spacing: keyboard.rowSpacing
0313             orientation: Qt.Vertical
0314             verticalLayoutDirection: ListView.TopToBottom
0315             interactive: false
0316 
0317             model: rowListModel
0318 
0319             delegate:
0320                 Item {
0321                     /* Wrap keyboardRow for attaching a MouseArea. Not possible
0322                      * in Row-s directly */
0323                     id: rowListDelegate
0324                     width: rowList.width
0325                     height: keyboardRow.height
0326                     x: keyboardRow.x
0327                     y: keyboardRow.y
0328                     z: keyboardRow.z
0329 
0330                     MouseArea {
0331                         anchors.fill: parent
0332                         propagateComposedEvents: true
0333 
0334                         // update index to allow for updating z value of the rows
0335                         onEntered: rowList.currentIndex = index;
0336 
0337                         onPressed: {
0338                             // same onPress for mobile
0339                             rowList.currentIndex = index;
0340                             // need to propagate through to the key for mobile!
0341                             mouse.accepted = false;
0342                         }
0343                     }
0344 
0345                     Row {
0346                         id: keyboardRow
0347                         spacing: keyboard.keySpacing
0348                         width: parent.width
0349 
0350                         z: rowListDelegate.ListView.isCurrentItem ? 1 : -1
0351 
0352                         Item {
0353                             id: keyboardRowSpacing
0354                             width: offset / 2;
0355                             height: keyboard.keyHeight
0356                         }
0357 
0358                         Repeater {
0359                             id: keyboardRowRepeater
0360 
0361                             z: rowListDelegate.ListView.isCurrentItem ? 1 : -1
0362 
0363                             model: keys
0364                             delegate: VirtualKey {
0365                                 width: (keyboard.width - keyboardRowRepeater.count *
0366                                         keyboardRow.spacing - offset - keyboard.margin*2) /
0367                                        keyboardRowRepeater.count
0368                                 height: keyboard.keyHeight
0369                                 modifiers: keyboard.modifiers
0370                                 specialKey: specialKeyValue
0371                             }
0372 
0373                             onItemAdded: item.pressed.connect(keyboard.handleVirtualKeyPress);
0374 
0375                             onItemRemoved: item.pressed.disconnect(keyboard.handleVirtualKeyPress);
0376                         } // Repeater
0377                     } // Row
0378             } // Item
0379         } // ListView
0380     } // keyboardBackground
0381 
0382     /// @endcond
0383 }