Repository: FormidableLabs/spectacle (ts)

Issue:
Keyboard controls don't work on Linux
Keyboard controls only work for Windows and Mac.
I am using an Ubuntu and when I start my presentation and press one of the following combinations nothing happens.
`Alt` + `O`
`Alt` + `P`
`Alt` + `F`


Pull request:
Add hotkeys support on linux.
### Description

Keyboard controls only work for Windows and Mac.
I am using an Ubuntu and when I start my presentation and press one of the following combinations nothing happens.
`Alt` + `O`
`Alt` + `P`
`Alt` + `F`

Fixes #904 

#### Type of Change

- [X] Bug fix (non-breaking change which fixes an issue)

### How Has This Been Tested?

`yarn`
`yarn check-ci`
`yarn test`
`yarn build` + tested it locally
`yarn format`



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5f0c685..533aa95 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Changelog
 
+## Unreleased
+
+- Enhance hot key support for Linux users.
+  [#905](https://github.com/FormidableLabs/spectacle/pull/905)
+
 ## 6.0.3 (05-11-2020)
 
 - Fix keyboard toggles for both MacOS and Windows.
diff --git a/examples/one-page.html b/examples/one-page.html
index 0f168be..96a9932 100644
--- a/examples/one-page.html
+++ b/examples/one-page.html
@@ -124,7 +124,7 @@
           </${Slide}>
           <${Slide}>
             <${FlexBox} height="100%" flexDirection="column">
-              <${Heading} margin="0px" fontSize="150px">SPECTACLE</${Heading}>
+              <${Heading} margin="0px" fontSize="150px">✨<i>Spectacle</i> ✨</${Heading}>
               <${Heading} margin="0px" fontSize="h2">A ReactJS Presentation Library</${Heading}>
               <${Heading} margin="0px 32px" color="primary" fontSize="h3">Where you can write your decks in JSX, Markdown, or MDX!</${Heading}>
             </${FlexBox}>
diff --git a/src/hooks/use-keyboard-controls.js b/src/hooks/use-keyboard-controls.js
index e324923..7192ada 100644
--- a/src/hooks/use-keyboard-controls.js
+++ b/src/hooks/use-keyboard-controls.js
@@ -1,7 +1,7 @@
 import React from 'react';
 import debounce from '../utils/debounce';
 import { useToggleFullScreen } from './use-full-screen';
-import { isWindows, isMacOS } from '../utils/detect-platform';
+import { isWindows, isMacOS, isLinux } from '../utils/detect-platform';
 
 const useKeyboardControls = ({
   keyboardControls = 'arrows',
@@ -52,7 +52,7 @@ const useKeyboardControls = ({
             default:
               null;
           }
-        } else if (e.altKey && isWindows()) {
+        } else if (e.altKey && (isWindows() || isLinux())) {
           const key = e.key.toUpperCase();
           switch (key) {
             case 'O':
diff --git a/src/utils/detect-platform.js b/src/utils/detect-platform.js
index 95e45c6..46c87fd 100644
--- a/src/utils/detect-platform.js
+++ b/src/utils/detect-platform.js
@@ -3,3 +3,5 @@ export const isWindows = () =>
 
 export const isMacOS = () =>
   navigator.platform.toLowerCase().includes('macintel');
+
+export const isLinux = () => navigator.platform.toLowerCase().includes('linux');


Test patch:
diff --git a/src/hooks/use-keyboard-controls.test.js b/src/hooks/use-keyboard-controls.test.js
index aaa80be..1234bba 100644
--- a/src/hooks/use-keyboard-controls.test.js
+++ b/src/hooks/use-keyboard-controls.test.js
@@ -102,6 +102,7 @@ describe('useKeyboardControls', () => {
   });
   describe('it toggles view modes on mac', () => {
     beforeEach(() => {
+      detectPlatform.isLinux = jest.fn().mockReturnValue(false);
       detectPlatform.isMacOS = jest.fn().mockReturnValue(true);
       detectPlatform.isWindows = jest.fn().mockReturnValue(false);
     });
@@ -166,6 +167,7 @@ describe('useKeyboardControls', () => {
   });
   describe('it toggles view modes on windows', () => {
     beforeEach(() => {
+      detectPlatform.isLinux = jest.fn().mockReturnValue(false);
       detectPlatform.isMacOS = jest.fn().mockReturnValue(false);
       detectPlatform.isWindows = jest.fn().mockReturnValue(true);
     });
@@ -228,4 +230,69 @@ describe('useKeyboardControls', () => {
       expect(toggleFullScreenMock).toBeCalled();
     });
   });
+  describe('it toggles view modes on Linux', () => {
+    beforeEach(() => {
+      detectPlatform.isLinux = jest.fn().mockReturnValue(true);
+      detectPlatform.isMacOS = jest.fn().mockReturnValue(false);
+      detectPlatform.isWindows = jest.fn().mockReturnValue(false);
+    });
+    it('calls toggleMode with overViewMode when Alt + O is pressed', () => {
+      const map = {};
+      window.addEventListener = jest.fn((event, callback) => {
+        map[event] = callback;
+      });
+      const TestComponent = () => {
+        useKeboardControls({
+          keyboardControls: 'arrows',
+          navigateToNext: navigateToNextMock,
+          navigateToPrevious: navigateToPrevMock,
+          toggleMode: toggleModeMock
+        });
+        return <div data-testid="target">Target</div>;
+      };
+      mount(<TestComponent />);
+      map.keydown({ key: 'O', altKey: true });
+      expect(toggleModeMock).toBeCalledWith('overviewMode');
+    });
+    it('calls toggleMode with presenterMode when Alt + P is pressed', () => {
+      const map = {};
+      window.addEventListener = jest.fn((event, callback) => {
+        map[event] = callback;
+      });
+      const TestComponent = () => {
+        useKeboardControls({
+          keyboardControls: 'arrows',
+          navigateToNext: navigateToNextMock,
+          navigateToPrevious: navigateToPrevMock,
+          toggleMode: toggleModeMock
+        });
+        return <div data-testid="target">Target</div>;
+      };
+      mount(<TestComponent />);
+      map.keydown({ key: 'P', altKey: true });
+      expect(toggleModeMock).toBeCalledWith('presenterMode');
+    });
+    it('calls toggleFullScreenMode when Alt + F is pressed', () => {
+      const toggleFullScreenMock = jest.fn();
+      toggleFullScreen.useToggleFullScreen = jest
+        .fn()
+        .mockReturnValue(toggleFullScreenMock);
+      const map = {};
+      window.addEventListener = jest.fn((event, callback) => {
+        map[event] = callback;
+      });
+      const TestComponent = () => {
+        useKeboardControls({
+          keyboardControls: 'arrows',
+          navigateToNext: navigateToNextMock,
+          navigateToPrevious: navigateToPrevMock,
+          toggleMode: toggleModeMock
+        });
+        return <div data-testid="target">Target</div>;
+      };
+      mount(<TestComponent />);
+      map.keydown({ key: 'F', altKey: true });
+      expect(toggleFullScreenMock).toBeCalled();
+    });
+  });
 });