loupedeck-commander 1.2.12 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/common/ApplicationConfig.mjs +31 -24
- package/common/BaseLoupeDeckHandler.mjs +30 -11
- package/common/ButtonField.mjs +159 -0
- package/common/button.mjs +499 -0
- package/common/utils.mjs +28 -7
- package/config.yaml +6 -0
- package/interfaces/baseif.mjs +1 -1
- package/interfaces/interfaces.mjs +34 -0
- package/interfaces/opcuaif.mjs +67 -45
- package/package.json +3 -2
- package/profile-1.yaml +185 -0
- package/profile-2.yaml +210 -0
- package/test.mjs +15 -1
- package/common/touchbuttons.mjs +0 -597
- package/config.json +0 -13
- package/profile-1.json +0 -272
- package/profile-2.json +0 -290
package/README.md
CHANGED
|
@@ -42,8 +42,8 @@ npm install -s loupedeck-commander
|
|
|
42
42
|
Create a new configuration file with at least one profile or copy from here,
|
|
43
43
|
and replace the image references with your own icons (90x90px size):
|
|
44
44
|
|
|
45
|
-
- [config.
|
|
46
|
-
- [profile-1.
|
|
45
|
+
- [config.yaml](https://gitlab.com/keckxde/loupedeck-commander/-/blob/main/config.yaml)
|
|
46
|
+
- [profile-1.yaml](https://gitlab.com/keckxde/loupedeck-commander/-/blob/main/profile-1.yaml)
|
|
47
47
|
|
|
48
48
|
Create a `index.mjs` file to open up your loupedeck connection:
|
|
49
49
|
|
|
@@ -51,7 +51,7 @@ Create a `index.mjs` file to open up your loupedeck connection:
|
|
|
51
51
|
# save as index.mjs
|
|
52
52
|
import { BaseLoupeDeckHandler } from 'loupedeck-commander'
|
|
53
53
|
|
|
54
|
-
const handler = new BaseLoupeDeckHandler('config.
|
|
54
|
+
const handler = new BaseLoupeDeckHandler('config.yaml')
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
57
|
* Stop the handlers when a signal like SIGINT or SIGTERM arrive
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readConfigFile as readConfigFile, writeJSONFile,syncParams, writeYAMLFile } from './utils.mjs'
|
|
2
2
|
|
|
3
3
|
export class ApplicationConfig {
|
|
4
4
|
application = 'undefined'
|
|
@@ -7,7 +7,8 @@ export class ApplicationConfig {
|
|
|
7
7
|
|
|
8
8
|
loadFromFile (fileName) {
|
|
9
9
|
console.info(`ApplicationConfig: Loading Config File ${fileName}`)
|
|
10
|
-
const config =
|
|
10
|
+
const config = readConfigFile(fileName)
|
|
11
|
+
|
|
11
12
|
|
|
12
13
|
if (!config){
|
|
13
14
|
console.info(`ApplicationConfig: Could not read/parse Config File ${fileName} - breaking here`)
|
|
@@ -66,7 +67,7 @@ class Profile {
|
|
|
66
67
|
|
|
67
68
|
loadFromFile (fileName) {
|
|
68
69
|
console.info(`ProfileConfig: Loading Profile File ${fileName}, Index ${this.#index}`)
|
|
69
|
-
const config =
|
|
70
|
+
const config = readConfigFile(fileName)
|
|
70
71
|
if (config === undefined) {
|
|
71
72
|
console.warn(`ProfileConfig: Cannot parse/load Profile File ${fileName}`)
|
|
72
73
|
return false
|
|
@@ -105,7 +106,13 @@ class Profile {
|
|
|
105
106
|
fileName = fileName.toLowerCase()
|
|
106
107
|
|
|
107
108
|
console.info(`ProfileConfig: Save To Config File ${fileName}`)
|
|
108
|
-
|
|
109
|
+
if(fileName.endsWith('.json')) {
|
|
110
|
+
writeJSONFile(fileName, this)
|
|
111
|
+
writeYAMLFile(fileName.replace('.json','.yaml'), this)
|
|
112
|
+
}else if(fileName.endsWith('.yaml')) {
|
|
113
|
+
writeYAMLFile(fileName, this)
|
|
114
|
+
writeJSONFile(fileName.replace('.yaml','.json'), this)
|
|
115
|
+
}
|
|
109
116
|
}
|
|
110
117
|
}
|
|
111
118
|
|
|
@@ -114,18 +121,18 @@ class Profile {
|
|
|
114
121
|
*/
|
|
115
122
|
class TouchConfig {
|
|
116
123
|
center = {
|
|
117
|
-
"0" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } }
|
|
118
|
-
"1" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } }
|
|
119
|
-
"2" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } }
|
|
120
|
-
"3" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } }
|
|
121
|
-
"4" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } }
|
|
122
|
-
"5" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } }
|
|
123
|
-
"6" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } }
|
|
124
|
-
"7" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } }
|
|
125
|
-
"8" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } }
|
|
126
|
-
"9" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } }
|
|
127
|
-
"10" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } }
|
|
128
|
-
"11" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } }
|
|
124
|
+
"0" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
|
|
125
|
+
"1" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
|
|
126
|
+
"2" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
|
|
127
|
+
"3" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
|
|
128
|
+
"4" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
|
|
129
|
+
"5" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
|
|
130
|
+
"6" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
|
|
131
|
+
"7" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
|
|
132
|
+
"8" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
|
|
133
|
+
"9" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
|
|
134
|
+
"10" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
|
|
135
|
+
"11" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
|
|
129
136
|
} // CENTER Display Config - Available in CT & LIVE
|
|
130
137
|
left = {
|
|
131
138
|
"0" : { "states" : { "on" : { "color": "#000000", "cmd": "echo \"{id} {state}\"" } }, group : "" },
|
|
@@ -177,14 +184,14 @@ class TouchConfig {
|
|
|
177
184
|
class ButtonConfig {
|
|
178
185
|
buttons = {}
|
|
179
186
|
defaultButtons = {
|
|
180
|
-
"0" : {"states" : { "off" : { "filter": "pressed", "color": "#
|
|
181
|
-
"1" : {"states" : { "off" : { "filter": "pressed", "color": "#000055",
|
|
182
|
-
"2" : {"states" : { "off" : { "filter": "pressed", "color": "#000055",
|
|
183
|
-
"3" : {"states" : { "off" : { "filter": "pressed", "color": "#000055",
|
|
184
|
-
"4" : {"states" : { "off" : { "filter": "pressed", "color": "#000055",
|
|
185
|
-
"5" : {"states" : { "off" : { "filter": "pressed", "color": "#000055",
|
|
186
|
-
"6" : {"states" : { "off" : { "filter": "pressed", "color": "#000055",
|
|
187
|
-
"7" : {"states" : { "off" : { "filter": "pressed", "color": "#000055",
|
|
187
|
+
"0" : {"states" : { "off" : { "filter": "pressed", "color": "#005500", "brightness" : 0 }, "half" : { "filter": "pressed", "brightness" : 0.5, "vibrate": 0x58, "color": "#00aa00" } , "on" : { "filter": "pressed", "brightness" : 1, "color": "#00ff00" } }, params: { group : "brightness"} },
|
|
188
|
+
"1" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", }, "on" : { "filter": "pressed", "profile": 0, "color": "#00ff00" } }, params: { group : "profiles"} },
|
|
189
|
+
"2" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", }, "on" : { "filter": "pressed", "profile": 1, "color": "#00ff00" } }, params: { group : "profiles"} },
|
|
190
|
+
"3" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", }, "on" : { "filter": "pressed", "profile": 2, "color": "#00ff00" } }, params: { group : "profiles"} },
|
|
191
|
+
"4" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", }, "on" : { "filter": "pressed", "profile": 3, "color": "#00ff00" } }, params: { group : "profiles"} },
|
|
192
|
+
"5" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", }, "on" : { "filter": "pressed", "profile": 4, "color": "#00ff00" } }, params: { group : "profiles"} },
|
|
193
|
+
"6" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", }, "on" : { "filter": "pressed", "profile": 5, "color": "#00ff00" } }, params: { group : "profiles"} },
|
|
194
|
+
"7" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", }, "on" : { "filter": "pressed", "profile": 6, "color": "#00ff00" } }, params: { group : "profiles"} }
|
|
188
195
|
}
|
|
189
196
|
|
|
190
197
|
constructor (data,profileCount,index) {
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import {discover, HAPTIC,LoupedeckDevice } from 'loupedeck'
|
|
2
2
|
import { ApplicationConfig } from './ApplicationConfig.mjs'
|
|
3
|
-
import { ButtonField
|
|
3
|
+
import { ButtonField } from './ButtonField.mjs'
|
|
4
|
+
|
|
5
|
+
import { InitializeInterfaces, StopInterfaces, opcuainterface, profileEmitter } from '../interfaces/interfaces.mjs'
|
|
4
6
|
|
|
5
7
|
export class BaseLoupeDeckHandler {
|
|
6
8
|
device = undefined
|
|
7
9
|
appConfig = undefined
|
|
8
10
|
profileConfigs = []
|
|
9
11
|
currentProfile = 0
|
|
12
|
+
brightness = 1
|
|
10
13
|
screens = {}
|
|
11
14
|
buttons = {}
|
|
12
15
|
knobs = {}
|
|
@@ -92,10 +95,8 @@ export class BaseLoupeDeckHandler {
|
|
|
92
95
|
await new Promise(resolve => setTimeout(resolve, 250))
|
|
93
96
|
}
|
|
94
97
|
*/
|
|
95
|
-
|
|
96
|
-
this.device.setBrightness(0)
|
|
98
|
+
this.changeBrightness(0)
|
|
97
99
|
await new Promise(resolve => setTimeout(resolve, 250))
|
|
98
|
-
}
|
|
99
100
|
if (this.device){
|
|
100
101
|
this.device.reconnectInterval = 0
|
|
101
102
|
await this.device.close()
|
|
@@ -125,6 +126,25 @@ export class BaseLoupeDeckHandler {
|
|
|
125
126
|
return this.appConfig.loadFromFile(fileName)
|
|
126
127
|
}
|
|
127
128
|
|
|
129
|
+
vibrate (pattern) {
|
|
130
|
+
console.info(`Vibrate with pattern ${pattern}`)
|
|
131
|
+
if (this.device) {
|
|
132
|
+
this.device.vibrate(pattern)
|
|
133
|
+
} else {
|
|
134
|
+
console.warn("No Device connected, cannot vibrate")
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
changeBrightness (brightness) {
|
|
139
|
+
console.info(`Change Brightness to ${brightness}`)
|
|
140
|
+
this.brightness = brightness
|
|
141
|
+
if (this.device) {
|
|
142
|
+
this.device.setBrightness(brightness)
|
|
143
|
+
} else {
|
|
144
|
+
console.warn("No Device connected, cannot change brightness")
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
128
148
|
/**
|
|
129
149
|
* activate the profile with the givven ID
|
|
130
150
|
*/
|
|
@@ -196,20 +216,19 @@ export class BaseLoupeDeckHandler {
|
|
|
196
216
|
|
|
197
217
|
await this.activateProfile(0)
|
|
198
218
|
|
|
199
|
-
// move into activate profile function to call init with every profile change
|
|
200
|
-
// var profile = this.getCurrentProfile()
|
|
201
|
-
//await InitializeInterfaces(profile)
|
|
202
|
-
|
|
203
219
|
const self = this
|
|
204
220
|
|
|
205
221
|
// Register callback on monitored item change:
|
|
206
222
|
opcuainterface.on("monitored item changed",(buttonID,nodeid,val) => { self.buttonStateChanged(buttonID,nodeid,val) })
|
|
207
223
|
profileEmitter.on("profileChanged",(profileID) => { self.activateProfile(profileID) })
|
|
224
|
+
profileEmitter.on("brightnessChanged",(brightness) => { self.changeBrightness(brightness) })
|
|
225
|
+
profileEmitter.on("vibrate",(pattern) => { self.vibrate(pattern) })
|
|
226
|
+
|
|
208
227
|
|
|
209
228
|
|
|
210
|
-
this.
|
|
211
|
-
this.
|
|
212
|
-
|
|
229
|
+
this.changeBrightness(1)
|
|
230
|
+
this.vibrate(HAPTIC.ASCEND_MED)
|
|
231
|
+
|
|
213
232
|
// Fore update of all screens
|
|
214
233
|
console.info('✅ Force Screen update')
|
|
215
234
|
this.screenUpdate["center"] = true
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import {Button} from './button.mjs'
|
|
2
|
+
|
|
3
|
+
export class ButtonField {
|
|
4
|
+
#buttons = {}
|
|
5
|
+
#screen
|
|
6
|
+
width = 0
|
|
7
|
+
height = 0
|
|
8
|
+
#keys = []
|
|
9
|
+
#type
|
|
10
|
+
#name
|
|
11
|
+
#profile
|
|
12
|
+
|
|
13
|
+
constructor (name, rows, columns, width, height, data, profile) {
|
|
14
|
+
console.info(`ButtonField ${name.padEnd(10, ' ')} Buttons: ${rows} x ${columns} , Pixels ${width} x ${height}`)
|
|
15
|
+
this.#name = name
|
|
16
|
+
this.width = width
|
|
17
|
+
this.height = height
|
|
18
|
+
// this.#rows = rows
|
|
19
|
+
// this.#columns = columns
|
|
20
|
+
this.#screen = this.width > 0 && this.height > 0
|
|
21
|
+
this.#type = 'button'
|
|
22
|
+
this.#profile = profile
|
|
23
|
+
if (this.#screen) { this.#type = 'touch' }
|
|
24
|
+
|
|
25
|
+
const keys = Object.keys(data)
|
|
26
|
+
for (let i = 0; i < keys.length; i++) {
|
|
27
|
+
const key = keys[i]
|
|
28
|
+
const tb = new Button(`${this.#type}-${key}`, width / columns, height / rows, data[key],key,this.#profile)
|
|
29
|
+
this.#buttons[key] = tb
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
this.#keys = keys
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
async draw (device) {
|
|
37
|
+
if (!this.#screen) {
|
|
38
|
+
// physical buttons:
|
|
39
|
+
for (let i = 0; i < this.#keys.length; i++) {
|
|
40
|
+
const key = this.#keys[i]
|
|
41
|
+
this.#buttons[key].drawPhysical(device, key)
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
// screen:
|
|
45
|
+
device.drawScreen(this.#name, ctx => {
|
|
46
|
+
ctx.globalCompositeOperation = 'source-atop'
|
|
47
|
+
for (let i = 0; i < this.#keys.length; i++) {
|
|
48
|
+
const key = this.#keys[i]
|
|
49
|
+
const iValue = parseInt(key, 10)
|
|
50
|
+
const row = Math.floor(iValue / device.columns)
|
|
51
|
+
const column = iValue % device.columns
|
|
52
|
+
|
|
53
|
+
this.#buttons[key].draw(row, column, ctx)
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
setState (id, val) {
|
|
60
|
+
this.#buttons[id].setState(val)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/*setIntState (id, val) {
|
|
64
|
+
this.#buttons[id].setIntState(val)
|
|
65
|
+
}*/
|
|
66
|
+
|
|
67
|
+
async load () {
|
|
68
|
+
for (let i = 0; i < this.#keys.length; i++) {
|
|
69
|
+
const key = this.#keys[i]
|
|
70
|
+
if (isNaN(key)) {
|
|
71
|
+
await this.#buttons[key].load(this.#profile)
|
|
72
|
+
} else {
|
|
73
|
+
const iVal = parseInt(key, 10)
|
|
74
|
+
await this.#buttons[iVal].load(this.#profile)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async pressed (id) {
|
|
80
|
+
this.checkAndCreateButton(id)
|
|
81
|
+
const result = await this.#buttons[id].pressed()
|
|
82
|
+
if (!result) {
|
|
83
|
+
console.info(`pressed ${this.#type} ${id}`)
|
|
84
|
+
}
|
|
85
|
+
return result
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Button released event handler
|
|
90
|
+
* @param {*} id
|
|
91
|
+
* @returns
|
|
92
|
+
*/
|
|
93
|
+
async released (id) {
|
|
94
|
+
const result = await this.#buttons[id].released()
|
|
95
|
+
if (result) {
|
|
96
|
+
// disable all other buttons of the group, if this one had been activated:
|
|
97
|
+
for (let i = 0; i < this.#keys.length; i++) {
|
|
98
|
+
let key = this.#keys[i]
|
|
99
|
+
if (!isNaN(key)) { key = parseInt(key, 10) }
|
|
100
|
+
if (id === key) { continue }
|
|
101
|
+
if (this.#buttons[key].group === this.#buttons[id].group) {
|
|
102
|
+
this.#buttons[key].setState(0)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (!result) {
|
|
107
|
+
console.info(`released ${this.#type} ${id}`)
|
|
108
|
+
}
|
|
109
|
+
return result
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Button changed event handler (after opcua value change)
|
|
114
|
+
* @param {*} buttonID
|
|
115
|
+
* @param {*} nodeid
|
|
116
|
+
* @param {*} val
|
|
117
|
+
*/
|
|
118
|
+
async changed(buttonID,nodeid,val){
|
|
119
|
+
for (let i = 0; i < this.#keys.length; i++) {
|
|
120
|
+
let bID = this.#keys[i]
|
|
121
|
+
await this.#buttons[bID].changed(i,nodeid,val)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Handle a rotation event for a knob
|
|
127
|
+
* @param {*} id : Knob ID (e.g. 'knobTL, 'knobTR', 'knobBL', 'knobBR')
|
|
128
|
+
* @param {*} delta
|
|
129
|
+
* @returns
|
|
130
|
+
*/
|
|
131
|
+
async rotated (id, delta) {
|
|
132
|
+
this.checkAndCreateButton(id)
|
|
133
|
+
const result = await this.#buttons[id].rotated(delta)
|
|
134
|
+
if (!result) { console.info(`rotated ${this.#type} ${id} ${delta}`) }
|
|
135
|
+
return result
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Handle a touchmove event for a touchbutton (available in left, center and right button fields)
|
|
140
|
+
* @param {*} id
|
|
141
|
+
* @param {*} x
|
|
142
|
+
* @param {*} y
|
|
143
|
+
* @returns
|
|
144
|
+
*/
|
|
145
|
+
async touchmove (id, x, y) {
|
|
146
|
+
this.checkAndCreateButton(id)
|
|
147
|
+
const result = await this.#buttons[id].touchmove(x, y)
|
|
148
|
+
if (!result) { console.info(`touchmove ${id} ${x} ${y}`) }
|
|
149
|
+
return result
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
checkAndCreateButton (id) {
|
|
153
|
+
if (!(id in this.#buttons)) {
|
|
154
|
+
const tb = new Button(id, 1, 1, id)
|
|
155
|
+
this.#buttons[id] = tb
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|