Skip to content

Commit

Permalink
Detect arrow keys when pressed together with meta key
Browse files Browse the repository at this point in the history
Related to #512.
  • Loading branch information
vadimdemedes committed Mar 28, 2023
1 parent 26b8364 commit 8180c1c
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 20 deletions.
33 changes: 13 additions & 20 deletions src/hooks/use-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,14 @@ const useInput = (inputHandler: Handler, options: Options = {}) => {
const handleData = (data: Buffer) => {
let input = String(data);

const meta =
input.startsWith('\u001B\u001B') || // Meta + arrow keys
(input.startsWith('\u001B') && !input.startsWith('\u001B[')); // Meta + character

if (meta && input.length > 1) {
input = input.slice(1);
}

const key = {
upArrow: input === '\u001B[A',
downArrow: input === '\u001B[B',
Expand All @@ -147,11 +155,12 @@ const useInput = (inputHandler: Handler, options: Options = {}) => {
return: input === '\r',
escape: input === '\u001B',
ctrl: false,
shift: false,
// Shift + Tab
shift: input === '\u001B[Z',
tab: input === '\t' || input === '\u001B[Z',
backspace: input === '\u0008',
delete: input === '\u007F' || input === '\u001B[3~',
meta: false
meta
};

// Copied from `keypress` module
Expand All @@ -161,30 +170,14 @@ const useInput = (inputHandler: Handler, options: Options = {}) => {
// eslint-disable-next-line unicorn/prefer-code-point
input.charCodeAt(0) + 'a'.charCodeAt(0) - 1
);
key.ctrl = true;
}

if (
input.startsWith('\u001B') &&
!key.upArrow &&
!key.downArrow &&
!key.leftArrow &&
!key.rightArrow &&
!key.pageUp &&
!key.pageDown
) {
input = input.slice(1);
key.meta = true;
key.ctrl = true;
}

const isLatinUppercase = input >= 'A' && input <= 'Z';
const isCyrillicUppercase = input >= 'А' && input <= 'Я';
if (input.length === 1 && (isLatinUppercase || isCyrillicUppercase)) {
key.shift = true;
}

// Shift+Tab
if (key.tab && input === '[Z') {
if (input.length === 1 && (isLatinUppercase || isCyrillicUppercase)) {
key.shift = true;
}

Expand Down
20 changes: 20 additions & 0 deletions test/fixtures/use-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,26 @@ function UserInput({test}: {test: string | undefined}) {
return;
}

if (test === 'upArrowMeta' && key.upArrow && key.meta) {
exit();
return;
}

if (test === 'downArrowMeta' && key.downArrow && key.meta) {
exit();
return;
}

if (test === 'leftArrowMeta' && key.leftArrow && key.meta) {
exit();
return;
}

if (test === 'rightArrowMeta' && key.rightArrow && key.meta) {
exit();
return;
}

if (test === 'pageDown' && key.pageDown && !key.meta) {
exit();
return;
Expand Down
28 changes: 28 additions & 0 deletions test/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,34 @@ test.serial('useInput - handle right arrow', async t => {
t.true(ps.output.includes('exited'));
});

test.serial('useInput - handle meta + up arrow', async t => {
const ps = term('use-input', ['upArrowMeta']);
ps.write('\u001B\u001B[A');
await ps.waitForExit();
t.true(ps.output.includes('exited'));
});

test.serial('useInput - handle meta + down arrow', async t => {
const ps = term('use-input', ['downArrowMeta']);
ps.write('\u001B\u001B[B');
await ps.waitForExit();
t.true(ps.output.includes('exited'));
});

test.serial('useInput - handle meta + left arrow', async t => {
const ps = term('use-input', ['leftArrowMeta']);
ps.write('\u001B\u001B[D');
await ps.waitForExit();
t.true(ps.output.includes('exited'));
});

test.serial('useInput - handle meta + right arrow', async t => {
const ps = term('use-input', ['rightArrowMeta']);
ps.write('\u001B\u001B[C');
await ps.waitForExit();
t.true(ps.output.includes('exited'));
});

test.serial('useInput - handle page down', async t => {
const ps = term('use-input', ['pageDown']);
ps.write('\u001B[6~');
Expand Down

0 comments on commit 8180c1c

Please sign in to comment.