diff --git a/app/App.js b/app/App.js
index f9561267c9..76bec49a64 100644
--- a/app/App.js
+++ b/app/App.js
@@ -36,6 +36,7 @@ import SearchBoxContainer from './containers/SearchBoxContainer';
import IpcContainer from './containers/IpcContainer';
import SoundContainer from './containers/SoundContainer';
import ToastContainer from './containers/ToastContainer';
+import ShortcutsContainer from './containers/ShortcutsContainer';
import ui from 'nuclear-ui';
import PlayerControls from './components/PlayerControls';
@@ -270,6 +271,7 @@ class App extends React.Component {
{this.renderRightPanel(settings)}
+
{this.renderFooter(settings)}
diff --git a/app/containers/ShortcutsContainer/index.js b/app/containers/ShortcutsContainer/index.js
new file mode 100644
index 0000000000..78bb1bafb7
--- /dev/null
+++ b/app/containers/ShortcutsContainer/index.js
@@ -0,0 +1,134 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import Sound from 'react-sound';
+import * as Mousetrap from 'mousetrap';
+
+import * as PlayerActions from '../../actions/player';
+import * as QueueActions from '../../actions/queue';
+
+const VOLUME_ITERATION = 5;
+const SEEK_ITERATION = 100;
+
+class Shortcuts extends React.Component {
+ handleSpaceBar() {
+ const { queue, player, actions } = this.props;
+
+ if (queue.queueItems.length > 0) {
+ if(player.playbackStatus === Sound.status.PLAYING) {
+ actions.pausePlayback();
+ } else {
+ actions.startPlayback();
+ }
+ }
+ }
+
+ playCurrentSong() {
+ const { queue, player, actions } = this.props;
+
+ if (
+ queue.queueItems.length > 0 &&
+ player.playbackStatus !== Sound.status.PLAYING
+ ) {
+ actions.startPlayback();
+ }
+ }
+
+ increaseVolume() {
+ const { player, actions } = this.props;
+
+ if (player.volume < 100) {
+ actions.updateVolume(player.volume + VOLUME_ITERATION);
+ }
+ }
+
+ decreaseVolume() {
+ const { player, actions } = this.props;
+
+ if (player.volume > 0) {
+ actions.updateVolume(player.volume - VOLUME_ITERATION);
+ }
+ }
+
+ increaseSeek() {
+ const { player, actions } = this.props;
+
+ if (player.playbackProgress < 100) {
+ actions.updateSeek(player.seek + SEEK_ITERATION);
+ }
+ }
+
+ decreaseSeek() {
+ const { player, actions} = this.props;
+
+ if (player.playbackProgress > 0) {
+ actions.updateSeek(player.seek - SEEK_ITERATION);
+ }
+ }
+
+ constructor(props) {
+ super(props);
+ this.handleSpaceBar = this.handleSpaceBar.bind(this);
+ this.increaseVolume = this.increaseVolume.bind(this);
+ this.decreaseVolume = this.decreaseVolume.bind(this);
+ this.playCurrentSong = this.playCurrentSong.bind(this);
+ this.increaseSeek = this.increaseSeek.bind(this);
+ this.decreaseSeek = this.decreaseSeek.bind(this);
+ }
+
+ componentDidMount() {
+ Mousetrap.bind('space', this.handleSpaceBar);
+ Mousetrap.bind('enter', this.playCurrentSong);
+ Mousetrap.bind('up', this.increaseVolume);
+ Mousetrap.bind('down', this.decreaseVolume);
+ Mousetrap.bind('left', this.decreaseSeek);
+ Mousetrap.bind('right', this.increaseSeek);
+ Mousetrap.bind(['ctrl+right', 'command+right'], this.props.actions.nextSong);
+ Mousetrap.bind(['ctrl+left', 'command+left'], this.props.actions.previousSong);
+ Mousetrap.bind(['ctrl+top', 'command+top'], this.props.actions.unmute);
+ Mousetrap.bind(['ctrl+down', 'command+down'], this.props.actions.mute);
+ }
+
+ componentWillUnmount() {
+ Mousetrap.unbind([
+ 'space',
+ 'left',
+ 'right',
+ 'up',
+ 'down',
+ 'right',
+ 'left',
+ 'ctrl+right',
+ 'command+right',
+ 'ctrl+left',
+ 'command+left',
+ 'ctrl+top',
+ 'command+top',
+ 'ctrl+down',
+ 'command+down'
+ ]);
+ }
+
+ shouldComponentUpdate() {
+ return false;
+ }
+
+ render() {
+ return null;
+ }
+}
+
+function mapStateToProps({ player, queue }) {
+ return {
+ player,
+ queue
+ };
+}
+
+function mapDispatchToProps(dispatch) {
+ return {
+ actions: bindActionCreators(Object.assign({}, PlayerActions, QueueActions), dispatch)
+ };
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(Shortcuts);
diff --git a/package.json b/package.json
index 1a3a401357..26dcdb3c5b 100644
--- a/package.json
+++ b/package.json
@@ -52,6 +52,7 @@
"get-artist-title": "^1.1.1",
"md5": "^2.2.1",
"moment": "^2.20.1",
+ "mousetrap": "^1.6.2",
"nuclear-core": "0.0.4",
"nuclear-ui": "0.0.6",
"numeral": "^2.0.6",