virtual-keypad 5.13.0 → 5.13.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 +21 -21
- package/README.md +45 -45
- package/dist/404.html +14 -14
- package/dist/fonts/Pelli-EyeChart.svg +494 -494
- package/dist/fonts/Sloan.svg +138 -138
- package/dist/index.html +22 -22
- package/dist/keypad.html +58 -58
- package/dist/main.js +1 -1
- package/dist/main.js.LICENSE.txt +8 -8
- package/dist/receiver.html +146 -146
- package/dist/server.js +66 -66
- package/package.json +36 -36
- package/src/keypad.css +108 -108
- package/src/keypad.js +399 -385
- package/src/keypadPeer.js +191 -189
- package/src/main.js +4 -4
- package/src/maxKeySize.js +142 -105
- package/src/receiver.css +11 -11
- package/src/receiver.js +257 -223
- package/webpack.common.js +30 -30
- package/webpack.dev.js +9 -9
- package/webpack.prod.js +6 -6
package/src/receiver.js
CHANGED
|
@@ -1,223 +1,257 @@
|
|
|
1
|
-
// import { QRCode } from "qrcode";
|
|
2
|
-
var QRCode = require("qrcode");
|
|
3
|
-
import "./receiver.css";
|
|
4
|
-
import { KeypadPeer } from "./keypadPeer.js";
|
|
5
|
-
|
|
6
|
-
const doNothing = () => undefined;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class Receiver extends KeypadPeer {
|
|
17
|
-
constructor(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
this.
|
|
32
|
-
this.
|
|
33
|
-
this.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
this.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
this.
|
|
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
|
-
try {
|
|
99
|
-
this.conn.send(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
this.
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
this.
|
|
177
|
-
|
|
178
|
-
this.
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
this.conn
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
1
|
+
// import { QRCode } from "qrcode";
|
|
2
|
+
var QRCode = require("qrcode");
|
|
3
|
+
import "./receiver.css";
|
|
4
|
+
import { KeypadPeer } from "./keypadPeer.js";
|
|
5
|
+
|
|
6
|
+
const doNothing = () => undefined;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param {{alphabet: string[], font:string}} keypadParameters
|
|
10
|
+
* @param {(data) => void} onDataCallback
|
|
11
|
+
* @param {() => void} handshakeCallback
|
|
12
|
+
* @param {(connection) => void} customConnectionCallback
|
|
13
|
+
* @param {() => void} customCloseCallback
|
|
14
|
+
* @param {(error) => void} customErrorCallback
|
|
15
|
+
*/
|
|
16
|
+
class Receiver extends KeypadPeer {
|
|
17
|
+
constructor(
|
|
18
|
+
keypadParameters,
|
|
19
|
+
onDataCallback = doNothing,
|
|
20
|
+
handshakeCallback = doNothing,
|
|
21
|
+
customConnectionCallback = doNothing,
|
|
22
|
+
customCloseCallback = doNothing,
|
|
23
|
+
customErrorCallback = doNothing
|
|
24
|
+
) {
|
|
25
|
+
super({
|
|
26
|
+
targetElementId: keypadParameters.targetElementId,
|
|
27
|
+
onErrorReconnectMessage: keypadParameters.onErrorReconnectMessage,
|
|
28
|
+
});
|
|
29
|
+
keypadParameters = this.#verifyKeypadParameters(keypadParameters);
|
|
30
|
+
|
|
31
|
+
this.alphabet = this.checkAlphabet(keypadParameters["alphabet"]); // What symbols to display on the keys
|
|
32
|
+
this.font = keypadParameters["font"]; // What fontface to display the symbols in
|
|
33
|
+
this.onErrorReconnectMessage =
|
|
34
|
+
keypadParameters.onErrorReconnectMessage ??
|
|
35
|
+
"Connection lost. Please reconnect...";
|
|
36
|
+
|
|
37
|
+
this.onData = onDataCallback; // What to do on a button-press
|
|
38
|
+
this.onHandshake = () => {
|
|
39
|
+
handshakeCallback();
|
|
40
|
+
this._setupHeartBeatIntervals();
|
|
41
|
+
}; // What to do when the connection is established
|
|
42
|
+
this.onConnection = (connection) => {
|
|
43
|
+
this.#onPeerConnection(connection);
|
|
44
|
+
customConnectionCallback(connection);
|
|
45
|
+
};
|
|
46
|
+
this.onClose = () => {
|
|
47
|
+
this.onPeerClose();
|
|
48
|
+
customCloseCallback();
|
|
49
|
+
};
|
|
50
|
+
this.onError = (err) => {
|
|
51
|
+
this.onPeerError(err);
|
|
52
|
+
customErrorCallback(err);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/* Set up callbacks that handle any events related to our peer object. */
|
|
56
|
+
this.peer.on("open", this.#onPeerOpen); // On creation of Receiver (local) Peer object
|
|
57
|
+
this.peer.on("connection", this.onConnection); // On connection with Keypad (remote) Peer object
|
|
58
|
+
this.peer.on("disconnected", this.onPeerDisconnected);
|
|
59
|
+
this.peer.on("close", this.onClose);
|
|
60
|
+
this.peer.on("error", this.onError);
|
|
61
|
+
}
|
|
62
|
+
update = (alphabet = undefined, font = undefined) => {
|
|
63
|
+
// Update alphabet
|
|
64
|
+
if (typeof alphabet !== "undefined") {
|
|
65
|
+
const validAlphabet = this.checkAlphabet(alphabet);
|
|
66
|
+
if (String(this.alphabet) !== String(validAlphabet))
|
|
67
|
+
this.displayUpdate("New alphabet: " + String(validAlphabet), true); // DEBUG
|
|
68
|
+
this.alphabet = validAlphabet; // Store new alphabet
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Update font
|
|
72
|
+
// TODO check if the font is supported, somehow
|
|
73
|
+
this.font = font ?? this.font; // Store new font
|
|
74
|
+
|
|
75
|
+
// Update keypad
|
|
76
|
+
try {
|
|
77
|
+
this.conn.send({
|
|
78
|
+
message: "Update",
|
|
79
|
+
alphabet: this.alphabet,
|
|
80
|
+
font: this.font,
|
|
81
|
+
peerID: this.peer.id,
|
|
82
|
+
});
|
|
83
|
+
} catch (e) {
|
|
84
|
+
this.displayUpdate(
|
|
85
|
+
`Error updating! Alphabet: ${String(this.alphabet)}, font: ${
|
|
86
|
+
this.font
|
|
87
|
+
}`,
|
|
88
|
+
e
|
|
89
|
+
); // DEBUG
|
|
90
|
+
console.error(e);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
disableKeys = (whichKeys = undefined) => {
|
|
94
|
+
const message = {
|
|
95
|
+
message: "Disable",
|
|
96
|
+
};
|
|
97
|
+
if (whichKeys) message.keys = whichKeys;
|
|
98
|
+
try {
|
|
99
|
+
this.conn.send(message);
|
|
100
|
+
} catch (e) {
|
|
101
|
+
this.displayUpdate(`Error disabling keys. Keys: ${whichKeys}`);
|
|
102
|
+
console.error(e);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
enableKeys = (whichKeys = undefined) => {
|
|
106
|
+
const message = {
|
|
107
|
+
message: "Enable",
|
|
108
|
+
};
|
|
109
|
+
if (whichKeys) message.keys = whichKeys;
|
|
110
|
+
try {
|
|
111
|
+
this.conn.send(message);
|
|
112
|
+
} catch (e) {
|
|
113
|
+
this.displayUpdate(`Error enabling keys. Keys: ${whichKeys}`);
|
|
114
|
+
console.error(e);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
updateDisplayMessage = (message) => {
|
|
118
|
+
try {
|
|
119
|
+
this.conn.send({
|
|
120
|
+
message: "UpdateHeader",
|
|
121
|
+
headerContent: message,
|
|
122
|
+
});
|
|
123
|
+
} catch (e) {
|
|
124
|
+
this.displayUpdate("Error in updating message!"); // DEBUG
|
|
125
|
+
console.error(e);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
updateFooterMessage = (message) => {
|
|
129
|
+
try {
|
|
130
|
+
this.conn.send({
|
|
131
|
+
message: "UpdateFooter",
|
|
132
|
+
headerContent: message,
|
|
133
|
+
});
|
|
134
|
+
} catch (e) {
|
|
135
|
+
this.displayUpdate("Error in updating footer message."); // Debug
|
|
136
|
+
console.error(e);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
#verifyKeypadParameters = (keypadParameters) => {
|
|
140
|
+
if (!keypadParameters.hasOwnProperty("alphabet")) {
|
|
141
|
+
console.error(
|
|
142
|
+
"Must provide 'alphabet' parameter to Receiver object. Defaulting to 'CDHKNORSVZ'"
|
|
143
|
+
);
|
|
144
|
+
keypadParameters["alphabet"] = "CDHKNORSVZ".split("");
|
|
145
|
+
} else {
|
|
146
|
+
keypadParameters["alphabet"] = this.checkAlphabet(
|
|
147
|
+
keypadParameters.alphabet
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
if (!keypadParameters.hasOwnProperty("font")) {
|
|
151
|
+
console.error(
|
|
152
|
+
"Must provide 'font' parameter to Receiver object. Defaulting to 'Arial'"
|
|
153
|
+
);
|
|
154
|
+
keypadParameters["alphabet"] = "Arial";
|
|
155
|
+
} else {
|
|
156
|
+
// FUTURE verify that the selected font is available
|
|
157
|
+
}
|
|
158
|
+
return keypadParameters;
|
|
159
|
+
};
|
|
160
|
+
#onPeerOpen = (id) => {
|
|
161
|
+
// Workaround for peer.reconnect deleting previous id
|
|
162
|
+
if (this.id === null) {
|
|
163
|
+
this.displayUpdate("Received null id from peer open"); // DEBUG
|
|
164
|
+
this.peer.id = this.lastPeerId;
|
|
165
|
+
} else {
|
|
166
|
+
this.lastPeerId = this.peer.id;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const params = {
|
|
170
|
+
// alphabet: this.alphabet,
|
|
171
|
+
// font: this.font,
|
|
172
|
+
peerID: this.peer.id,
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
let queryString = this.queryStringFromObject(params);
|
|
176
|
+
const uri = this.keypadUrl + queryString;
|
|
177
|
+
this.qrURL = uri;
|
|
178
|
+
console.log(this.qrURL);
|
|
179
|
+
|
|
180
|
+
// Display QR code for the participant to scan
|
|
181
|
+
const qrCanvas = document.createElement("canvas");
|
|
182
|
+
|
|
183
|
+
QRCode.toCanvas(qrCanvas, uri, function (error) {
|
|
184
|
+
if (error) console.error(error);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// Store encoding of QR code, eg to use as an image source
|
|
188
|
+
this.qrURI = qrCanvas.toDataURL();
|
|
189
|
+
|
|
190
|
+
if (!!document.getElementById(this.targetElement)) {
|
|
191
|
+
document.getElementById(this.targetElement).appendChild(qrCanvas);
|
|
192
|
+
} else {
|
|
193
|
+
console.log("Peer reachable at: ", uri);
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
#onPeerConnection = (connection) => {
|
|
197
|
+
// Allow only a single connection
|
|
198
|
+
if (this.conn && this.conn.open) {
|
|
199
|
+
connection.on("open", function () {
|
|
200
|
+
connection.send({
|
|
201
|
+
message: "Rejected",
|
|
202
|
+
info: "Already connected to another client",
|
|
203
|
+
});
|
|
204
|
+
setTimeout(function () {
|
|
205
|
+
connection.close();
|
|
206
|
+
}, 500);
|
|
207
|
+
});
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
this.conn = connection;
|
|
211
|
+
console.log("Connection: ", connection);
|
|
212
|
+
this.displayUpdate("You typed: ");
|
|
213
|
+
this.#ready();
|
|
214
|
+
};
|
|
215
|
+
#ready = () => {
|
|
216
|
+
/*
|
|
217
|
+
* Triggered once a connection has been achieved.
|
|
218
|
+
* Defines callbacks to handle incoming data and connection events.
|
|
219
|
+
*/
|
|
220
|
+
// Perform callback with data
|
|
221
|
+
this.conn.on("data", (data) => {
|
|
222
|
+
data = data; // data = JSON.parse(data);
|
|
223
|
+
console.log("Received data: ", data);
|
|
224
|
+
switch (data.message) {
|
|
225
|
+
case "Handshake":
|
|
226
|
+
this.conn.send({
|
|
227
|
+
message: "KeypadParameters",
|
|
228
|
+
alphabet: this.alphabet,
|
|
229
|
+
font: this.font,
|
|
230
|
+
});
|
|
231
|
+
this.onHandshake();
|
|
232
|
+
break;
|
|
233
|
+
case "Keypress":
|
|
234
|
+
this.onData(data);
|
|
235
|
+
break;
|
|
236
|
+
// TODO factor out into keypadPeer
|
|
237
|
+
case "Heartbeat":
|
|
238
|
+
this.lastHeartbeat = performance.now();
|
|
239
|
+
break;
|
|
240
|
+
default:
|
|
241
|
+
console.log("Message type: ", data.message);
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
this.conn.on("close", () => {
|
|
245
|
+
this.onClose();
|
|
246
|
+
this.displayUpdate("Connection reset. Awaiting connection...");
|
|
247
|
+
this.conn = null;
|
|
248
|
+
});
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
/*
|
|
252
|
+
Referenced links:
|
|
253
|
+
https://stackoverflow.com/questions/28016664/when-you-pass-this-as-an-argument/28016676#28016676
|
|
254
|
+
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
|
|
255
|
+
*/
|
|
256
|
+
|
|
257
|
+
export { Receiver };
|
package/webpack.common.js
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
|
|
3
|
-
module.exports = {
|
|
4
|
-
entry: './src/main.js',
|
|
5
|
-
output: {
|
|
6
|
-
path: path.resolve(__dirname, 'dist'),
|
|
7
|
-
filename: '[name].js',
|
|
8
|
-
library: 'virtualKeypad',
|
|
9
|
-
libraryTarget: 'umd',
|
|
10
|
-
},
|
|
11
|
-
module: {
|
|
12
|
-
rules: [
|
|
13
|
-
{ test: /\.css$/,
|
|
14
|
-
use: [ 'style-loader', 'css-loader', ],
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
|
|
18
|
-
use: [
|
|
19
|
-
{
|
|
20
|
-
loader: 'file-loader',
|
|
21
|
-
options: {
|
|
22
|
-
name: '[name].[ext]',
|
|
23
|
-
outputPath: 'fonts/'
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
],
|
|
27
|
-
},
|
|
28
|
-
]
|
|
29
|
-
}
|
|
30
|
-
};
|
|
1
|
+
const path = require('path');
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
entry: './src/main.js',
|
|
5
|
+
output: {
|
|
6
|
+
path: path.resolve(__dirname, 'dist'),
|
|
7
|
+
filename: '[name].js',
|
|
8
|
+
library: 'virtualKeypad',
|
|
9
|
+
libraryTarget: 'umd',
|
|
10
|
+
},
|
|
11
|
+
module: {
|
|
12
|
+
rules: [
|
|
13
|
+
{ test: /\.css$/,
|
|
14
|
+
use: [ 'style-loader', 'css-loader', ],
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
|
|
18
|
+
use: [
|
|
19
|
+
{
|
|
20
|
+
loader: 'file-loader',
|
|
21
|
+
options: {
|
|
22
|
+
name: '[name].[ext]',
|
|
23
|
+
outputPath: 'fonts/'
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
};
|
package/webpack.dev.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
const { merge } = require('webpack-merge');
|
|
2
|
-
const common = require('./webpack.common.js');
|
|
3
|
-
|
|
4
|
-
module.exports = merge(common, {
|
|
5
|
-
mode: 'development',
|
|
6
|
-
devtool: 'inline-source-map',
|
|
7
|
-
devServer: {
|
|
8
|
-
static: './dist',
|
|
9
|
-
},
|
|
1
|
+
const { merge } = require('webpack-merge');
|
|
2
|
+
const common = require('./webpack.common.js');
|
|
3
|
+
|
|
4
|
+
module.exports = merge(common, {
|
|
5
|
+
mode: 'development',
|
|
6
|
+
devtool: 'inline-source-map',
|
|
7
|
+
devServer: {
|
|
8
|
+
static: './dist',
|
|
9
|
+
},
|
|
10
10
|
});
|
package/webpack.prod.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const { merge } = require('webpack-merge');
|
|
2
|
-
const common = require('./webpack.common.js');
|
|
3
|
-
|
|
4
|
-
module.exports = merge(common, {
|
|
5
|
-
mode: 'production',
|
|
6
|
-
devtool: 'source-map',
|
|
1
|
+
const { merge } = require('webpack-merge');
|
|
2
|
+
const common = require('./webpack.common.js');
|
|
3
|
+
|
|
4
|
+
module.exports = merge(common, {
|
|
5
|
+
mode: 'production',
|
|
6
|
+
devtool: 'source-map',
|
|
7
7
|
});
|