diff --git a/Changelog.md b/Changelog.md
index 4ee6a29ab86b7f99bff24a31d17167ce176af1ff..b285e50b6ca5fd0eeba214a602771ec964ec612a 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -15,6 +15,7 @@ Note: Although this is a minor release, the configuration file changed because t
 * Refactored post interactions on the single post view [#7089](https://github.com/diaspora/diaspora/pull/7089)
 * Extract inline JavaScript [#7113](https://github.com/diaspora/diaspora/pull/7113)
 * Port conversations inbox to backbone.js [#7108](https://github.com/diaspora/diaspora/pull/7108)
+* Refactored stream shortcuts for more flexibility [#7127](https://github.com/diaspora/diaspora/pull/7127)
 
 ## Bug fixes
 * Post comments no longer get collapsed when interacting with a post [#7040](https://github.com/diaspora/diaspora/pull/7040)
diff --git a/app/assets/javascripts/app/helpers/shortcuts.js b/app/assets/javascripts/app/helpers/shortcuts.js
new file mode 100644
index 0000000000000000000000000000000000000000..c8d79f3fad5dff5fe4df32bd580661e2bd1e6531
--- /dev/null
+++ b/app/assets/javascripts/app/helpers/shortcuts.js
@@ -0,0 +1,31 @@
+// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
+(function() {
+  app.helpers.Shortcuts = function(evtname, fn) {
+    var textAcceptingInputTypes = [
+      "color",
+      "date",
+      "datetime",
+      "datetime-local",
+      "email",
+      "month",
+      "number",
+      "password",
+      "range",
+      "search",
+      "select",
+      "text",
+      "textarea",
+      "time",
+      "url",
+      "week"
+    ];
+
+    $("body").on(evtname, function(event) {
+      // make sure that the user is not typing in an input field
+      if (textAcceptingInputTypes.indexOf(event.target.type) === -1) {
+        fn(event);
+      }
+    });
+  };
+})();
+// @license-end
diff --git a/app/assets/javascripts/app/views/stream/shortcuts.js b/app/assets/javascripts/app/views/stream/shortcuts.js
index 56d9df05d7bf016da56335f5809c8b3a96f72919..a19a1fa060ae5a2fd56bd20666bb1e0c4b857cfb 100644
--- a/app/assets/javascripts/app/views/stream/shortcuts.js
+++ b/app/assets/javascripts/app/views/stream/shortcuts.js
@@ -3,18 +3,12 @@
 app.views.StreamShortcuts = Backbone.View.extend({
   _headerSize: 60,
 
-  events: {
-    "keydown": "_onHotkeyDown",
-    "keyup": "_onHotkeyUp"
+  initialize: function() {
+    app.helpers.Shortcuts("keydown", this._onHotkeyDown.bind(this));
+    app.helpers.Shortcuts("keyup", this._onHotkeyUp.bind(this));
   },
 
   _onHotkeyDown: function(event) {
-    //make sure that the user is not typing in an input field
-    var textAcceptingInputTypes = ["textarea", "select", "text", "password", "number", "email", "url", "range", "date", "month", "week", "time", "datetime", "datetime-local", "search", "color"];
-    if(jQuery.inArray(event.target.type, textAcceptingInputTypes) > -1){
-      return;
-    }
-
     // trigger the events based on what key was pressed
     switch (String.fromCharCode( event.which ).toLowerCase()) {
       case "j":
@@ -28,12 +22,6 @@ app.views.StreamShortcuts = Backbone.View.extend({
   },
 
   _onHotkeyUp: function(event) {
-    //make sure that the user is not typing in an input field
-    var textAcceptingInputTypes = ["textarea", "select", "text", "password", "number", "email", "url", "range", "date", "month", "week", "time", "datetime", "datetime-local", "search", "color"];
-    if(jQuery.inArray(event.target.type, textAcceptingInputTypes) > -1){
-      return;
-    }
-
     // trigger the events based on what key was pressed
     switch (String.fromCharCode( event.which ).toLowerCase()) {
       case "c":
diff --git a/spec/javascripts/app/helpers/shortcuts_spec.js b/spec/javascripts/app/helpers/shortcuts_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..b738d50c4b5790afb71d637816d071d1c58e7604
--- /dev/null
+++ b/spec/javascripts/app/helpers/shortcuts_spec.js
@@ -0,0 +1,17 @@
+describe("app.helpers.Shortcuts", function() {
+  it("calls the function when the event has been fired outside of an input field", function() {
+    var spy = jasmine.createSpy();
+    spec.content().append("<div class='hotkey-div'></div>");
+    app.helpers.Shortcuts("keydown", spy);
+    $(".hotkey-div").trigger("keydown");
+    expect(spy).toHaveBeenCalled();
+  });
+
+  it("doesn't call the function when the event has been fired in an input field", function() {
+    var spy = jasmine.createSpy();
+    spec.content().append("<textarea class='hotkey-textarea'></textarea>");
+    app.helpers.Shortcuts("keydown", spy);
+    $(".hotkey-textarea").trigger("keydown");
+    expect(spy).not.toHaveBeenCalled();
+  });
+});
diff --git a/spec/javascripts/app/views/stream/shortcuts_spec.js b/spec/javascripts/app/views/stream/shortcuts_spec.js
index 3933c63244f465c19a3c1eadecf7eaa500ca349f..ba58b54c13363f4751a12c472925a3e254912dbe 100644
--- a/spec/javascripts/app/views/stream/shortcuts_spec.js
+++ b/spec/javascripts/app/views/stream/shortcuts_spec.js
@@ -13,131 +13,95 @@ describe("app.views.StreamShortcuts", function () {
     expect(spec.content().find("div.stream-element.loaded").length).toBe(2);
   });
 
-  describe("pressing 'j'", function(){
-    it("should call 'gotoNext' if not pressed in an input field", function(){
-      spyOn(this.view, 'gotoNext');
-      var e = $.Event("keydown", { which: Keycodes.J, target: {type: "div"} });
-      this.view._onHotkeyDown(e);
-      expect(this.view.gotoNext).toHaveBeenCalled();
-    });
-
-    it("'gotoNext' should call 'selectPost'", function(){
-      spyOn(this.view, 'selectPost');
-      this.view.gotoNext();
-      expect(this.view.selectPost).toHaveBeenCalled();
-    });
-
-    it("shouldn't do anything if the user types in an input field", function(){
-      spyOn(this.view, 'gotoNext');
-      spyOn(this.view, 'selectPost');
-      var e = $.Event("keydown", { which: Keycodes.J, target: {type: "textarea"} });
-      this.view._onHotkeyDown(e);
-      expect(this.view.gotoNext).not.toHaveBeenCalled();
-      expect(this.view.selectPost).not.toHaveBeenCalled();
+  describe("initialize", function() {
+    it("setups the shortcuts", function() {
+      spyOn(app.helpers, "Shortcuts").and.callThrough();
+      spyOn(app.views.StreamShortcuts.prototype, "_onHotkeyDown");
+      spyOn(app.views.StreamShortcuts.prototype, "_onHotkeyUp");
+      this.view = new app.views.StreamShortcuts({el: $(document)});
+      expect(app.helpers.Shortcuts.calls.count()).toBe(2);
+
+      $("body").trigger($.Event("keydown", {which: Keycodes.J, target: {type: "textarea"}}));
+      $("body").trigger($.Event("keyup", {which: Keycodes.J, target: {type: "textarea"}}));
+      expect(app.views.StreamShortcuts.prototype._onHotkeyDown).not.toHaveBeenCalled();
+      expect(app.views.StreamShortcuts.prototype._onHotkeyUp).not.toHaveBeenCalled();
+
+      var e = $.Event("keydown", {which: Keycodes.J, target: {type: "div"}});
+      $("body").trigger(e);
+      expect(app.views.StreamShortcuts.prototype._onHotkeyDown).toHaveBeenCalledWith(e);
+
+      e = $.Event("keyup", {which: Keycodes.J, target: {type: "div"}});
+      $("body").trigger(e);
+      expect(app.views.StreamShortcuts.prototype._onHotkeyUp).toHaveBeenCalledWith(e);
     });
   });
 
-  describe("pressing 'k'", function(){
-    it("should call 'gotoPrev' if not pressed in an input field", function(){
-      spyOn(this.view, 'gotoPrev');
-      var e = $.Event("keydown", { which: Keycodes.K, target: {type: "div"} });
+  describe("_onHotkeyDown", function() {
+    it("calls goToNext when the user pressed 'J'", function() {
+      spyOn(this.view, "gotoNext");
+      var e = $.Event("keydown", {which: Keycodes.J, target: {type: "div"}});
       this.view._onHotkeyDown(e);
-      expect(this.view.gotoPrev).toHaveBeenCalled();
-    });
-
-    it("'gotoPrev' should call 'selectPost'", function(){
-      spyOn(this.view, 'selectPost');
-      this.view.gotoPrev();
-      expect(this.view.selectPost).toHaveBeenCalled();
+      expect(this.view.gotoNext).toHaveBeenCalled();
     });
 
-    it("shouldn't do anything if the user types in an input field", function(){
-      spyOn(this.view, 'gotoPrev');
-      spyOn(this.view, 'selectPost');
-      var e = $.Event("keydown", { which: Keycodes.K, target: {type: "textarea"} });
+    it("calls gotoPrev when the user pressed 'K'", function() {
+      spyOn(this.view, "gotoPrev");
+      var e = $.Event("keydown", {which: Keycodes.K, target: {type: "div"}});
       this.view._onHotkeyDown(e);
-      expect(this.view.gotoPrev).not.toHaveBeenCalled();
-      expect(this.view.selectPost).not.toHaveBeenCalled();
+      expect(this.view.gotoPrev).toHaveBeenCalled();
     });
   });
 
-  describe("pressing 'c'", function(){
-    it("should click on the comment-button if not pressed in an input field", function(){
-      spyOn(this.view, 'commentSelected');
-      var e = $.Event("keyup", { which: Keycodes.C, target: {type: "div"} });
+  describe("_onHotkeyUp", function() {
+    it("calls commentSelected when the user pressed 'C'", function() {
+      spyOn(this.view, "commentSelected");
+      var e = $.Event("keyup", {which: Keycodes.C, target: {type: "div"}});
       this.view._onHotkeyUp(e);
       expect(this.view.commentSelected).toHaveBeenCalled();
     });
 
-    it("shouldn't do anything if the user types in an input field", function(){
-      spyOn(this.view, 'commentSelected');
-      var e = $.Event("keyup", { which: Keycodes.C, target: {type: "textarea"} });
-      this.view._onHotkeyUp(e);
-      expect(this.view.commentSelected).not.toHaveBeenCalled();
-    });
-  });
-
-  describe("pressing 'l'", function(){
-    it("should click on the like-button if not pressed in an input field", function(){
-      spyOn(this.view, 'likeSelected');
-      var e = $.Event("keyup", { which: Keycodes.L, target: {type: "div"} });
+    it("calls likeSelected when the user pressed 'L'", function() {
+      spyOn(this.view, "likeSelected");
+      var e = $.Event("keyup", {which: Keycodes.L, target: {type: "div"}});
       this.view._onHotkeyUp(e);
       expect(this.view.likeSelected).toHaveBeenCalled();
     });
 
-    it("shouldn't do anything if the user types in an input field", function(){
-      spyOn(this.view, 'likeSelected');
-      var e = $.Event("keyup", { which: Keycodes.L, target: {type: "textarea"} });
+    it("calls expandSelected when the user pressed 'M'", function() {
+      spyOn(this.view, "expandSelected");
+      var e = $.Event("keyup", {which: Keycodes.M, target: {type: "div"}});
       this.view._onHotkeyUp(e);
-      expect(this.view.likeSelected).not.toHaveBeenCalled();
+      expect(this.view.expandSelected).toHaveBeenCalled();
     });
-  });
 
-  describe("pressing 'r'", function(){
-    it("should click on the reshare-button if not pressed in an input field", function(){
-      spyOn(this.view, 'reshareSelected');
-      var e = $.Event("keyup", { which: Keycodes.R, target: {type: "div"} });
+    it("calls openFirstLinkSelected when the user pressed 'O'", function() {
+      spyOn(this.view, "openFirstLinkSelected");
+      var e = $.Event("keyup", {which: Keycodes.O, target: {type: "div"}});
       this.view._onHotkeyUp(e);
-      expect(this.view.reshareSelected).toHaveBeenCalled();
+      expect(this.view.openFirstLinkSelected).toHaveBeenCalled();
     });
 
-    it("shouldn't do anything if the user types in an input field", function(){
-      spyOn(this.view, 'reshareSelected');
-      var e = $.Event("keyup", { which: Keycodes.R, target: {type: "textarea"} });
+    it("calls reshareSelected when the user pressed 'R'", function() {
+      spyOn(this.view, "reshareSelected");
+      var e = $.Event("keyup", {which: Keycodes.R, target: {type: "div"}});
       this.view._onHotkeyUp(e);
-      expect(this.view.reshareSelected).not.toHaveBeenCalled();
+      expect(this.view.reshareSelected).toHaveBeenCalled();
     });
   });
 
-  describe("pressing 'm'", function(){
-    it("should click on the more-button if not pressed in an input field", function(){
-      spyOn(this.view, 'expandSelected');
-      var e = $.Event("keyup", { which: Keycodes.M, target: {type: "div"} });
-      this.view._onHotkeyUp(e);
-      expect(this.view.expandSelected).toHaveBeenCalled();
-    });
-
-    it("shouldn't do anything if the user types in an input field", function(){
-      spyOn(this.view, 'expandSelected');
-      var e = $.Event("keyup", { which: Keycodes.M, target: {type: "textarea"} });
-      this.view._onHotkeyUp(e);
-      expect(this.view.expandSelected).not.toHaveBeenCalled();
+  describe("gotoNext", function() {
+    it("calls selectPost", function() {
+      spyOn(this.view, "selectPost");
+      this.view.gotoNext();
+      expect(this.view.selectPost).toHaveBeenCalled();
     });
   });
 
-  describe("pressing 'o'", function(){
-    it("should click on the more-button if not pressed in an input field", function(){
-      spyOn(this.view, 'openFirstLinkSelected');
-      var e = $.Event("keyup", { which: Keycodes.O, target: {type: "div"} });
-      this.view._onHotkeyUp(e);
-      expect(this.view.openFirstLinkSelected).toHaveBeenCalled();
-    });
-
-    it("shouldn't do anything if the user types in an input field", function(){
-      spyOn(this.view, 'openFirstLinkSelected');
-      var e = $.Event("keyup", { which: Keycodes.O, target: {type: "textarea"} });
-      this.view._onHotkeyUp(e);
-      expect(this.view.openFirstLinkSelected).not.toHaveBeenCalled();
+  describe("gotoPrev", function() {
+    it("calls selectPost", function() {
+      spyOn(this.view, "selectPost");
+      this.view.gotoPrev();
+      expect(this.view.selectPost).toHaveBeenCalled();
     });
   });
 });