| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843 |
- // Copyright (C) 2016 The Qt Company Ltd.
- // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
- import QtQuick
- // Deliberately imported after QtQuick to avoid missing restoreMode property in Binding. Fix in Qt 6.
- import QtQml
- import QtQuick.Layouts
- import QtQuick.Window
- import QtQuick.VirtualKeyboard
- import QtQuick.VirtualKeyboard.Styles
- import QtQuick.VirtualKeyboard.Settings
- import QtQuick.VirtualKeyboard.Plugins
- import Qt.labs.folderlistmodel
- Item {
- id: keyboard
- objectName: "keyboard"
- property alias style: styleLoader.item
- property alias wordCandidateView: wordCandidateView
- property alias shadowInputControl: shadowInputControl
- property alias alternativeKeys: alternativeKeys
- property alias characterPreview: characterPreview
- property alias wordCandidateContextMenu: wordCandidateContextMenu
- property alias fullScreenModeSelectionControl: fullScreenModeSelectionControl
- property alias navigationHighlight: navigationHighlight
- property alias keyboardInputArea: keyboardInputArea
- property Item activeKey: null
- property TouchPoint activeTouchPoint
- property int localeIndex: -1
- property var availableLocaleIndices: []
- property var availableCustomLocaleIndices: []
- property string locale: localeIndex >= 0 && localeIndex < layoutsModel.count ? layoutsModel.get(localeIndex, "fileName") : ""
- property string inputLocale
- property int defaultLocaleIndex: -1
- readonly property bool latinOnly: InputContext.inputMethodHints & (Qt.ImhLatinOnly | Qt.ImhEmailCharactersOnly | Qt.ImhUrlCharactersOnly)
- readonly property bool preferNumbers: InputContext.inputMethodHints & Qt.ImhPreferNumbers
- readonly property bool dialableCharactersOnly: InputContext.inputMethodHints & Qt.ImhDialableCharactersOnly
- readonly property bool formattedNumbersOnly: InputContext.inputMethodHints & Qt.ImhFormattedNumbersOnly
- readonly property bool digitsOnly: InputContext.inputMethodHints & Qt.ImhDigitsOnly
- property string layout
- property string layoutType: {
- if (keyboard.handwritingMode) return "handwriting"
- if (keyboard.dialableCharactersOnly) return "dialpad"
- if (keyboard.formattedNumbersOnly) return "numbers"
- if (keyboard.digitsOnly) return "digits"
- if (keyboard.symbolMode) return "symbols"
- return "main"
- }
- property bool active: Qt.inputMethod.visible
- property bool handwritingMode
- property bool fullScreenHandwritingMode
- property bool symbolMode
- property bool fullScreenMode: VirtualKeyboardSettings.fullScreenMode
- property var defaultInputMethod: initDefaultInputMethod()
- property var plainInputMethod: PlainInputMethod {}
- property var customInputMethod: null
- property var customInputMethodSharedLayouts: []
- property int defaultInputMode: InputEngine.InputMode.Latin
- property bool inputMethodNeedsReset: true
- property bool inputModeNeedsReset: true
- property bool navigationModeActive: false
- readonly property bool languagePopupListActive: languagePopupList.enabled
- property alias soundEffect: soundEffect
- property alias keyboardLayoutLoader: keyboardLayoutLoader
- property real screenHeight: parent.parent ? parent.parent.height : Screen.height
- property bool noAnimations
- property int pressAndHoldDelay: 500
- function initDefaultInputMethod() {
- try {
- return Qt.createQmlObject('import QtQuick; import QtQuick.VirtualKeyboard.Plugins; DefaultInputMethod {}', keyboard, "defaultInputMethod")
- } catch (e) { }
- return plainInputMethod
- }
- Component.onCompleted: InputContext.priv.registerInputPanel(parent)
- width: keyboardBackground.width
- height: keyboardBackground.height
- onActiveChanged: {
- hideLanguagePopup()
- if (active && symbolMode && !preferNumbers)
- symbolMode = false
- keyboardInputArea.reset()
- wordCandidateViewAutoHideTimer.stop()
- }
- onActiveKeyChanged: {
- if (InputContext.inputEngine.activeKey !== Qt.Key_unknown)
- InputContext.inputEngine.virtualKeyCancel()
- }
- Connections {
- target: VirtualKeyboardSettings
- function onLocaleChanged() {
- updateDefaultLocale()
- localeIndex = defaultLocaleIndex
- }
- function onActiveLocalesChanged() {
- updateDefaultLocale()
- if (!isValidLocale(localeIndex) || VirtualKeyboardSettings.locale)
- localeIndex = defaultLocaleIndex
- }
- function onDefaultInputMethodDisabledChanged() {
- updateInputMethod()
- }
- }
- onAvailableLocaleIndicesChanged: hideLanguagePopup()
- onAvailableCustomLocaleIndicesChanged: hideLanguagePopup()
- onLocaleChanged: {
- hideLanguagePopup()
- inputMethodNeedsReset = true
- inputModeNeedsReset = true
- updateLayout()
- }
- onInputLocaleChanged: {
- if (Qt.locale(inputLocale).name !== "C")
- InputContext.priv.locale = inputLocale
- }
- onLayoutChanged: hideLanguagePopup()
- onLayoutTypeChanged: {
- updateAvailableLocaleIndices()
- updateLayout()
- }
- onLatinOnlyChanged: inputModeNeedsReset = true
- onPreferNumbersChanged: {
- keyboard.symbolMode = !keyboard.handwritingMode && preferNumbers
- inputModeNeedsReset = true
- }
- onDialableCharactersOnlyChanged: inputModeNeedsReset = true
- onFormattedNumbersOnlyChanged: inputModeNeedsReset = true
- onDigitsOnlyChanged: inputModeNeedsReset = true
- onHandwritingModeChanged: if (!keyboard.handwritingMode) keyboard.fullScreenHandwritingMode = false
- onFullScreenHandwritingModeChanged: if (keyboard.fullScreenHandwritingMode) keyboard.handwritingMode = true
- onLanguagePopupListActiveChanged: {
- if (languagePopupListActive && navigationModeActive)
- keyboardInputArea.initialKey = null
- }
- Connections {
- target: InputContext
- function onInputMethodHintsChanged() {
- if (InputContext.priv.focus)
- updateInputMethod()
- }
- }
- Connections {
- target: InputContext.priv
- function onInputItemChanged() {
- keyboard.hideLanguagePopup()
- if (active && symbolMode && !preferNumbers)
- symbolMode = false
- }
- function onFocusChanged() {
- if (InputContext.priv.focus)
- updateInputMethod()
- }
- function onNavigationKeyPressed(key, isAutoRepeat) {
- var initialKey
- var direction = wordCandidateView.effectiveLayoutDirection == Qt.LeftToRight ? 1 : -1
- switch (key) {
- case Qt.Key_Left:
- if (keyboard.navigationModeActive && !keyboardInputArea.initialKey) {
- if (languagePopupListActive) {
- hideLanguagePopup()
- keyboardInputArea.setActiveKey(null)
- keyboardInputArea.navigateToNextKey(0, 0, false)
- break
- }
- if (alternativeKeys.active) {
- if (alternativeKeys.listView.currentIndex > 0) {
- alternativeKeys.listView.decrementCurrentIndex()
- } else {
- alternativeKeys.close()
- keyboardInputArea.setActiveKey(null)
- keyboardInputArea.navigateToNextKey(0, 0, false)
- }
- break
- }
- if (functionPopupList.active) {
- if (functionPopupList.listView.currentIndex > 0) {
- functionPopupList.listView.decrementCurrentIndex()
- } else {
- functionPopupList.close()
- keyboardInputArea.setActiveKey(null)
- keyboardInputArea.navigateToNextKey(0, 0, false)
- }
- break
- }
- if (wordCandidateContextMenu.active) {
- hideWordCandidateContextMenu()
- break
- }
- if (wordCandidateView.count) {
- if (wordCandidateView.effectiveLayoutDirection == Qt.LeftToRight &&
- wordCandidateView.currentIndex > 0) {
- wordCandidateView.decrementCurrentIndex()
- } else if (wordCandidateView.effectiveLayoutDirection == Qt.RightToLeft &&
- wordCandidateView.currentIndex + 1 < wordCandidateView.count) {
- wordCandidateView.incrementCurrentIndex()
- } else {
- keyboardInputArea.navigateToNextKey(0, 0, false)
- initialKey = keyboardInputArea.initialKey
- while (keyboardInputArea.navigateToNextKey(0, 1 * direction, false))
- initialKey = keyboardInputArea.initialKey
- while (keyboardInputArea.navigateToNextKey(1, 0, false))
- initialKey = keyboardInputArea.initialKey
- keyboardInputArea.initialKey = initialKey
- keyboardInputArea.navigateToNextKey(0, 0, false)
- }
- break
- }
- }
- initialKey = keyboardInputArea.initialKey
- if (!keyboardInputArea.navigateToNextKey(-1 * direction, 0, false)) {
- keyboardInputArea.initialKey = initialKey
- if (!keyboardInputArea.navigateToNextKey(0, -1 * direction, false)) {
- if (wordCandidateView.count) {
- wordCandidateView.currentIndex =
- wordCandidateView.effectiveLayoutDirection == Qt.LeftToRight ?
- (wordCandidateView.count - 1) : 0
- break
- }
- keyboardInputArea.initialKey = initialKey
- keyboardInputArea.navigateToNextKey(0, -1 * direction, true)
- }
- keyboardInputArea.navigateToNextKey(-1 * direction, 0, true)
- }
- break
- case Qt.Key_Up:
- if (languagePopupListActive) {
- if (languagePopupList.currentIndex > 0) {
- languagePopupList.decrementCurrentIndex()
- } else if (languagePopupList.keyNavigationWraps) {
- languagePopupList.currentIndex = languagePopupList.count - 1
- } else {
- hideLanguagePopup()
- keyboardInputArea.setActiveKey(null)
- keyboardInputArea.navigateToNextKey(0, 0, false)
- }
- } else if (alternativeKeys.active) {
- alternativeKeys.close()
- keyboardInputArea.setActiveKey(null)
- keyboardInputArea.navigateToNextKey(0, 0, false)
- } else if (functionPopupList.active) {
- functionPopupList.close()
- keyboardInputArea.setActiveKey(null)
- keyboardInputArea.navigateToNextKey(0, 0, false)
- } else if (wordCandidateContextMenu.active) {
- if (wordCandidateContextMenuList.currentIndex > 0) {
- wordCandidateContextMenuList.decrementCurrentIndex()
- } else if (wordCandidateContextMenuList.keyNavigationWraps && wordCandidateContextMenuList.count > 1) {
- wordCandidateContextMenuList.currentIndex = wordCandidateContextMenuList.count - 1
- } else {
- hideWordCandidateContextMenu()
- }
- } else if (keyboard.navigationModeActive && !keyboardInputArea.initialKey && wordCandidateView.count) {
- keyboardInputArea.navigateToNextKey(0, 0, false)
- initialKey = keyboardInputArea.initialKey
- if (!keyboardInputArea.navigateToNextKey(0, -1, false)) {
- keyboardInputArea.initialKey = initialKey
- keyboardInputArea.navigateToNextKey(0, -1, true)
- } else {
- keyboardInputArea.navigateToNextKey(0, 1, false)
- }
- } else if (!keyboardInputArea.navigateToNextKey(0, -1, !keyboard.navigationModeActive || !keyboardInputArea.initialKey || wordCandidateView.count == 0)) {
- if (wordCandidateView.currentIndex === -1)
- wordCandidateView.incrementCurrentIndex()
- }
- break
- case Qt.Key_Right:
- if (keyboard.navigationModeActive && !keyboardInputArea.initialKey) {
- if (languagePopupListActive) {
- hideLanguagePopup()
- keyboardInputArea.setActiveKey(null)
- keyboardInputArea.navigateToNextKey(0, 0, false)
- break
- }
- if (alternativeKeys.active) {
- if (alternativeKeys.listView.currentIndex + 1 < alternativeKeys.listView.count) {
- alternativeKeys.listView.incrementCurrentIndex()
- } else {
- alternativeKeys.close()
- keyboardInputArea.setActiveKey(null)
- keyboardInputArea.navigateToNextKey(0, 0, false)
- }
- break
- }
- if (functionPopupList.active) {
- if (functionPopupList.listView.currentIndex + 1 < functionPopupList.listView.count) {
- functionPopupList.listView.incrementCurrentIndex()
- } else {
- functionPopupList.close()
- keyboardInputArea.setActiveKey(null)
- keyboardInputArea.navigateToNextKey(0, 0, false)
- }
- break
- }
- if (wordCandidateContextMenu.active) {
- hideWordCandidateContextMenu()
- break
- }
- if (wordCandidateView.count) {
- if (wordCandidateView.effectiveLayoutDirection == Qt.LeftToRight &&
- wordCandidateView.currentIndex + 1 < wordCandidateView.count) {
- wordCandidateView.incrementCurrentIndex()
- } else if (wordCandidateView.effectiveLayoutDirection == Qt.RightToLeft &&
- wordCandidateView.currentIndex > 0) {
- wordCandidateView.decrementCurrentIndex()
- } else {
- keyboardInputArea.navigateToNextKey(0, 0, false)
- initialKey = keyboardInputArea.initialKey
- while (keyboardInputArea.navigateToNextKey(0, -1 * direction, false))
- initialKey = keyboardInputArea.initialKey;
- while (keyboardInputArea.navigateToNextKey(-1, 0, false))
- initialKey = keyboardInputArea.initialKey;
- keyboardInputArea.initialKey = initialKey
- keyboardInputArea.navigateToNextKey(0, 0, false)
- }
- break
- }
- }
- initialKey = keyboardInputArea.initialKey
- if (!keyboardInputArea.navigateToNextKey(1 * direction, 0, false)) {
- keyboardInputArea.initialKey = initialKey
- if (!keyboardInputArea.navigateToNextKey(0, 1 * direction, false)) {
- if (wordCandidateView.count) {
- wordCandidateView.currentIndex =
- wordCandidateView.effectiveLayoutDirection == Qt.LeftToRight ?
- 0 : (wordCandidateView.count - 1)
- break
- }
- keyboardInputArea.initialKey = initialKey
- keyboardInputArea.navigateToNextKey(0, 1 * direction, true)
- }
- keyboardInputArea.navigateToNextKey(1 * direction, 0, true)
- }
- break
- case Qt.Key_Down:
- if (languagePopupListActive) {
- if (languagePopupList.currentIndex + 1 < languagePopupList.count) {
- languagePopupList.incrementCurrentIndex()
- } else if (languagePopupList.keyNavigationWraps) {
- languagePopupList.currentIndex = 0
- } else {
- hideLanguagePopup()
- keyboardInputArea.setActiveKey(null)
- keyboardInputArea.navigateToNextKey(0, 0, false)
- }
- } else if (alternativeKeys.active) {
- alternativeKeys.close()
- keyboardInputArea.setActiveKey(null)
- keyboardInputArea.navigateToNextKey(0, 0, false)
- } else if (functionPopupList.active) {
- functionPopupList.close()
- keyboardInputArea.setActiveKey(null)
- keyboardInputArea.navigateToNextKey(0, 0, false)
- } else if (wordCandidateContextMenu.active) {
- if (wordCandidateContextMenuList.currentIndex + 1 < wordCandidateContextMenuList.count) {
- wordCandidateContextMenuList.incrementCurrentIndex()
- } else if (wordCandidateContextMenuList.keyNavigationWraps && wordCandidateContextMenuList.count > 1) {
- wordCandidateContextMenuList.currentIndex = 0
- } else {
- hideWordCandidateContextMenu()
- keyboardInputArea.setActiveKey(null)
- keyboardInputArea.navigateToNextKey(0, 0, false)
- }
- } else if (keyboard.navigationModeActive && !keyboardInputArea.initialKey && wordCandidateView.count) {
- keyboardInputArea.navigateToNextKey(0, 0, false)
- initialKey = keyboardInputArea.initialKey
- if (!keyboardInputArea.navigateToNextKey(0, 1, false)) {
- keyboardInputArea.initialKey = initialKey
- keyboardInputArea.navigateToNextKey(0, 1, true)
- } else {
- keyboardInputArea.navigateToNextKey(0, -1, false)
- }
- } else if (!keyboardInputArea.navigateToNextKey(0, 1, !keyboard.navigationModeActive || !keyboardInputArea.initialKey || wordCandidateView.count == 0)) {
- if (wordCandidateView.currentIndex === -1)
- wordCandidateView.incrementCurrentIndex()
- }
- break
- case Qt.Key_Return:
- if (!keyboard.navigationModeActive)
- break
- if (languagePopupListActive) {
- if (!isAutoRepeat) {
- languagePopupList.model.selectItem(languagePopupList.currentIndex)
- keyboardInputArea.reset()
- keyboardInputArea.navigateToNextKey(0, 0, false)
- }
- } else if (keyboardInputArea.initialKey) {
- if (!isAutoRepeat) {
- pressAndHoldTimer.restart()
- keyboardInputArea.setActiveKey(keyboardInputArea.initialKey)
- keyboardInputArea.press(keyboardInputArea.initialKey, true)
- }
- } else if (!wordCandidateContextMenu.active && wordCandidateView.count > 0) {
- if (!isAutoRepeat) {
- pressAndHoldTimer.restart()
- }
- }
- break
- default:
- break
- }
- }
- function onNavigationKeyReleased(key, isAutoRepeat) {
- switch (key) {
- case Qt.Key_Return:
- if (!keyboard.navigationModeActive) {
- if (languagePopupListActive)
- languagePopupList.model.selectItem(languagePopupList.currentIndex)
- break
- }
- if (isAutoRepeat)
- break
- if (!languagePopupListActive && !alternativeKeys.active && !functionPopupList.active && !wordCandidateContextMenu.active && keyboard.activeKey) {
- keyboardInputArea.release(keyboard.activeKey)
- pressAndHoldTimer.stop()
- alternativeKeys.close()
- functionPopupList.close()
- keyboardInputArea.setActiveKey(null)
- if (!languagePopupListActive && keyboardInputArea.navigationCursor !== Qt.point(-1, -1))
- keyboardInputArea.navigateToNextKey(0, 0, false)
- } else if (wordCandidateContextMenu.active) {
- if (!wordCandidateContextMenu.openedByNavigationKeyLongPress) {
- wordCandidateContextMenu.selectCurrentItem()
- keyboardInputArea.navigateToNextKey(0, 0, false)
- } else {
- wordCandidateContextMenu.openedByNavigationKeyLongPress = false
- }
- } else if (alternativeKeys.active) {
- if (!alternativeKeys.openedByNavigationKeyLongPress) {
- alternativeKeys.clicked()
- alternativeKeys.close()
- keyboardInputArea.navigateToNextKey(0, 0, false)
- keyboardInputArea.reset()
- } else {
- alternativeKeys.openedByNavigationKeyLongPress = false
- }
- } else if (functionPopupList.active) {
- if (!functionPopupList.openedByNavigationKeyLongPress) {
- functionPopupList.clicked()
- functionPopupList.close()
- keyboardInputArea.navigateToNextKey(0, 0, false)
- keyboardInputArea.reset()
- } else {
- functionPopupList.openedByNavigationKeyLongPress = false
- }
- } else if (!wordCandidateContextMenu.active && wordCandidateView.count > 0) {
- wordCandidateView.model.selectItem(wordCandidateView.currentIndex)
- if (!InputContext.preeditText.length)
- keyboardInputArea.navigateToNextKey(0, 1, true)
- }
- break
- default:
- break
- }
- }
- }
- Connections {
- target: InputContext.inputEngine
- function onVirtualKeyClicked(key, text, modifiers, isAutoRepeat) {
- if (isAutoRepeat && keyboard.activeKey)
- soundEffect.play(keyboard.activeKey.soundEffect)
- if (key !== Qt.Key_unknown && keyboardInputArea.dragSymbolMode) {
- keyboardInputArea.dragSymbolMode = false
- keyboard.symbolMode = false
- } else if (key === Qt.Key_Space) {
- var surroundingText = InputContext.surroundingText.trim()
- if (InputContext.priv.shiftHandler.sentenceEndingCharacters.indexOf(surroundingText.charAt(surroundingText.length-1)) >= 0)
- keyboard.symbolMode = false
- }
- }
- }
- FolderListModel {
- id: layoutsModel
- nameFilters: ["$"]
- folder: VirtualKeyboardSettings.layoutPath
- }
- Connections {
- target: layoutsModel
- function onCountChanged() {
- updateDefaultLocale()
- localeIndex = defaultLocaleIndex
- }
- }
- AlternativeKeys {
- id: alternativeKeys
- objectName: "alternativeKeys"
- // Add some extra margin for decoration
- property real horizontalMargin: style.alternateKeysListItemWidth
- property real verticalMargin: style.alternateKeysListItemHeight
- property rect previewRect: Qt.rect(keyboard.x + alternativeKeys.listView.x - horizontalMargin,
- keyboard.y + alternativeKeys.listView.y - verticalMargin,
- alternativeKeys.listView.width + horizontalMargin * 2,
- alternativeKeys.listView.height + verticalMargin * 2)
- property bool openedByNavigationKeyLongPress
- onVisibleChanged: {
- if (visible)
- InputContext.priv.previewRectangle = Qt.binding(function() {return previewRect})
- else
- openedByNavigationKeyLongPress = false
- InputContext.priv.previewVisible = visible
- }
- }
- FunctionPopupList {
- id: functionPopupList
- property bool openedByNavigationKeyLongPress
- }
- Timer {
- id: pressAndHoldTimer
- interval: keyboard.pressAndHoldDelay
- onTriggered: {
- if (keyboard.activeKey && keyboard.activeKey === keyboardInputArea.initialKey) {
- var origin = keyboard.mapFromItem(activeKey, activeKey.width / 2, 0)
- if (keyboard.activeKey.smallText === "\u2699" &&
- functionPopupList.open(keyboard.activeKey, origin.x, origin.y)) {
- InputContext.inputEngine.virtualKeyCancel()
- keyboardInputArea.initialKey = null
- functionPopupList.openedByNavigationKeyLongPress = keyboard.navigationModeActive
- } else if (alternativeKeys.open(keyboard.activeKey, origin.x, origin.y)) {
- InputContext.inputEngine.virtualKeyCancel()
- keyboardInputArea.initialKey = null
- alternativeKeys.openedByNavigationKeyLongPress = keyboard.navigationModeActive
- } else if (keyboard.activeKey.key === Qt.Key_Context1 && !keyboard.symbolMode) {
- InputContext.inputEngine.virtualKeyCancel()
- keyboardInputArea.dragSymbolMode = true
- keyboard.symbolMode = true
- keyboardInputArea.initialKey = null
- if (keyboardInputArea.navigationCursor !== Qt.point(-1, -1))
- keyboardInputArea.navigateToNextKey(0, 0, false)
- }
- } else if (keyboardInputArea.dragSymbolMode &&
- keyboard.activeKey &&
- keyboard.activeKey.functionKey &&
- !keyboard.activeKey.repeat) {
- InputContext.inputEngine.virtualKeyCancel()
- keyboardInputArea.click(keyboard.activeKey)
- keyboardInputArea.initialKey = null
- if (keyboardInputArea.navigationCursor !== Qt.point(-1, -1))
- keyboardInputArea.navigateToNextKey(0, 0, false)
- } else if (!wordCandidateContextMenu.active && keyboard.navigationModeActive) {
- wordCandidateContextMenu.show(wordCandidateView.currentIndex)
- wordCandidateContextMenu.openedByNavigationKeyLongPress = keyboard.navigationModeActive
- }
- }
- }
- Timer {
- id: releaseInaccuracyTimer
- interval: 500
- onTriggered: {
- if (keyboardInputArea.pressed && activeTouchPoint && !alternativeKeys.active && !keyboardInputArea.dragSymbolMode && !functionPopupList.active) {
- var key = keyboardInputArea.keyOnPoint(activeTouchPoint.x, activeTouchPoint.y)
- if (key !== keyboard.activeKey) {
- InputContext.inputEngine.virtualKeyCancel()
- keyboardInputArea.setActiveKey(key)
- keyboardInputArea.press(key, false)
- }
- }
- }
- }
- CharacterPreviewBubble {
- id: characterPreview
- objectName: "characterPreviewBubble"
- active: keyboardInputArea.pressed && !alternativeKeys.active && !functionPopupList.active
- property rect previewRect: Qt.rect(keyboard.x + characterPreview.x,
- keyboard.y + characterPreview.y,
- characterPreview.width,
- characterPreview.height)
- }
- Binding {
- target: InputContext.priv
- property: "previewRectangle"
- value: characterPreview.previewRect
- when: characterPreview.visible
- restoreMode: Binding.RestoreBinding
- }
- Binding {
- target: InputContext.priv
- property: "previewRectangle"
- value: languagePopupList.previewRect
- when: languagePopupListActive
- restoreMode: Binding.RestoreBinding
- }
- Binding {
- target: InputContext.priv
- property: "previewVisible"
- value: characterPreview.visible || languagePopupListActive
- restoreMode: Binding.RestoreBinding
- }
- Loader {
- id: styleLoader
- source: VirtualKeyboardSettings.style
- Binding {
- target: styleLoader.item
- property: "keyboardHeight"
- value: keyboardInnerContainer.height
- restoreMode: Binding.RestoreBinding
- }
- }
- Loader {
- id: navigationHighlight
- objectName: "navigationHighlight"
- property var highlightItem: {
- if (keyboard.navigationModeActive) {
- if (languagePopupListActive) {
- return languagePopupList.highlightItem
- } else if (keyboardInputArea.initialKey) {
- return keyboardInputArea.initialKey
- } else if (alternativeKeys.listView.count > 0) {
- return alternativeKeys.listView.highlightItem
- } else if (functionPopupList.listView.count > 0) {
- return functionPopupList.listView.highlightItem
- } else if (wordCandidateContextMenu.active) {
- return wordCandidateContextMenuList.highlightItem
- } else if (wordCandidateView.count > 0) {
- return wordCandidateView.highlightItem
- }
- }
- return keyboard
- }
- // Note: without "highlightItem.x - highlightItem.x" the binding does not work for alternativeKeys
- property var highlightItemOffset: highlightItem ? keyboard.mapFromItem(highlightItem, highlightItem.x - highlightItem.x, highlightItem.y - highlightItem.y) : ({x:0, y:0})
- property int moveDuration: !keyboard.noAnimations ? 200 : 0
- property int resizeDuration: !keyboard.noAnimations ? 200 : 0
- z: 2
- x: highlightItemOffset.x
- y: highlightItemOffset.y
- width: highlightItem ? highlightItem.width : 0
- height: highlightItem ? highlightItem.height : 0
- visible: keyboard.navigationModeActive && highlightItem !== null && highlightItem !== keyboard
- sourceComponent: keyboard.style.navigationHighlight
- Behavior on x {
- NumberAnimation { id: xAnimation; duration: navigationHighlight.moveDuration; easing.type: Easing.OutCubic }
- }
- Behavior on y {
- NumberAnimation { id: yAnimation; duration: navigationHighlight.moveDuration; easing.type: Easing.OutCubic }
- }
- Behavior on width {
- NumberAnimation { id: widthAnimation; duration: navigationHighlight.resizeDuration; easing.type: Easing.OutCubic }
- }
- Behavior on height {
- NumberAnimation { id: heightAnimation; duration: navigationHighlight.resizeDuration; easing.type: Easing.OutCubic }
- }
- }
- ShadowInputControl {
- id: shadowInputControl
- objectName: "shadowInputControl"
- z: -3
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.bottom: wordCandidateView.top
- height: keyboard.screenHeight -
- keyboard.height +
- wordCandidateView.y
- visible: fullScreenMode && (shadowInputControlVisibleTimer.running || InputContext.animating)
- Connections {
- target: keyboard
- function onActiveChanged() {
- if (keyboard.active)
- shadowInputControlVisibleTimer.start()
- else
- shadowInputControlVisibleTimer.stop()
- }
- }
- Timer {
- id: shadowInputControlVisibleTimer
- interval: 2147483647
- repeat: true
- }
- MouseArea {
- onPressed: keyboard.hideLanguagePopup()
- anchors.fill: parent
- enabled: languagePopupList.enabled
- }
- }
- SelectionControl {
- id: fullScreenModeSelectionControl
- objectName: "fullScreenModeSelectionControl"
- inputContext: InputContext.priv.shadow
- anchors.top: shadowInputControl.top
- anchors.left: shadowInputControl.left
- enabled: keyboard.enabled && fullScreenMode
- }
- ListView {
- id: wordCandidateView
- objectName: "wordCandidateView"
- clip: true
- z: -2
- property bool empty: true
- readonly property bool visibleCondition: keyboard.active && InputContext.inputEngine.wordCandidateListVisibleHint &&
- (!wordCandidateView.empty || wordCandidateViewAutoHideTimer.running)
- readonly property bool alwaysVisibleCondition: InputContext.inputEngine.wordCandidateListVisibleHint &&
- (keyboard.fullScreenMode || VirtualKeyboardSettings.wordCandidateList.alwaysVisible)
- readonly property real visibleYOffset: -height
- height: style ? style.selectionListHeight : 0
- anchors.left: parent.left
- anchors.right: parent.right
- spacing: 0
- orientation: ListView.Horizontal
- snapMode: ListView.SnapToItem
- delegate: style.selectionListDelegate
- highlight: style.selectionListHighlight ? style.selectionListHighlight : defaultHighlight
- highlightMoveDuration: 0
- highlightResizeDuration: 0
- add: !keyboard.noAnimations ? style.selectionListAdd : null
- remove: !keyboard.noAnimations ? style.selectionListRemove : null
- keyNavigationWraps: true
- model: InputContext.inputEngine.wordCandidateListModel
- onCurrentItemChanged: if (currentItem) soundEffect.register(currentItem.soundEffect)
- Connections {
- target: wordCandidateView.model ? wordCandidateView.model : null
- function onActiveItemChanged(index) { wordCandidateView.currentIndex = index }
- function onItemSelected() { if (wordCandidateView.currentItem) soundEffect.play(wordCandidateView.currentItem.soundEffect) }
- function onCountChanged() {
- var empty = wordCandidateView.model.count === 0
- if (empty)
- wordCandidateViewAutoHideTimer.restart()
- else
- wordCandidateViewAutoHideTimer.stop()
- wordCandidateView.empty = empty
- keyboard.hideWordCandidateContextMenu()
- }
- }
- Connections {
- target: InputContext.priv
- function onInputItemChanged() { wordCandidateViewAutoHideTimer.stop() }
- }
- Connections {
- target: InputContext.inputEngine
- function onWordCandidateListVisibleHintChanged() { wordCandidateViewAutoHideTimer.stop() }
- }
- Timer {
- id: wordCandidateViewAutoHideTimer
- interval: VirtualKeyboardSettings.wordCandidateList.autoHideDelay
- }
- Loader {
- sourceComponent: style.selectionListBackground
- anchors.fill: parent
- z: -1
- }
- Component {
- id: defaultHighlight
- Item {}
- }
- states: [
- State {
- name: "visible"
- when: wordCandidateView.visibleCondition
- PropertyChanges {
- target: wordCandidateView
- y: wordCandidateView.visibleYOffset
- }
- },
- State {
- name: "alwaysVisible"
- when: wordCandidateView.alwaysVisibleCondition
- PropertyChanges {
- target: wordCandidateView
- y: wordCandidateView.visibleYOffset
- }
- }
- ]
- transitions: Transition {
- id: wordCandidateViewTransition
- from: ""
- to: "visible"
- enabled: !InputContext.animating && !keyboard.noAnimations
- reversible: true
- ParallelAnimation {
- NumberAnimation {
- properties: "y"
- duration: 250
- easing.type: Easing.InOutQuad
- }
- }
- }
- function longPressItem(index) {
- return keyboard.showWordCandidateContextMenu(index)
- }
- }
- Item {
- id: soundEffect
- property var __sounds: ({})
- property bool available: false
- signal playingChanged(url source, bool playing)
- Connections {
- target: VirtualKeyboardSettings
- function onStyleNameChanged() {
- soundEffect.__sounds = {}
- soundEffect.available = false
- }
- }
- function play(sound) {
- if (enabled && sound != Qt.resolvedUrl("")) {
- var soundId = Qt.md5(sound)
- var multiSoundEffect = __sounds[soundId]
- if (!multiSoundEffect)
- multiSoundEffect = register(sound)
- if (multiSoundEffect) {
- multiSoundEffect.soundVolume = VirtualKeyboardSettings.convertVolume(VirtualKeyboardSettings.keySoundVolume)
- multiSoundEffect.play()
- }
- }
- }
- function register(sound) {
- var multiSoundEffect = null
- if (enabled && sound != Qt.resolvedUrl("")) {
- var soundId = Qt.md5(sound)
- multiSoundEffect = __sounds[soundId]
- if (!multiSoundEffect) {
- multiSoundEffect = Qt.createQmlObject('import QtQuick; import QtQuick.VirtualKeyboard; MultiSoundEffect {}', soundEffect)
- if (multiSoundEffect) {
- multiSoundEffect.playingChanged.connect(soundEffect.playingChanged)
- multiSoundEffect.source = sound
- __sounds[soundId] = multiSoundEffect
- available = true
- }
- }
- }
- return multiSoundEffect
- }
- }
- Loader {
- id: keyboardBackground
- z: -1
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.bottom: parent.bottom
- height: keyboardInnerContainer.height
- sourceComponent: style.keyboardBackground
- Item {
- id: keyboardInnerContainer
- z: 1
- width: Math.round(keyboardBackground.width)
- height: style ? Math.round(style.keyboardDesignHeight * width / style.keyboardDesignWidth) : 0
- anchors.horizontalCenter: parent.horizontalCenter
- LayoutMirroring.enabled: false
- LayoutMirroring.childrenInherit: true
- KeyboardObserver {
- id: keyboardObserver
- function scanLayout() {
- if (keyboardLayoutLoader.item == null)
- return null
- return keyboardLayoutLoader.item.scanLayout()
- }
- }
- Component.onCompleted: InputContext.priv.setKeyboardObserver(keyboardObserver)
- onWidthChanged: notifyLayoutChanged()
- onHeightChanged: notifyLayoutChanged()
- Loader {
- id: keyboardLayoutLoader
- objectName: "keyboardLayoutLoader"
- anchors.fill: parent
- anchors.leftMargin: Math.round(style.keyboardRelativeLeftMargin * parent.width)
- anchors.rightMargin: Math.round(style.keyboardRelativeRightMargin * parent.width)
- anchors.topMargin: Math.round(style.keyboardRelativeTopMargin * parent.height)
- anchors.bottomMargin: Math.round(style.keyboardRelativeBottomMargin * parent.height)
- Binding {
- target: keyboardLayoutLoader
- property: "source"
- value: keyboard.layout
- when: keyboard.width > 0 && keyboard.layout.length > 0
- restoreMode: Binding.RestoreNone
- }
- onItemChanged: {
- if (!item)
- return
- // Reset input mode if the new layout wants to override it
- if (item.inputMode !== -1)
- inputModeNeedsReset = true
- if (!InputContext.inputEngine.inputMethod)
- updateInputMethod()
- notifyLayoutChanged()
- }
- MultiPointTouchArea {
- id: keyboardInputArea
- objectName: "keyboardInputArea"
- property Item initialKey: null
- property bool dragSymbolMode
- property real releaseMargin: initialKey !== null ? Math.min(initialKey.width / 3, initialKey.height / 3) : 0
- property point navigationCursor: Qt.point(-1, -1)
- anchors.fill: keyboardLayoutLoader
- Connections {
- target: keyboardLayoutLoader
- function onLoaded() {
- if (keyboard.navigationModeActive &&
- keyboardInputArea.navigationCursor !== Qt.point(-1, -1))
- keyboard.navigationModeActive = keyboardInputArea.navigateToNextKey(0, 0, false)
- }
- }
- Connections {
- target: keyboard
- function onNavigationModeActiveChanged() {
- if (!keyboard.navigationModeActive) {
- keyboardInputArea.navigationCursor = Qt.point(-1, -1)
- keyboardInputArea.reset()
- }
- }
- }
- function press(key, isRealPress) {
- if (key && key.enabled) {
- if (!key.noKeyEvent)
- InputContext.inputEngine.virtualKeyPress(key.key, key.uppercased ? key.text.toUpperCase() : key.text, key.uppercased ? Qt.ShiftModifier : 0, key.repeat && !dragSymbolMode)
- if (isRealPress)
- soundEffect.play(key.soundEffect)
- }
- }
- function release(key) {
- if (key && key.enabled) {
- if (!key.noKeyEvent)
- InputContext.inputEngine.virtualKeyRelease(key.key, key.uppercased ? key.text.toUpperCase() : key.text, key.uppercased ? Qt.ShiftModifier : 0)
- key.clicked()
- }
- }
- function click(key) {
- if (key && key.enabled) {
- if (!key.noKeyEvent)
- InputContext.inputEngine.virtualKeyClick(key.key, InputContext.uppercase ? key.text.toUpperCase() : key.text, InputContext.uppercase ? Qt.ShiftModifier : 0)
- key.clicked()
- }
- }
- function setActiveKey(activeKey) {
- if (keyboard.activeKey === activeKey)
- return
- if (keyboard.activeKey) {
- if (keyboard.activeKey.keyType === QtVirtualKeyboard.KeyType.FlickKey)
- keyboard.activeKey.onKeyChanged.disconnect(onFlickKeyKeyChanged)
- keyboard.activeKey.active = false
- }
- keyboard.activeKey = activeKey
- if (keyboard.activeKey) {
- keyboard.activeKey.active = true
- }
- }
- function keyOnPoint(px, py) {
- var parentItem = keyboardLayoutLoader
- var child = parentItem.childAt(px, py)
- while (child !== null) {
- var position = parentItem.mapToItem(child, px, py)
- px = position.x; py = position.y
- parentItem = child
- child = parentItem.childAt(px, py)
- if (child && child.key !== undefined)
- return child
- }
- return null
- }
- function hitInitialKey(x, y, margin) {
- if (!initialKey)
- return false
- var position = initialKey.mapFromItem(keyboardInputArea, x, y)
- return (position.x > -margin
- && position.y > -margin
- && position.x < initialKey.width + margin
- && position.y < initialKey.height + margin)
- }
- function containsPoint(touchPoints, point) {
- if (!point)
- return false
- for (var i in touchPoints)
- if (touchPoints[i].pointId == point.pointId)
- return true
- return false
- }
- function releaseActiveKey() {
- if (alternativeKeys.active) {
- alternativeKeys.clicked()
- } else if (functionPopupList.active) {
- functionPopupList.clicked()
- } else if (keyboard.activeKey) {
- release(keyboard.activeKey)
- }
- reset()
- }
- function reset() {
- releaseInaccuracyTimer.stop()
- pressAndHoldTimer.stop()
- setActiveKey(null)
- activeTouchPoint = null
- alternativeKeys.close()
- functionPopupList.close()
- if (dragSymbolMode) {
- keyboard.symbolMode = false
- dragSymbolMode = false
- }
- }
- function nextKeyInNavigation(dX, dY, wrapEnabled) {
- var nextKey = null, x, y, itemOffset
- if (dX !== 0 || dY !== 0) {
- var offsetX, offsetY
- for (offsetX = dX, offsetY = dY;
- Math.abs(offsetX) < width && Math.abs(offsetY) < height;
- offsetX += dX, offsetY += dY) {
- x = navigationCursor.x + offsetX
- if (x < 0) {
- if (!wrapEnabled)
- break
- x += width
- } else if (x >= width) {
- if (!wrapEnabled)
- break
- x -= width
- }
- y = navigationCursor.y + offsetY
- if (y < 0) {
- if (!wrapEnabled)
- break
- y += height
- } else if (y >= height) {
- if (!wrapEnabled)
- break
- y -= height
- }
- nextKey = keyOnPoint(x, y)
- if (nextKey) {
- // Check if key is visible. Only the visible keys have keyPanelDelegate set.
- if (nextKey != initialKey && nextKey.hasOwnProperty("keyPanelDelegate") && nextKey.keyPanelDelegate)
- break
- // Jump over the item to reduce the number of iterations in this loop
- itemOffset = mapToItem(nextKey, x, y)
- if (dX > 0)
- offsetX += nextKey.width - itemOffset.x
- else if (dX < 0)
- offsetX -= itemOffset.x
- else if (dY > 0)
- offsetY += nextKey.height - itemOffset.y
- else if (dY < 0)
- offsetY -= itemOffset.y
- }
- nextKey = null
- }
- } else {
- nextKey = keyOnPoint(navigationCursor.x, navigationCursor.y)
- }
- if (nextKey) {
- itemOffset = mapFromItem(nextKey, nextKey.width / 2, nextKey.height / 2)
- if (dX) {
- x = itemOffset.x
- } else if (dY) {
- y = itemOffset.y
- } else {
- x = itemOffset.x
- y = itemOffset.y
- }
- navigationCursor = Qt.point(x, y)
- }
- return nextKey
- }
- function navigateToNextKey(dX, dY, wrapEnabled) {
- // Resolve initial landing point of the navigation cursor
- if (!keyboard.navigationModeActive || keyboard.navigationCursor === Qt.point(-1, -1)) {
- if (dX > 0)
- navigationCursor = Qt.point(0, height / 2)
- else if (dX < 0)
- navigationCursor = Qt.point(width, height / 2)
- else if (dY > 0)
- navigationCursor = Qt.point(width / 2, 0)
- else if (dY < 0)
- navigationCursor = Qt.point(width / 2, height)
- else
- navigationCursor = Qt.point(width / 2, height / 2)
- keyboard.navigationModeActive = true
- }
- if (dX && dY) {
- initialKey = nextKeyInNavigation(dX, 0, wrapEnabled)
- if (initialKey || wrapEnabled)
- initialKey = nextKeyInNavigation(0, dY, wrapEnabled)
- } else {
- initialKey = nextKeyInNavigation(dX, dY, wrapEnabled)
- }
- return initialKey !== null
- }
- function onFlickKeyKeyChanged() {
- InputContext.inputEngine.virtualKeyCancel()
- press(activeKey, false)
- }
- onPressed: (touchPoints) => {
- keyboard.navigationModeActive = false
- // Immediately release any pending key that the user might be
- // holding (and about to release) when a second key is pressed.
- if (activeTouchPoint)
- releaseActiveKey();
- for (var i in touchPoints) {
- // Release any key pressed by a previous iteration of the loop.
- if (containsPoint(touchPoints, activeTouchPoint))
- releaseActiveKey();
- initialKey = keyOnPoint(touchPoints[i].x, touchPoints[i].y)
- if (!initialKey)
- continue
- activeTouchPoint = touchPoints[i]
- if (initialKey.keyType === QtVirtualKeyboard.KeyType.FlickKey) {
- initialKey.press(activeTouchPoint.x, activeTouchPoint.y)
- initialKey.onKeyChanged.connect(onFlickKeyKeyChanged)
- } else {
- releaseInaccuracyTimer.start()
- pressAndHoldTimer.start()
- }
- setActiveKey(initialKey)
- press(initialKey, true)
- }
- }
- onUpdated: (touchPoints) => {
- if (!containsPoint(touchPoints, activeTouchPoint))
- return
- if (alternativeKeys.active) {
- alternativeKeys.move(mapToItem(alternativeKeys, activeTouchPoint.x, 0).x)
- } else if (functionPopupList.active) {
- functionPopupList.move(mapToItem(functionPopupList, activeTouchPoint.x, activeTouchPoint.y))
- } else if (activeKey && activeKey.keyType === QtVirtualKeyboard.KeyType.FlickKey) {
- activeKey.update(activeTouchPoint.x, activeTouchPoint.y)
- } else {
- var key = null
- if (releaseInaccuracyTimer.running) {
- if (hitInitialKey(activeTouchPoint.x, activeTouchPoint.y, releaseMargin)) {
- key = initialKey
- } else if (initialKey) {
- releaseInaccuracyTimer.stop()
- initialKey = null
- }
- }
- if (key === null) {
- key = keyOnPoint(activeTouchPoint.x, activeTouchPoint.y)
- }
- if (key !== keyboard.activeKey) {
- InputContext.inputEngine.virtualKeyCancel()
- setActiveKey(key)
- press(key, false)
- if (dragSymbolMode) {
- if (key && key.functionKey && key.key !== Qt.Key_Context1)
- pressAndHoldTimer.restart()
- else
- pressAndHoldTimer.stop()
- }
- }
- }
- }
- onReleased: (touchPoints) => {
- if (containsPoint(touchPoints, activeTouchPoint)) {
- if (dragSymbolMode) {
- var key = keyOnPoint(activeTouchPoint.x, activeTouchPoint.y)
- if (key && key.key === Qt.Key_Context1) {
- dragSymbolMode = false
- InputContext.inputEngine.virtualKeyCancel()
- reset()
- return
- }
- }
- releaseActiveKey();
- }
- }
- onCanceled: (touchPoints) => {
- if (containsPoint(touchPoints, activeTouchPoint))
- reset()
- }
- }
- }
- }
- }
- Item {
- id: languagePopup
- z: 1
- anchors.fill: parent
- LayoutMirroring.enabled: false
- LayoutMirroring.childrenInherit: true
- MouseArea {
- onPressed: keyboard.hideLanguagePopup()
- anchors.fill: parent
- enabled: languagePopupList.enabled
- }
- PopupList {
- id: languagePopupList
- objectName: "languagePopupList"
- z: 2
- anchors.left: parent.left
- anchors.top: parent.top
- enabled: false
- model: languageListModel
- delegate: keyboard.style ? keyboard.style.languageListDelegate : null
- highlight: keyboard.style ? keyboard.style.languageListHighlight : defaultHighlight
- add: keyboard.style && !keyboard.noAnimations ? keyboard.style.languageListAdd : null
- remove: keyboard.style && !keyboard.noAnimations ? keyboard.style.languageListRemove : null
- property rect previewRect: Qt.rect(keyboard.x + languagePopupList.x,
- keyboard.y + languagePopupList.y,
- languagePopupList.width,
- languagePopupList.height)
- }
- Loader {
- sourceComponent: keyboard.style.languageListBackground
- anchors.fill: languagePopupList
- z: -1
- visible: languagePopupList.visible
- }
- ListModel {
- id: languageListModel
- function selectItem(index) {
- languagePopupList.currentIndex = index
- keyboard.soundEffect.play(languagePopupList.currentItem.soundEffect)
- changeLanguageTimer.newLocaleIndex = languageListModel.get(index).localeIndex
- changeLanguageTimer.start()
- }
- }
- Timer {
- id: changeLanguageTimer
- interval: 1
- property int newLocaleIndex
- onTriggered: {
- if (languagePopupListActive) {
- hideLanguagePopup()
- start()
- } else {
- localeIndex = newLocaleIndex
- }
- }
- }
- function show(locales, parentItem, customLayoutsOnly) {
- let currentIndex = -1
- if (!languagePopupList.enabled) {
- languageListModel.clear()
- for (var i = 0; i < locales.length; i++) {
- languageListModel.append({localeName: locales[i].name, displayName: locales[i].locale.nativeLanguageName, localeIndex: locales[i].index})
- if (locales[i].index === keyboard.localeIndex)
- currentIndex = i
- }
- if (parentItem) {
- languagePopupList.anchors.leftMargin = Qt.binding(function() {
- const newLeftMargin = Math.round(keyboard.mapFromItem(parentItem, (parentItem.width - languagePopupList.width) / 2, 0).x)
- return Math.min(Math.max(0, newLeftMargin), keyboard.width - languagePopupList.width)
- })
- languagePopupList.anchors.topMargin = Qt.binding(function() {return Math.round(keyboard.mapFromItem(parentItem, 0, -languagePopupList.height).y)})
- } else {
- languagePopupList.anchors.leftMargin = Qt.binding(function() {return Math.round((keyboard.width - languagePopupList.width) / 2)})
- languagePopupList.anchors.topMargin = Qt.binding(function() {return Math.round((keyboard.height - languagePopupList.height) / 2)})
- }
- }
- languagePopupList.enabled = true
- if (currentIndex !== -1) {
- languagePopupList.currentIndex = currentIndex
- languagePopupList.forceLayout()
- languagePopupList.positionViewAtIndex(currentIndex, ListView.Center)
- }
- }
- function hide() {
- if (languagePopupList.enabled) {
- languagePopupList.enabled = false
- languagePopupList.anchors.leftMargin = undefined
- languagePopupList.anchors.topMargin = undefined
- languageListModel.clear()
- }
- }
- }
- function showLanguagePopup(parentItem, customLayoutsOnly) {
- var locales = keyboard.listLocales(customLayoutsOnly, parent.externalLanguageSwitchEnabled)
- if (parent.externalLanguageSwitchEnabled) {
- var currentIndex = 0
- for (var i = 0; i < locales.length; i++) {
- if (locales[i] === keyboard.locale) {
- currentIndex = i
- break
- }
- }
- parent.externalLanguageSwitch(locales, currentIndex)
- return
- }
- languagePopup.show(locales, parentItem, customLayoutsOnly)
- }
- function hideLanguagePopup() {
- languagePopup.hide()
- }
- MouseArea {
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.bottom: parent.bottom
- height: keyboard.screenHeight
- onPressed: keyboard.hideWordCandidateContextMenu()
- enabled: wordCandidateContextMenuList.enabled
- }
- Item {
- id: wordCandidateContextMenu
- objectName: "wordCandidateContextMenu"
- z: 1
- anchors.fill: parent
- LayoutMirroring.enabled: false
- LayoutMirroring.childrenInherit: true
- property int previousWordCandidateIndex: -1
- readonly property bool active: wordCandidateContextMenuList.visible
- property bool openedByNavigationKeyLongPress
- PopupList {
- id: wordCandidateContextMenuList
- objectName: "wordCandidateContextMenuList"
- z: 2
- anchors.left: parent.left
- anchors.top: parent.top
- enabled: false
- model: wordCandidateContextMenuListModel
- property rect previewRect: Qt.rect(keyboard.x + wordCandidateContextMenuList.x,
- keyboard.y + wordCandidateContextMenuList.y,
- wordCandidateContextMenuList.width,
- wordCandidateContextMenuList.height)
- }
- Loader {
- sourceComponent: keyboard.style.popupListBackground
- anchors.fill: wordCandidateContextMenuList
- z: -1
- visible: wordCandidateContextMenuList.visible
- }
- ListModel {
- id: wordCandidateContextMenuListModel
- function selectItem(index) {
- wordCandidateContextMenu.previousWordCandidateIndex = -1
- wordCandidateContextMenuList.currentIndex = index
- keyboard.soundEffect.play(wordCandidateContextMenuList.currentItem.soundEffect)
- switch (get(index).action) {
- case "remove":
- wordCandidateView.model.removeItem(wordCandidateView.currentIndex)
- break
- }
- keyboard.hideWordCandidateContextMenu()
- }
- }
- function show(wordCandidateIndex) {
- if (wordCandidateContextMenu.enabled)
- wordCandidateContextMenu.hide()
- wordCandidateContextMenuListModel.clear()
- var canRemoveSuggestion = wordCandidateView.model.dataAt(wordCandidateIndex, SelectionListModel.Role.CanRemoveSuggestion)
- if (canRemoveSuggestion) {
- var dictionaryType = wordCandidateView.model.dataAt(wordCandidateIndex, SelectionListModel.Role.Dictionary)
- var removeItemText;
- switch (dictionaryType) {
- case SelectionListModel.DictionaryType.User:
- //~ VirtualKeyboard Context menu for word suggestion if it can be removed from the user dictionary.
- removeItemText = qsTr("Remove from dictionary")
- break
- case SelectionListModel.DictionaryType.Default:
- // Fallthrough
- default:
- //~ VirtualKeyboard Context menu for word suggestion if it can be removed from the default dictionary.
- removeItemText = qsTr("Block word")
- break
- }
- wordCandidateContextMenuListModel.append({action: "remove", display: removeItemText, wordCompletionLength: 0})
- }
- if (wordCandidateContextMenuListModel.count === 0)
- return
- previousWordCandidateIndex = wordCandidateView.currentIndex
- wordCandidateView.currentIndex = wordCandidateIndex
- wordCandidateContextMenuList.anchors.leftMargin = Qt.binding(function() {
- if (!wordCandidateView.currentItem)
- return 0
- var leftBorder = Math.round(wordCandidateView.mapFromItem(wordCandidateView.currentItem, (wordCandidateView.currentItem.width - wordCandidateContextMenuList.width) / 2, 0).x)
- var rightBorder = Math.round(wordCandidateContextMenuList.parent.width - wordCandidateContextMenuList.width)
- return Math.max(0, Math.min(leftBorder, rightBorder))
- })
- wordCandidateContextMenuList.enabled = true
- wordCandidateContextMenuList.currentIndex = 0
- }
- function hide() {
- if (wordCandidateContextMenuList.enabled) {
- if (previousWordCandidateIndex !== -1) {
- wordCandidateView.currentIndex = previousWordCandidateIndex
- previousWordCandidateIndex = -1
- }
- wordCandidateContextMenuList.enabled = false
- wordCandidateContextMenuList.anchors.leftMargin = undefined
- wordCandidateContextMenuListModel.clear()
- }
- openedByNavigationKeyLongPress = false
- }
- function selectCurrentItem() {
- if (active && wordCandidateContextMenuList.currentIndex !== -1)
- wordCandidateContextMenuListModel.selectItem(wordCandidateContextMenuList.currentIndex)
- }
- }
- function showWordCandidateContextMenu(wordCandidateIndex) {
- wordCandidateContextMenu.show(wordCandidateIndex)
- }
- function hideWordCandidateContextMenu() {
- wordCandidateContextMenu.hide()
- }
- function updateInputMethod() {
- if (!keyboardLayoutLoader.item)
- return
- if (!InputContext.priv.focus)
- return
- // Reset the custom input method if it is not included in the list of shared layouts
- if (customInputMethod && !inputMethodNeedsReset && customInputMethodSharedLayouts.indexOf(layoutType) === -1)
- inputMethodNeedsReset = true
- var customInputMethodToDestroy = null
- if (inputMethodNeedsReset) {
- if (customInputMethod) {
- // Postpones the destruction of the custom input method after creating a new one
- // and after assigning it to the input engine. This allows the input method to clear
- // its state before destroying.
- customInputMethodToDestroy = customInputMethod
- customInputMethod = null
- }
- customInputMethodSharedLayouts = []
- inputMethodNeedsReset = false
- }
- var inputMethod = null
- var inputMode = InputContext.inputEngine.inputMode
- // Use input method from keyboard layout
- if (keyboardLayoutLoader.item.inputMethod) {
- inputMethod = keyboardLayoutLoader.item.inputMethod
- } else if (!customInputMethod) {
- try {
- customInputMethod = keyboardLayoutLoader.item.createInputMethod()
- if (customInputMethod) {
- // Pull the list of shared layouts from the keyboard layout
- if (keyboardLayoutLoader.item.sharedLayouts)
- customInputMethodSharedLayouts = customInputMethodSharedLayouts.concat(keyboardLayoutLoader.item.sharedLayouts)
- // Make sure the current layout is included in the list
- if (customInputMethodSharedLayouts.indexOf(layoutType) === -1)
- customInputMethodSharedLayouts.push(layoutType)
- // Reset input mode, since inputEngine.inputModes is updated
- inputModeNeedsReset = true
- }
- } catch (e) {
- console.error(e.message)
- }
- }
- if (!inputMethod) {
- if (customInputMethod) {
- inputMethod = customInputMethod
- } else if (!VirtualKeyboardSettings.defaultInputMethodDisabled) {
- inputMethod = defaultInputMethod
- } else {
- inputMethod = plainInputMethod
- }
- }
- var inputMethodChanged = InputContext.inputEngine.inputMethod !== inputMethod
- if (inputMethodChanged) {
- InputContext.inputEngine.inputMethod = inputMethod
- }
- if (InputContext.inputEngine.inputMethod) {
- var inputModes = InputContext.inputEngine.inputModes
- if (inputModes.length > 0) {
- // Reset to default input mode if the input locale has changed
- if (inputModeNeedsReset) {
- inputMode = inputModes[0]
- // Check the current layout for input mode override
- if (keyboardLayoutLoader.item.inputMode !== -1)
- inputMode = keyboardLayoutLoader.item.inputMode
- // Update input mode automatically in handwriting mode
- if (keyboard.handwritingMode) {
- if (keyboard.dialableCharactersOnly && inputModes.indexOf(InputEngine.InputMode.Dialable) !== -1)
- inputMode = InputEngine.InputMode.Dialable
- else if ((keyboard.formattedNumbersOnly || keyboard.digitsOnly) && inputModes.indexOf(InputEngine.InputMode.Numeric) !== -1)
- inputMode = InputEngine.InputMode.Numeric
- else if (keyboardLayoutLoader.item.inputMode === -1)
- inputMode = inputModes[0]
- }
- // Check the input method hints for input mode overrides
- if (latinOnly)
- inputMode = InputEngine.InputMode.Latin
- if (preferNumbers)
- inputMode = InputEngine.InputMode.Numeric
- }
- // Make sure the input mode is supported by the current input method
- if (inputModes.indexOf(inputMode) === -1)
- inputMode = inputModes[0]
- if (InputContext.inputEngine.inputMode !== inputMode || inputMethodChanged || inputModeNeedsReset) {
- InputContext.priv.setKeyboardObserver(keyboardObserver)
- InputContext.inputEngine.inputMode = inputMode
- }
- inputModeNeedsReset = false
- }
- }
- if (customInputMethodToDestroy !== null)
- customInputMethodToDestroy.destroy()
- // Clear the toggle shift timer
- InputContext.priv.shiftHandler.clearToggleShiftTimer()
- }
- function updateLayout() {
- var newLayout
- newLayout = findLayout(locale, layoutType)
- if (!newLayout.length) {
- newLayout = findLayout(locale, "main")
- }
- layout = newLayout
- inputLocale = locale
- updateInputMethod()
- }
- function updateDefaultLocale() {
- updateAvailableLocaleIndices()
- if (layoutsModel.count > 0) {
- var defaultLocales = []
- if (isValidLocale(VirtualKeyboardSettings.locale))
- defaultLocales.push(VirtualKeyboardSettings.locale)
- if (isValidLocale(InputContext.locale))
- defaultLocales.push(InputContext.locale)
- if (VirtualKeyboardSettings.activeLocales.length > 0 && isValidLocale(VirtualKeyboardSettings.activeLocales[0]))
- defaultLocales.push(VirtualKeyboardSettings.activeLocales[0])
- if (VirtualKeyboardSettings.availableLocales.indexOf("en_GB") !== -1)
- defaultLocales.push("en_GB")
- if (availableLocaleIndices.length > 0)
- defaultLocales.push(layoutsModel.get(availableLocaleIndices[0], "fileName"))
- var newDefaultLocaleIndex = -1
- for (var i = 0; i < defaultLocales.length; i++) {
- newDefaultLocaleIndex = findLocale(defaultLocales[i], -1)
- if (availableLocaleIndices.indexOf(newDefaultLocaleIndex) !== -1)
- break;
- newDefaultLocaleIndex = -1
- }
- defaultLocaleIndex = newDefaultLocaleIndex
- } else {
- defaultLocaleIndex = -1
- }
- }
- function filterLocaleIndices(filterCb) {
- var localeIndices = []
- for (var i = 0; i < layoutsModel.count; i++) {
- if (localeIndices.indexOf(i) === -1) {
- var localeName = layoutsModel.get(i, "fileName")
- if (filterCb(localeName) && findLayout(localeName, "main"))
- localeIndices.push(i)
- }
- }
- return localeIndices
- }
- function updateAvailableLocaleIndices() {
- // Update list of all available locales
- var fallbackIndex = findFallbackIndex()
- var newIndices = filterLocaleIndices(function(localeName) {
- return isValidLocale(localeName)
- })
- // Handle case where the VirtualKeyboardSettings.activeLocales contains no valid entries
- // Fetch all locales by ignoring active locales setting
- var ignoreActiveLocales = newIndices.length === 0
- if (ignoreActiveLocales) {
- newIndices = filterLocaleIndices(function(localeName) {
- return isValidLocale(localeName, ignoreActiveLocales)
- })
- }
- // Fetch matching locale names
- var newAvailableLocales = []
- for (var i = 0; i < newIndices.length; i++) {
- newAvailableLocales.push(layoutsModel.get(newIndices[i], "fileName"))
- }
- newAvailableLocales.sort()
- var sortOrder = !ignoreActiveLocales && VirtualKeyboardSettings.activeLocales.length > 0 ?
- VirtualKeyboardSettings.activeLocales :
- newAvailableLocales
- newIndices.sort(function(localeIndexA, localeIndexB) {
- var localeNameA = layoutsModel.get(localeIndexA, "fileName")
- var localeNameB = layoutsModel.get(localeIndexB, "fileName")
- var sortIndexA = sortOrder.indexOf(localeNameA)
- var sortIndexB = sortOrder.indexOf(localeNameB)
- return sortIndexA - sortIndexB
- })
- availableLocaleIndices = newIndices
- InputContext.priv.updateAvailableLocales(newAvailableLocales)
- // Update list of custom locale indices
- newIndices = []
- for (i = 0; i < availableLocaleIndices.length; i++) {
- if (availableLocaleIndices[i] === localeIndex ||
- layoutExists(layoutsModel.get(availableLocaleIndices[i], "fileName"), layoutType))
- newIndices.push(availableLocaleIndices[i])
- }
- availableCustomLocaleIndices = newIndices
- }
- function listLocales(customLayoutsOnly, localeNameOnly) {
- var locales = []
- var localeIndices = customLayoutsOnly ? availableCustomLocaleIndices : availableLocaleIndices
- for (var i = 0; i < localeIndices.length; i++) {
- var layoutFolder = layoutsModel.get(localeIndices[i], "fileName")
- if (localeNameOnly)
- locales.push(layoutFolder)
- else
- locales.push({locale:Qt.locale(layoutFolder), index:localeIndices[i], name:layoutFolder})
- }
- return locales
- }
- function nextLocaleIndex(customLayoutsOnly) {
- var newLocaleIndex = localeIndex
- var localeIndices = customLayoutsOnly ? availableCustomLocaleIndices : availableLocaleIndices
- var i = localeIndices.indexOf(localeIndex)
- if (i !== -1) {
- i = (i + 1) % localeIndices.length
- newLocaleIndex = localeIndices[i]
- }
- return newLocaleIndex
- }
- function changeInputLanguage(customLayoutsOnly) {
- var newLocaleIndex = nextLocaleIndex(customLayoutsOnly)
- if (newLocaleIndex !== -1 && newLocaleIndex !== localeIndex)
- localeIndex = newLocaleIndex
- }
- function canChangeInputLanguage(customLayoutsOnly) {
- if (customLayoutsOnly)
- return availableCustomLocaleIndices.length > 1
- return availableLocaleIndices.length > 1
- }
- function findLocale(localeName, defaultValue) {
- var languageCode = localeName.substring(0, 3) // Including the '_' delimiter
- var languageMatch = -1
- for (var i = 0; i < layoutsModel.count; i++) {
- if (!layoutsModel.isFolder(i))
- continue
- var layoutFolder = layoutsModel.get(i, "fileName")
- if (layoutFolder === localeName)
- return i
- if (languageMatch == -1 && layoutFolder.substring(0, 3) === languageCode)
- languageMatch = i
- }
- return (languageMatch != -1) ? languageMatch : defaultValue
- }
- function findFallbackIndex() {
- for (var i = 0; i < layoutsModel.count; i++) {
- var layoutFolder = layoutsModel.get(i, "fileName")
- if (layoutFolder === "fallback")
- return i
- }
- return -1
- }
- function isValidLocale(localeNameOrIndex, ignoreActiveLocales) {
- var localeName
- if (typeof localeNameOrIndex == "number") {
- if (localeNameOrIndex < 0 || localeNameOrIndex >= layoutsModel.count)
- return false
- localeName = layoutsModel.get(localeNameOrIndex, "fileName")
- } else {
- localeName = localeNameOrIndex
- }
- if (!localeName)
- return false
- if (localeName === "fallback")
- return false
- if (Qt.locale(localeName).name === "C")
- return false
- if (ignoreActiveLocales !== true &&
- VirtualKeyboardSettings.activeLocales.length > 0 &&
- VirtualKeyboardSettings.activeLocales.indexOf(localeName) === -1)
- return false
- return true
- }
- function getLayoutFile(localeName, layoutType) {
- if (localeName === "" || layoutType === "")
- return ""
- return layoutsModel.folder + "/" + localeName + "/" + layoutType + ".qml"
- }
- function getFallbackFile(localeName, layoutType) {
- if (localeName === "" || layoutType === "")
- return ""
- return layoutsModel.folder + "/" + localeName + "/" + layoutType + ".fallback"
- }
- function layoutExists(localeName, layoutType) {
- var result = InputContext.priv.fileExists(getLayoutFile(localeName, layoutType))
- if (!result && layoutType === "handwriting")
- result = InputContext.priv.fileExists(getFallbackFile(localeName, layoutType))
- return result
- }
- function findLayout(localeName, layoutType) {
- var layoutFile = getLayoutFile(localeName, layoutType)
- if (InputContext.priv.fileExists(layoutFile))
- return layoutFile
- var fallbackFile = getFallbackFile(localeName, layoutType)
- if (InputContext.priv.fileExists(fallbackFile)) {
- layoutFile = getLayoutFile("fallback", layoutType)
- if (InputContext.priv.fileExists(layoutFile))
- return layoutFile
- }
- return ""
- }
- function isHandwritingAvailable() {
- if (VirtualKeyboardSettings.handwritingModeDisabled)
- return false
- return VirtualKeyboardFeatures.Handwriting && layoutExists(locale, "handwriting")
- }
- function setHandwritingMode(enabled, resetInputMode) {
- if (VirtualKeyboardSettings.handwritingModeDisabled)
- return
- if (enabled && resetInputMode)
- inputModeNeedsReset = true
- handwritingMode = enabled
- }
- function notifyLayoutChanged() {
- Qt.callLater(function() {
- if (keyboardLayoutLoader.item != null) keyboardObserver.layoutChanged()
- })
- }
- function doKeyboardFunction(keyboardFunction) {
- if (!isKeyboardFunctionAvailable(keyboardFunction))
- return
- switch (keyboardFunction) {
- case QtVirtualKeyboard.KeyboardFunction.HideInputPanel:
- InputContext.priv.hideInputPanel()
- break
- case QtVirtualKeyboard.KeyboardFunction.ChangeLanguage:
- if (style.languagePopupListEnabled) {
- if (!languagePopupListActive) {
- showLanguagePopup(activeKey, false)
- } else {
- hideLanguagePopup()
- }
- } else {
- const customLayoutsOnly = arguments.length == 2 && arguments[1]
- changeInputLanguage(customLayoutsOnly)
- }
- break
- case QtVirtualKeyboard.KeyboardFunction.ToggleHandwritingMode:
- setHandwritingMode(!handwritingMode)
- break
- default:
- console.warn("Unknown keyboard function '%1'".arg(keyboardFunction))
- break
- }
- }
- function isKeyboardFunctionAvailable(keyboardFunction) {
- switch (keyboardFunction) {
- case QtVirtualKeyboard.KeyboardFunction.HideInputPanel:
- return true
- case QtVirtualKeyboard.KeyboardFunction.ChangeLanguage:
- const customLayoutsOnly = arguments.length == 2 && arguments[1]
- return canChangeInputLanguage(customLayoutsOnly)
- case QtVirtualKeyboard.KeyboardFunction.ToggleHandwritingMode:
- return isHandwritingAvailable()
- default:
- return false
- }
- }
- function isFunctionPopupListAvailable() {
- const allFunctionKeys = QtVirtualKeyboard.KeyboardFunctionKeys.Hide |
- QtVirtualKeyboard.KeyboardFunctionKeys.Language
- return (VirtualKeyboardSettings.visibleFunctionKeys & allFunctionKeys) !== allFunctionKeys ||
- isHandwritingAvailable()
- }
- }
|