diff --git a/apps/expo-multi-tv/__tests__/RemoteControlManager.android-test.ts b/apps/expo-multi-tv/__tests__/RemoteControlManager.android-test.ts new file mode 100644 index 0000000..3ba4c2f --- /dev/null +++ b/apps/expo-multi-tv/__tests__/RemoteControlManager.android-test.ts @@ -0,0 +1,48 @@ +import KeyEvent from 'react-native-keyevent'; +import RemoteControlManager from '../../../packages/shared-ui/src/app/remote-control/RemoteControlManager.android'; +import { SupportedKeys } from '../../../packages/shared-ui/src/app/remote-control/SupportedKeys'; + +jest.mock('react-native-keyevent', () => ({ + __esModule: true, + default: { + onKeyDownListener: jest.fn(), + onKeyUpListener: jest.fn(), + removeKeyDownListener: jest.fn(), + removeKeyUpListener: jest.fn(), + }, +})); + +const keyEventMock = KeyEvent as jest.Mocked; +const onKeyDown = keyEventMock.onKeyDownListener.mock.calls[0][0]; +const onKeyUp = keyEventMock.onKeyUpListener.mock.calls[0][0]; + +describe('RemoteControlManager.android', () => { + const listener = jest.fn(); + + beforeAll(() => { + RemoteControlManager.addKeydownListener(listener); + }); + + beforeEach(() => { + listener.mockClear(); + }); + + afterAll(() => { + RemoteControlManager.removeKeydownListener(listener); + }); + + it('emits directional keys on key down', () => { + onKeyDown({ keyCode: 22 }); + + expect(listener).toHaveBeenCalledWith(SupportedKeys.Right); + }); + + it.each([23, 66])('emits Enter for key code %i only on key up', (keyCode) => { + onKeyDown({ keyCode }); + expect(listener).not.toHaveBeenCalled(); + + onKeyUp({ keyCode }); + expect(listener).toHaveBeenCalledTimes(1); + expect(listener).toHaveBeenCalledWith(SupportedKeys.Enter); + }); +}); diff --git a/apps/expo-multi-tv/package.json b/apps/expo-multi-tv/package.json index afe432e..248b33a 100644 --- a/apps/expo-multi-tv/package.json +++ b/apps/expo-multi-tv/package.json @@ -16,7 +16,10 @@ "typecheck": "tsc --noEmit" }, "jest": { - "preset": "jest-expo" + "preset": "jest-expo", + "modulePaths": [ + "/node_modules" + ] }, "dependencies": { "@expo/metro-runtime": "~4.0.0", diff --git a/packages/shared-ui/src/app/remote-control/RemoteControlManager.android.ts b/packages/shared-ui/src/app/remote-control/RemoteControlManager.android.ts index f17ef3d..0961e76 100644 --- a/packages/shared-ui/src/app/remote-control/RemoteControlManager.android.ts +++ b/packages/shared-ui/src/app/remote-control/RemoteControlManager.android.ts @@ -21,14 +21,27 @@ class RemoteControlManager implements RemoteControlManagerInterface { constructor() { KeyEvent.onKeyDownListener(this.handleKeyDown); + KeyEvent.onKeyUpListener(this.handleKeyUp); } private handleKeyDown = (keyEvent: { keyCode: number }): void => { const mappedKey = KEY_CODE_MAPPING[keyEvent.keyCode]; - if (mappedKey) { - console.log(`Key pressed: ${mappedKey}`); - this.eventEmitter.emit('keyDown', mappedKey); + if (!mappedKey || mappedKey === SupportedKeys.Enter) { + return; } + + console.log(`Key pressed: ${mappedKey}`); + this.eventEmitter.emit('keyDown', mappedKey); + }; + + private handleKeyUp = (keyEvent: { keyCode: number }): void => { + const mappedKey = KEY_CODE_MAPPING[keyEvent.keyCode]; + if (mappedKey !== SupportedKeys.Enter) { + return; + } + + console.log(`Key pressed: ${mappedKey}`); + this.eventEmitter.emit('keyDown', mappedKey); }; addKeydownListener = (listener: (event: SupportedKeys) => void): ((event: SupportedKeys) => void) => { @@ -48,7 +61,8 @@ class RemoteControlManager implements RemoteControlManagerInterface { cleanup = (): void => { KeyEvent.removeKeyDownListener(); + KeyEvent.removeKeyUpListener(); }; } -export default new RemoteControlManager(); \ No newline at end of file +export default new RemoteControlManager();