I was using Dashboard 1.0, where the virtual keyboard would appear when I pressed the text input. However, after switching to Dashboard 2.0, I was no longer able to use this feature. I have implemented a similar solution and am sharing it in case anyone else needs it.
The entire functionality works as follows: when a text input is clicked, a pre-created dialog window appears. Inside the dialog, a keyboard is displayed, and when a key is clicked, the corresponding data is added to a globally stored variable and passed on.
Currently, it can only be used with a single UI text node, but I plan to explore alternative methods to improve it further. I would appreciate any ideas or additional suggestions from others!
[
{
"id": "4f81f8796c7be6db",
"type": "ui-text-input",
"z": "4f4a93bcc4e0c4f4",
"group": "f845855078ca3080",
"name": "",
"label": "text",
"order": 1,
"width": 0,
"height": 0,
"topic": "topic",
"topicType": "msg",
"mode": "text",
"tooltip": "",
"delay": 300,
"passthru": true,
"sendOnDelay": false,
"sendOnBlur": true,
"sendOnEnter": true,
"className": "",
"clearable": false,
"sendOnClear": false,
"icon": "",
"iconPosition": "left",
"iconInnerPosition": "inside",
"x": 890,
"y": 520,
"wires": [
[
"e5861f0fb8a66626"
]
]
},
{
"id": "d7c252ad7e82d0b3",
"type": "ui-template",
"z": "4f4a93bcc4e0c4f4",
"group": "f845855078ca3080",
"page": "",
"ui": "",
"name": "text click event",
"order": 2,
"width": 0,
"height": 0,
"head": "",
"format": "<script>\nexport default {\n mounted() {\n this.addInputListeners();\n },\n methods: {\n addInputListeners() {\n const inputTags = document.getElementsByTagName(\"input\");\n console.log(inputTags);\n for (let i = 0; i < inputTags.length; i++) {\n inputTags[i].addEventListener(\"click\", this.openModal, false);\n }\n },\n openModal(event) {\n const msg = { payload: \"keyboar\" };\n this.send(msg);\n }\n }\n};\n</script>\n\n<style scoped>\ninput {\n margin: 0.5em;\n padding: 0.5em;\n}\n</style>\n",
"storeOutMessages": true,
"passthru": true,
"resendOnRefresh": true,
"templateScope": "local",
"className": "",
"x": 520,
"y": 440,
"wires": [
[
"91681223e14df927"
]
]
},
{
"id": "d0c0129bc857d04e",
"type": "debug",
"z": "4f4a93bcc4e0c4f4",
"name": "debug 2673",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 930,
"y": 440,
"wires": []
},
{
"id": "91681223e14df927",
"type": "change",
"z": "4f4a93bcc4e0c4f4",
"name": "",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "{\"groups\":{\"show\":[\"Active Development:keyboard\"]}}",
"tot": "json"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 720,
"y": 440,
"wires": [
[
"d0c0129bc857d04e",
"2c4e5b8bba08b7a4"
]
]
},
{
"id": "2c4e5b8bba08b7a4",
"type": "ui-control",
"z": "4f4a93bcc4e0c4f4",
"name": "",
"ui": "35e7e3e70a04a217",
"events": "all",
"x": 920,
"y": 380,
"wires": [
[]
]
},
{
"id": "c1bd36d069e5fc3c",
"type": "ui-template",
"z": "4f4a93bcc4e0c4f4",
"group": "2a906d93a4506197",
"page": "",
"ui": "",
"name": "",
"order": 1,
"width": 0,
"height": 0,
"head": "",
"format": "<template>\n <div class=\"keyboard-container\">\n <div class=\"keyboard\">\n <div class=\"keyboard-line\" v-for=\"(line, lineIndex) in currentLayout\" :key=\"lineIndex\">\n <button class=\"keyboard-key\" v-for=\"(key, keyIndex) in line\" :key=\"keyIndex\" @click=\"pressKey(key)\">\n {{ displayKey(key) }}\n </button>\n </div>\n </div>\n </div>\n</template>\n\n<script>\nexport default {\n name: 'VirtualKeyboard',\n props: {\n layout: {\n type: String,\n default: 'english'\n }\n },\n data() {\n return {\n shift: false,\n capslock: false,\n englishLayout: [\n ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],\n ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'],\n ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'],\n ['shift', 'z', 'x', 'c', 'v', 'b', 'n', 'm', 'Del'],\n ['-', '/','space', 'return']\n ],\n numericLayout: [\n ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],\n ['Del']\n ]\n }\n },\n computed: {\n currentLayout() {\n return this.layout === 'numeric' ? this.numericLayout : this.englishLayout;\n }\n },\n methods: {\n pressKey(key) {\n if (key === 'shift') {\n this.shift = !this.shift;\n //this.sendMessage({ payload: 'shift' });\n return;\n }\n if (key === 'Del') {\n this.$emit('key-press', 'backspace');\n this.sendMessage({ payload: 'backspace' });\n return;\n }\n if (key === 'space') {\n this.$emit('key-press', ' ');\n this.sendMessage({ payload: ' ' });\n return;\n }\n if (key === 'return') {\n this.$emit('key-press', '\\n');\n this.sendMessage({ payload: '\\n' });\n return;\n }\n let output = key;\n if (this.shift || this.capslock) {\n output = key.toUpperCase();\n if (this.shift) {\n this.shift = false;\n }\n }\n this.$emit('key-press', output);\n this.sendMessage({ payload: output });\n },\n displayKey(key) {\n if (key.length === 1 && /[a-zA-Z]/.test(key)) {\n return (this.shift || this.capslock) ? key.toUpperCase() : key.toLowerCase();\n }\n return key;\n },\n sendMessage(payload) {\n if (typeof this.send === 'function') {\n this.send(payload);\n } else {\n this.$emit('input', payload);\n }\n }\n }\n}\n</script>\n\n<style scoped>\n.keyboard-container {\n display: inline-block;\n border: 1px solid #ccc;\n padding: 10px;\n background: #f9f9f9;\n}\n.keyboard {\n list-style: none;\n padding: 0;\n margin: 0;\n}\n.keyboard-line {\n display: flex;\n margin-bottom: 5px;\n}\n.keyboard-key {\n flex: 1;\n margin: 2px;\n padding: 10px;\n font-size: 16px;\n cursor: pointer;\n border: 1px solid #468db3;\n border-radius: 5px;\n background: #fff;\n transition: background 0.2s;\n}\n.keyboard-key:hover {\n background: #e0f0ff;\n}\n</style>\n",
"storeOutMessages": true,
"passthru": true,
"resendOnRefresh": true,
"templateScope": "local",
"className": "",
"x": 520,
"y": 520,
"wires": [
[
"940966306cf78ad2"
]
]
},
{
"id": "940966306cf78ad2",
"type": "function",
"z": "4f4a93bcc4e0c4f4",
"name": "function 89",
"func": "//<*****************************************************************>//\n// @ts-ignore\nvar context = this.context.global;\n//<*****************************************************************>//\nvar buffer;\n\nif(buffer != \"\")\n{\n if (msg.payload === \"backspace\") \n {\n buffer = buffer.slice(0, -1);\n } else \n {\n buffer += msg.payload;\n }\n}else\n{\n buffer += msg.payload;\n}\n\nmsg.payload = buffer;\n\nreturn msg;\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 710,
"y": 520,
"wires": [
[
"4f81f8796c7be6db",
"3ac979ede4029ac7"
]
]
},
{
"id": "e5861f0fb8a66626",
"type": "debug",
"z": "4f4a93bcc4e0c4f4",
"name": "debug 2674",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 1050,
"y": 520,
"wires": []
},
{
"id": "3ac979ede4029ac7",
"type": "debug",
"z": "4f4a93bcc4e0c4f4",
"name": "debug 2675",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 870,
"y": 600,
"wires": []
},
{
"id": "f845855078ca3080",
"type": "ui-group",
"name": "adminsetting",
"page": "8f7a46dc69023904",
"width": "12",
"height": "1",
"order": 1,
"showTitle": true,
"className": "",
"visible": "true",
"disabled": "false",
"groupType": "default"
},
{
"id": "35e7e3e70a04a217",
"type": "ui-base",
"name": "keyboard",
"path": "/dashboard",
"appIcon": "",
"includeClientData": true,
"acceptsClientConfig": [
"ui-notification",
"ui-gauge"
],
"showPathInSidebar": false,
"showPageTitle": true,
"navigationStyle": "icon",
"titleBarStyle": "fixed",
"showReconnectNotification": false,
"notificationDisplayTime": "1",
"showDisconnectNotification": false
},
{
"id": "2a906d93a4506197",
"type": "ui-group",
"name": "keyboard",
"page": "8f7a46dc69023904",
"width": "12",
"height": "1",
"order": 2,
"showTitle": true,
"className": "",
"visible": "true",
"disabled": "false",
"groupType": "dialog"
},
{
"id": "8f7a46dc69023904",
"type": "ui-page",
"name": "user",
"ui": "35e7e3e70a04a217",
"path": "/page9",
"icon": "account",
"layout": "grid",
"theme": "0d92c765bfad87e6",
"breakpoints": [
{
"name": "Default",
"px": "0",
"cols": "3"
},
{
"name": "Tablet",
"px": "576",
"cols": "6"
},
{
"name": "Small Desktop",
"px": "768",
"cols": "9"
},
{
"name": "Desktop",
"px": "1024",
"cols": "12"
}
],
"order": 1,
"className": "",
"visible": "true",
"disabled": "false"
},
{
"id": "0d92c765bfad87e6",
"type": "ui-theme",
"name": "Basic Blue Theme",
"colors": {
"surface": "#14549e",
"primary": "#336ba9",
"bgPage": "#eeeeee",
"groupBg": "#ffffff",
"groupOutline": "#cccccc"
},
"sizes": {
"pagePadding": "12px",
"groupGap": "12px",
"groupBorderRadius": "4px",
"widgetGap": "12px",
"density": "default"
}
}
]