Skip to content

Commit

Permalink
Refactor in terms of user intents
Browse files Browse the repository at this point in the history
Reflect the latest changes to the AT Driver specification, where "press
keys" has been restructured as a parameters of a new "interaction"
command designed for "user intents."
  • Loading branch information
jugglinmike committed Feb 13, 2025
1 parent 6eb43aa commit 96e7b3c
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 16 deletions.
4 changes: 2 additions & 2 deletions shared/install/macos.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const { promisify } = require('util');

const debug = require('debug')('install');

const { 'interaction.pressKeys': pressKeys } = require('../modules/macos/interaction');
const { 'interaction.userIntent': userIntent } = require('../modules/macos/interaction');

const LSREGISTER_EXECUTABLE_PATH =
'/System/Library/Frameworks/CoreServices.framework/Versions/Current/Frameworks/LaunchServices.framework/Versions/Current/Support/lsregister';
Expand Down Expand Up @@ -134,7 +134,7 @@ exports.uninstall = async function () {
*/
const canPressKeys = async () => {
try {
await pressKeys(null, { keys: ['shift'] });
await userIntent(null, { name: 'pressKeys', keys: ['shift'] });
} catch ({}) {
return false;
}
Expand Down
9 changes: 6 additions & 3 deletions shared/modules/macos/interaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
const { runScript, renderScript } = require('../../helpers/macos/applescript');
const { parseCodePoints } = require('../../helpers/macos/parseCodePoints');

const pressKeys = /** @type {ATDriverModules.InteractionPressKeys} */ (
async function (websocket, { keys }) {
const userIntent = /** @type {ATDriverModules.InteractionUserIntent} */ (
async function (websocket, { name, keys }) {
if (name !== 'pressKeys') {
throw new Error('unkown user intent');
}
await runScript(renderScript(parseCodePoints(keys)));
return {};
}
);

module.exports = /** @type {ATDriverModules.Interaction} */ ({
'interaction.pressKeys': pressKeys,
'interaction.userIntent': userIntent,
});
5 changes: 3 additions & 2 deletions shared/modules/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,17 @@

/**
* @typedef ATDriverModules.InteractionPressKeysParameters
* @property {"pressKeys"} name
* @property {ATDriverModules.InteractionPressKeysKeyCombination} keys
*/

/**
* @typedef {ATDriverModules.Command<ATDriverModules.InteractionPressKeysParameters, {}>} ATDriverModules.InteractionPressKeys
* @typedef {ATDriverModules.Command<ATDriverModules.InteractionPressKeysParameters, {}>} ATDriverModules.InteractionUserIntent
*/

/**
* @typedef {{
* "interaction.pressKeys": ATDriverModules.InteractionPressKeys
* "interaction.userIntent": ATDriverModules.InteractionUserIntent
* }} ATDriverModules.Interaction
*/

Expand Down
9 changes: 6 additions & 3 deletions shared/modules/win32/interaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,11 @@ const keyboardActionsMap = {

const keycodeMatch = /[\ue000-\ue05d]/;

const pressKeys = /** @type {ATDriverModules.InteractionPressKeys} */ (
(websocket, { keys }) => {
const userIntent = /** @type {ATDriverModules.InteractionUserIntent} */ (
(websocket, { name, keys }) => {
if (name !== 'pressKeys') {
throw new Error('unkown user intent');
}
const robotjsKeys = keys.map(key => {
if (keyboardActionsMap[key]) return keyboardActionsMap[key];
if (keycodeMatch.test(key))
Expand All @@ -93,5 +96,5 @@ const pressKeys = /** @type {ATDriverModules.InteractionPressKeys} */ (
);

module.exports = /** @type {ATDriverModules.Interaction} */ ({
'interaction.pressKeys': pressKeys,
'interaction.userIntent': userIntent,
});
16 changes: 10 additions & 6 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,14 +163,16 @@ suite('at-driver', () => {
});

test('rejects Command messages with omitted "id"', async () => {
websocket.send('{"method": "interaction.pressKeys", "params": {"keys": ["A"]}}');
websocket.send(
'{"method": "interaction.userIntent", "params": {"name": "pressKeys", "keys": ["A"]}}',
);
const message = await Promise.race([whenClosed, nextMessage(websocket)]);

assert.deepEqual(message, {
id: null,
error: 'unknown error',
message:
'Command missing required "id": "{"method": "interaction.pressKeys", "params": {"keys": ["A"]}}".',
'Command missing required "id": "{"method": "interaction.userIntent", "params": {"name": "pressKeys", "keys": ["A"]}}".',
});
});

Expand All @@ -184,8 +186,10 @@ suite('at-driver', () => {
});
});

test('accepts valid "pressKey" Command', async () => {
websocket.send('{"id": 83, "method": "interaction.pressKeys", "params": {"keys": [" "]}}');
test('accepts valid "userIntent" Command', async () => {
websocket.send(
'{"id": 83, "method": "interaction.userIntent", "params": {"name": "pressKeys", "keys": [" "]}}',
);
const message = await Promise.race([whenClosed, nextMessage(websocket)]);

assert.deepEqual(message, {
Expand All @@ -194,9 +198,9 @@ suite('at-driver', () => {
});
});

test('rejects invalid "pressKey" Command', async () => {
test('rejects invalid "userIntent" Command', async () => {
websocket.send(
'{"id": 902, "method": "interaction.pressKeys", "params": {"keys": ["df daf% ?"]}}',
'{"id": 902, "method": "interaction.userIntent", "params": {"name": "pressKeys", "keys": ["df daf% ?"]}}',
);
const message = await Promise.race([whenClosed, nextMessage(websocket)]);

Expand Down

0 comments on commit 96e7b3c

Please sign in to comment.