loupedeck-commander 1.4.1 → 1.4.2
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/LICENSE +201 -201
- package/README.md +131 -131
- package/common/ApplicationConfig.mjs +300 -300
- package/common/BaseLoupeDeckHandler.mjs +393 -381
- package/common/ButtonField.mjs +168 -166
- package/common/button.mjs +533 -520
- package/common/cmd-executer.mjs +16 -16
- package/common/index.mjs +5 -5
- package/common/utils.mjs +106 -106
- package/config.yaml +8 -8
- package/index.mjs +3 -3
- package/interfaces/baseif.mjs +71 -71
- package/interfaces/httpif.mjs +90 -90
- package/interfaces/interfaces.mjs +34 -34
- package/interfaces/opcuaif.mjs +484 -481
- package/interfaces/shellif.mjs +58 -58
- package/package.json +32 -32
- package/profile-1.yaml +186 -188
- package/profile-2.yaml +213 -215
- package/test.mjs +40 -40
package/common/ButtonField.mjs
CHANGED
|
@@ -1,166 +1,168 @@
|
|
|
1
|
-
import {Button} from './button.mjs'
|
|
2
|
-
|
|
3
|
-
export class ButtonField {
|
|
4
|
-
#buttons = {}
|
|
5
|
-
#screen
|
|
6
|
-
width = 0
|
|
7
|
-
height = 0
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
this
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
this.#
|
|
21
|
-
this.#
|
|
22
|
-
this.#
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
*
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if (
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
//
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
*
|
|
121
|
-
* @param {*}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
*
|
|
136
|
-
* @
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
*
|
|
149
|
-
* @param {*}
|
|
150
|
-
* @
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
166
|
-
|
|
1
|
+
import {Button} from './button.mjs'
|
|
2
|
+
|
|
3
|
+
export class ButtonField {
|
|
4
|
+
#buttons = {}
|
|
5
|
+
#screen
|
|
6
|
+
width = 0
|
|
7
|
+
height = 0
|
|
8
|
+
#rows = 0
|
|
9
|
+
#columns = 0
|
|
10
|
+
#keys = []
|
|
11
|
+
#type
|
|
12
|
+
#name
|
|
13
|
+
#profile
|
|
14
|
+
|
|
15
|
+
constructor (name, rows, columns, width, height, data, profile) {
|
|
16
|
+
console.info(`ButtonField ${name.padEnd(10, ' ')} Buttons: ${rows} x ${columns} , Pixels ${width} x ${height}`)
|
|
17
|
+
this.#name = name
|
|
18
|
+
this.width = width
|
|
19
|
+
this.height = height
|
|
20
|
+
this.#rows = rows
|
|
21
|
+
this.#columns = columns
|
|
22
|
+
this.#screen = this.width > 0 && this.height > 0
|
|
23
|
+
this.#type = 'button'
|
|
24
|
+
this.#profile = profile
|
|
25
|
+
if (this.#screen) { this.#type = 'touch' }
|
|
26
|
+
|
|
27
|
+
const keys = Object.keys(data)
|
|
28
|
+
for (let i = 0; i < keys.length; i++) {
|
|
29
|
+
const key = keys[i]
|
|
30
|
+
const tb = new Button(`${this.#type}-${key}`, width / columns, height / rows, data[key],key,this.#profile)
|
|
31
|
+
this.#buttons[key] = tb
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
this.#keys = keys
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
async draw (device) {
|
|
39
|
+
if (!this.#screen) {
|
|
40
|
+
// physical buttons:
|
|
41
|
+
for (let i = 0; i < this.#keys.length; i++) {
|
|
42
|
+
const key = this.#keys[i]
|
|
43
|
+
this.#buttons[key].drawPhysical(device, key)
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
// screen:
|
|
47
|
+
device.drawScreen(this.#name, ctx => {
|
|
48
|
+
ctx.globalCompositeOperation = 'source-atop'
|
|
49
|
+
for (let i = 0; i < this.#keys.length; i++) {
|
|
50
|
+
const key = this.#keys[i]
|
|
51
|
+
const iValue = parseInt(key, 10)
|
|
52
|
+
const row = Math.floor(iValue / device.columns)
|
|
53
|
+
const column = iValue % device.columns
|
|
54
|
+
|
|
55
|
+
this.#buttons[key].draw(row, column, ctx)
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
setState (id, val) {
|
|
62
|
+
this.#buttons[id].setState(val)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/*setIntState (id, val) {
|
|
66
|
+
this.#buttons[id].setIntState(val)
|
|
67
|
+
}*/
|
|
68
|
+
|
|
69
|
+
async load () {
|
|
70
|
+
for (let i = 0; i < this.#keys.length; i++) {
|
|
71
|
+
const key = this.#keys[i]
|
|
72
|
+
if (isNaN(key)) {
|
|
73
|
+
await this.#buttons[key].load(this.#profile)
|
|
74
|
+
} else {
|
|
75
|
+
const iVal = parseInt(key, 10)
|
|
76
|
+
await this.#buttons[iVal].load(this.#profile)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async pressed (id) {
|
|
82
|
+
this.checkAndCreateButton(id)
|
|
83
|
+
const result = await this.#buttons[id].pressed()
|
|
84
|
+
if (!result) {
|
|
85
|
+
console.info(`pressed ${this.#type} ${id}`)
|
|
86
|
+
}
|
|
87
|
+
return result
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Button released event handler
|
|
92
|
+
* @param {*} id
|
|
93
|
+
* @returns
|
|
94
|
+
*/
|
|
95
|
+
async released (id) {
|
|
96
|
+
const result = await this.#buttons[id].released()
|
|
97
|
+
if (result) {
|
|
98
|
+
// disable all other buttons of the group, if this one had been activated:
|
|
99
|
+
for (let i = 0; i < this.#keys.length; i++) {
|
|
100
|
+
let key = this.#keys[i]
|
|
101
|
+
if (!isNaN(key)) { key = parseInt(key, 10) }
|
|
102
|
+
// Ignore for myself (active element of the group)
|
|
103
|
+
if (id === key) { continue }
|
|
104
|
+
let toggleGroup = this.#buttons[id].getGroup()
|
|
105
|
+
// Ignore empty groups
|
|
106
|
+
if (toggleGroup === undefined || toggleGroup == "" ) { continue }
|
|
107
|
+
// Switch all other elements of the same group off:
|
|
108
|
+
if (this.#buttons[key].getGroup() === toggleGroup) {
|
|
109
|
+
this.#buttons[key].setState(0)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (!result) {
|
|
114
|
+
console.info(`released ${this.#type} ${id}`)
|
|
115
|
+
}
|
|
116
|
+
return result
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Button changed event handler (after opcua value change)
|
|
121
|
+
* @param {*} buttonID
|
|
122
|
+
* @param {*} nodeid
|
|
123
|
+
* @param {*} val
|
|
124
|
+
*/
|
|
125
|
+
async buttonStateChanged(changedButtonID,attribute,nodeid,val){
|
|
126
|
+
// todo: filter for buttonID
|
|
127
|
+
for (let i = 0; i < this.#keys.length; i++) {
|
|
128
|
+
let buttonID = this.#keys[i]
|
|
129
|
+
if (changedButtonID == buttonID)
|
|
130
|
+
await this.#buttons[buttonID].buttonStateChanged(i,attribute,nodeid,val)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Handle a rotation event for a knob
|
|
136
|
+
* @param {*} id : Knob ID (e.g. 'knobTL, 'knobTR', 'knobBL', 'knobBR')
|
|
137
|
+
* @param {*} delta
|
|
138
|
+
* @returns
|
|
139
|
+
*/
|
|
140
|
+
async rotated (id, delta) {
|
|
141
|
+
this.checkAndCreateButton(id)
|
|
142
|
+
const result = await this.#buttons[id].rotated(delta)
|
|
143
|
+
if (!result) { console.info(`rotated ${this.#type} ${id} ${delta}`) }
|
|
144
|
+
return result
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Handle a touchmove event for a touchbutton (available in left, center and right button fields)
|
|
149
|
+
* @param {*} id
|
|
150
|
+
* @param {*} x
|
|
151
|
+
* @param {*} y
|
|
152
|
+
* @returns
|
|
153
|
+
*/
|
|
154
|
+
async touchmove (id, x, y) {
|
|
155
|
+
this.checkAndCreateButton(id)
|
|
156
|
+
const result = await this.#buttons[id].touchmove(x, y)
|
|
157
|
+
if (!result) { console.info(`touchmove ${id} ${x} ${y}`) }
|
|
158
|
+
return result
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
checkAndCreateButton (id) {
|
|
162
|
+
if (!(id in this.#buttons)) {
|
|
163
|
+
const tb = new Button(id, 1, 1, id)
|
|
164
|
+
this.#buttons[id] = tb
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|