175

My users would like to be able to hit Ctrl+S to save a form. Is there a good cross-browser way of capturing the Ctrl+S key combination and submit my form?

App is built on Drupal, so jQuery is available.

Fabrizio
  • 7,603
  • 6
  • 44
  • 104
ceejayoz
  • 176,543
  • 40
  • 303
  • 368

17 Answers17

271

This works for me (using jquery) to overload Ctrl+S, Ctrl+F and Ctrl+G:

$(window).bind('keydown', function(event) {
    if (event.ctrlKey || event.metaKey) {
        switch (String.fromCharCode(event.which).toLowerCase()) {
        case 's':
            event.preventDefault();
            alert('ctrl-s');
            break;
        case 'f':
            event.preventDefault();
            alert('ctrl-f');
            break;
        case 'g':
            event.preventDefault();
            alert('ctrl-g');
            break;
        }
    }
});
Fabrizio
  • 7,603
  • 6
  • 44
  • 104
Danny Ruijters
  • 3,411
  • 2
  • 18
  • 21
  • 8
    This is the only answer that worked for me in all the browsers I tested, including Chrome Version 28.0.1500.71 – T. Brian Jones Jul 22 '13 at 16:49
  • 34
    Doable with pure JS if you use `window.addEventListener(` instead of `$(window).bind(` –  Oct 20 '13 at 22:44
  • On FF 27.0.1 this both alerts and opens the Save page dialog, accepted answer does not. – NateS Mar 22 '14 at 12:36
  • 2
    @NatesS if you remove the alert it does not open the save dialog. It is caused due to alert. Works fine for me in all browsers. Nice workaround. – CrazyNooB Apr 08 '14 at 09:00
  • This was the only one that worked for me on IE11, and hence in the windows store app webview. I did find an odd issue where CTRL+O or CTRL+P don't seem to pay attention to event.preventDefault. In these cases, the letter makes it through after the shortcut is handled – roryok Apr 23 '14 at 16:12
  • 2
    Worked for me. Please make accept this answer than the above one. – pavanw3b Jan 08 '15 at 08:37
  • Currently better to use keypress instead of keydown – Gabriele F. Mar 31 '16 at 16:01
  • How would you capture Ctrl-Shift-S or other more complex combinations with this? I tried adding an `else if ((event.ctrlKey || event.metaKey) && event.shiftKey ) { switch (String.fromCharCode(event.which)) { ` after the initial if statement with no luck – Fireflight Jul 09 '19 at 16:16
  • 1
    @Fireflight: an `else if` will not work because the original `if` statement will already be evaluated as true. You will have to put your code before the original `if` statement, turning the original in an `else if`. – Danny Ruijters Jul 11 '19 at 08:10
125
$(window).keypress(function(event) {
    if (!(event.which == 115 && event.ctrlKey) && !(event.which == 19)) return true;
    alert("Ctrl-S pressed");
    event.preventDefault();
    return false;
});

Key codes can differ between browsers, so you may need to check for more than just 115.

balupton
  • 47,113
  • 32
  • 131
  • 182
Jim
  • 72,985
  • 14
  • 101
  • 108
34

You could use a shortcut library to handle the browser specific stuff.

shortcut.add("Ctrl+S",function() {
    alert("Hi there!");
});
Aliaksandr Sushkevich
  • 11,550
  • 7
  • 37
  • 44
EndangeredMassa
  • 17,208
  • 8
  • 55
  • 79
  • 7
    This has been converted to a jQuery plugin, forked and reforked, and now supports 1.6.x: https://github.com/ricardovaleriano/jquery.hotkeys – Félix Saparelli Jul 26 '11 at 04:08
  • 12
    For fellow Googlers, the updated URL for the jQuery plugin is: https://github.com/jeresig/jquery.hotkeys – bgs264 Jul 09 '12 at 15:57
30

This jQuery solution works for me in Chrome and Firefox, for both Ctrl+S and Cmd+S.

$(document).keydown(function(e) {

    var key = undefined;
    var possible = [ e.key, e.keyIdentifier, e.keyCode, e.which ];

    while (key === undefined && possible.length > 0)
    {
        key = possible.pop();
    }

    if (key && (key == '115' || key == '83' ) && (e.ctrlKey || e.metaKey) && !(e.altKey))
    {
        e.preventDefault();
        alert("Ctrl-s pressed");
        return false;
    }
    return true;
}); 
Fabrizio
  • 7,603
  • 6
  • 44
  • 104
Alan Bellows
  • 1,781
  • 1
  • 14
  • 21
29

This one worked for me on Chrome... for some reason event.which returns a capital S (83) for me, not sure why (regardless of the caps lock state) so I used fromCharCode and toLowerCase just to be on the safe side

$(document).keydown(function(event) {

    //19 for Mac Command+S
    if (!( String.fromCharCode(event.which).toLowerCase() == 's' && event.ctrlKey) && !(event.which == 19)) return true;

    alert("Ctrl-s pressed");

    event.preventDefault();
    return false;
});

If anyone knows why I get 83 and not 115, I will be happy to hear, also if anyone tests this on other browsers I'll be happy to hear if it works or not

Aliaksandr Sushkevich
  • 11,550
  • 7
  • 37
  • 44
Eran Medan
  • 44,555
  • 61
  • 184
  • 276
  • I have this same problem with chrome. Such a pain! – qodeninja Jan 23 '13 at 17:56
  • p.s. now that I look at it, I think that the preventDefault is redundant as return false triggers it (And stopPropagation) but not sure it matters much for the question – Eran Medan Apr 22 '13 at 13:39
7

I combined a few options to support FireFox, IE and Chrome. I've also updated it to better support mac

// simply disables save event for chrome
$(window).keypress(function (event) {
    if (!(event.which == 115 && (navigator.platform.match("Mac") ? event.metaKey : event.ctrlKey)) && !(event.which == 19)) return true;
    event.preventDefault();
    return false;
});

// used to process the cmd+s and ctrl+s events
$(document).keydown(function (event) {
     if (event.which == 83 && (navigator.platform.match("Mac") ? event.metaKey : event.ctrlKey)) {
        event.preventDefault();
        save(event);
        return false;
     }
});
uadrive
  • 1,249
  • 14
  • 23
6

$(document).keydown(function(e) {
    if ((e.key == 's' || e.key == 'S' ) && (e.ctrlKey || e.metaKey))
    {
        e.preventDefault();
        alert("Ctrl-s pressed");
        return false;
    }
    return true;
}); 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Try pressing ctrl+s somewhere.

This is an up-to-date version of @AlanBellows's answer, replacing which with key. It also works even with Chrome's capital key glitch (where if you press Ctrl+S it sends capital S instead of s). Works in all modern browsers.

Fabrizio
  • 7,603
  • 6
  • 44
  • 104
Cannicide
  • 4,360
  • 3
  • 22
  • 42
5

I would like Web applications to not override my default shortcut keys, honestly. Ctrl+S already does something in browsers. Having that change abruptly depending on the site I'm viewing is disruptive and frustrating, not to mention often buggy. I've had sites hijack Ctrl+Tab because it looked the same as Ctrl+I, both ruining my work on the site and preventing me from switching tabs as usual.

If you want shortcut keys, use the accesskey attribute. Please don't break existing browser functionality.

Fabrizio
  • 7,603
  • 6
  • 44
  • 104
Eevee
  • 47,412
  • 11
  • 95
  • 127
  • 2
    I agree, entirely, but unfortunately I'm the peon implementing, not the decision maker. – ceejayoz Sep 18 '08 at 21:55
  • 26
    True, but CTRL+S is not an often-used feature. I doubt people would miss it, especially if it means you can save your file in your webapp. – EndangeredMassa Nov 05 '08 at 18:09
  • 17
    I normally agree with you, but the only time I _ever_ use ctrl-s in a browser is when I forget I'm using a webapp and expect the shortcut to do something useful. I'm normally disappointed. Gmail saves your email when you hit ctrl-s, although you'd never notice because when it just does what you expect it to, and what every desktop app does, you don't really notice. You DO notice when it thinks you want to save gmail as HTML, and it's annoying. – Carson Myers Jan 15 '12 at 02:54
  • 4
    This really depends on the application. I'm building a terminal emulator web app and overriding ctrl+c seems practical if not necessary. – Brack Jul 31 '12 at 13:52
  • The need to actually save an HTML page is fairly slim, I find myself doing this never. However as others have said, the browser is fast becoming the place where we do work, all of our work, and more and more browsers are taking the place of word processors and other apps traditionally used on the desktop, users are accustomed to their keyboard shortcuts, so supporting them is a must for usability and adoption. If you create a word processor and make me hit ALT+SHIFT+S or something worse, I'm going to dump your app like a bad habit as a user. – DavidScherer Dec 10 '14 at 15:47
  • i question why your fancy-pants futuristic web app needs me to explicitly ask to save in the first place. and if you create _anything_ that breaks some of my basic browser functionality, i'm going to dump it myself — i've raised hell about websites that steal `/` for focusing their own search, when that's already a shortcut in firefox. – Eevee Dec 10 '14 at 19:37
  • 1
    Let he who has never accidentally pressed Ctrl + S to submit a form cast the first stone. – KevBurnsJr Nov 01 '16 at 21:14
4

@Eevee: As the browser becomes the home for richer and richer functionality and starts to replace desktop apps, it's just not going to be an option to forgo the use of keyboard shortcuts. Gmail's rich and intuitive set of keyboard commands was instrumental in my willingness to abandon Outlook. The keyboard shortcuts in Todoist, Google Reader, and Google Calendar all make my life much, much easier on a daily basis.

Developers should definitely be careful not to override keystrokes that already have a meaning in the browser. For example, the WMD textbox I'm typing into inexplicably interprets Ctrl+Del as "Blockquote" rather than "delete word forward". I'm curious if there's a standard list somewhere of "browser-safe" shortcuts that site developers can use and that browsers will commit to staying away from in future versions.

Fabrizio
  • 7,603
  • 6
  • 44
  • 104
Herb Caudill
  • 50,043
  • 39
  • 124
  • 173
  • 1
    The answer is No, there is no safe list of browser-safe shortcuts. And it's good for two resaons: 1. Shortcut are customizable (at least in Opera). 2. Doing so, you don't restrict browser vendor creativity to give you more power for the browser usage itself. – gizmo Nov 05 '08 at 18:10
1

To Alan Bellows answer: !(e.altKey) added for users who use AltGr when typing (e.g Poland). Without this pressing AltGr+S will give same result as Ctrl+S

$(document).keydown(function(e) {
if ((e.which == '115' || e.which == '83' ) && (e.ctrlKey || e.metaKey) && !(e.altKey))
{
    e.preventDefault();
    alert("Ctrl-s pressed");
    return false;
}
return true; });
Fabrizio
  • 7,603
  • 6
  • 44
  • 104
1

I like this little plugin. It needs a bit more cross browser friendliness though.

Aliaksandr Sushkevich
  • 11,550
  • 7
  • 37
  • 44
misteraidan
  • 1,984
  • 4
  • 23
  • 31
0

I solved my problem on IE, using an alert("With a message") to prevent default Behavior:

window.addEventListener("keydown", function (e) {
    if(e.ctrlKey || e.metaKey){
        e.preventDefault(); //Good browsers
        if (navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') > 0) { //hack for ie
            alert("Please, use the print button located on the top bar");
            return;
        }
    }
});
Aliaksandr Sushkevich
  • 11,550
  • 7
  • 37
  • 44
0

example:

shortcut.add("Ctrl+c",function() {
    alert('Ok...');
}
,{
    'type':'keydown',
    'propagate':false,
    'target':document
});

usage

<script type="text/javascript" src="js/shortcut.js"></script>

link for download: http://www.openjs.com/scripts/events/keyboard_shortcuts/#

worldofjr
  • 3,868
  • 8
  • 37
  • 49
André
  • 1
0

This Plugin Made by me may be helpful.

Plugin

You can use this plugin you have to supply the key Codes and function to be run like this

simulatorControl([17,83], function(){
 console.log('You have pressed Ctrl+Z');
});

In the code i have displayed how to perform for Ctrl+S. You will get Detailed Documentation On the link. Plugin is in JavaScript Code section Of my Pen on Codepen.

Fabrizio
  • 7,603
  • 6
  • 44
  • 104
0

This was my solution, which is much easier to read than other suggestions here, can easily include other key combinations, and has been tested on IE, Chrome, and Firefox:

$(window).keydown(function(evt) {
  var key = String.fromCharCode(evt.keyCode).toLowerCase();
  switch(key) {
    case "s":
      if(evt.ctrlKey || evt.metaKey) {
        fnToRun();
        evt.preventDefault(true);
        return false;
      }
      break;
  }
  return true;
});
R. Salisbury
  • 1,954
  • 16
  • 17
  • 1
    +1 for the use of `String.fromCharCode`. Although, Macs don't have a control key. Test for the command key with `evt.metaKey`. It returns `true` for Cmd on Mac and Win on Windows. –  Jun 30 '20 at 23:07
0

A lot of answers in this thread mention e.which or e.Keycode which are not recommended nowadays according to MDN and https://keyjs.dev/. Moreover, the most-rated answer looks a little bit overdone since it also brings other hotkeys which leads to usage of switch. I did not check the third-party libraries, but I always try to use as few third-party libraries as possible.

Here's my solution (since you mentioned jQuery in your question):

$(document).keydown(function(e) {
    if (e.ctrlKey && e.key == "s" || e.metaKey && e.key == "s") {
        myFunction();
        e.preventDefault();
    }
});

The e.metaKey is here because of Mac devices.

The myFunction(); line is where you specify your function. The e.preventDefault(); line is here to prevent opening of the "Save…" window. If you want to keep it for some reason, feel free to remove this line.

msi
  • 65
  • 1
  • 7
0

This should work (adapted from https://stackoverflow.com/a/8285722/388902).

var ctrl_down = false;
var ctrl_key = 17;
var s_key = 83;

$(document).keydown(function(e) {
    if (e.keyCode == ctrl_key) ctrl_down = true;
}).keyup(function(e) {
    if (e.keyCode == ctrl_key) ctrl_down = false;
});

$(document).keydown(function(e) {
    if (ctrl_down && (e.keyCode == s_key)) {
        alert('Ctrl-s pressed');
        // Your code
        return false;
    }
}); 
Community
  • 1
  • 1
pelms
  • 1,212
  • 1
  • 12
  • 21