Related
How can I catch, for example, tab+t combination with jQuery? I've found a lot of examples with alt, shift and ctrl, since event object contains special flags in order to understand if, for example, alt was pressed. But there is not such thing for tab.
This should work. It's a bit convoluted and there is likely an easier way, but it works fine.
JSFiddle: https://jsfiddle.net/spybhhxc/
var tabdown = false;
var tdown = false;
$(document).keydown(function(e) {
if(e.which == 9) {
tabdown = true;
}
if(e.which === 84)
{
tdown = true;
}
if(tabdown && tdown)
{
//do your thing
}
});
$(document).keyup(function(e) {
if(e.which == 9) {
tabdown = false;
}
if(e.which === 84)
{
tdown = false;
}
});
This presents a problem though, as once you press tab, the document is unfocused as the tab key navigates to elements in a browser. You would be much better off using something like alt or ctrl which don't interact with the browser.
We can have a tab key pressed [tabPressed] variable which will be set to true on key down and unset the same on its key up event. We will using the tab key pressed[tabPressed] variable to check whether it is in pressed state during the other key press activities. The tab keycode is 9.
jsfiddle link http://jsfiddle.net/e3Lveyj2/
var tabPressed=false;
function handleKeyDown(e) {
var evt = (e==null ? event:e);
if(evt.keyCode == 9){
tabPressed=true;
}
if ((tabPressed) && (evt.keyCode == 84)) {
alert ("You pressed 'Tab+t'")
}
}
function handleKeyUp(e) {
var evt = (e==null ? event:e);
if(evt.keyCode == 9){
tabPressed=false;
}
}
document.onkeydown = handleKeyDown;
document.onkeyup = handleKeyUp;
I have a library that creates an editor on the fly (http://epiceditor.com) and also sets up key shortcuts automatically. The shortcuts can be configured in the options so I can't use e.altKey, e.ctrlKey, etc just a heads up.
For some reason the modifier key isn't being set back to false sometimes on Mac/Ubuntu browsers.
On Windows it seems to happen every time. You can reproduce this by clicking render in JSBin then pressing alt+p. You should see "Yay" appear. Now, if on Windows press just p again. You'll see "Yay appear again. Mac and Ubuntu users have seen this same issue occasionally but it's hard to reproduce it.
Also note this only happens with the alt key it seems. Below I have 16 (shift) next to the 18 (alt). If you swap those out it'll work as expected.
The code for the stripped down test case is:
var modKey = false;
var modKeyCode = 18; //16
document.body.addEventListener('keydown', function (e) {
if (!modKey && modKeyCode == e.keyCode) {
modKey = true;
}
if (modKey && e.keyCode == 80) {
console.log('Yay!');
}
});
document.body.addEventListener('keyup', function (e) {
if (modKey && modKeyCode == e.keyCode) {
modKey = false;
}
});
Demo: http://jsbin.com/uhupah/3/edit#javascript,html
I do not have access to my Linux box at the moment, so i cannot test your code.
Thus here is more of a suggestion:
Linux (in my experience) is finicky when it it comes to keyCodes and order of key events. Perhaps combine the if(..) from keyup with that of keydown
if (!modKey && modKeyCode == e.keyCode) {
modKey = true;
} else if (modKey && modKeyCode == e.keyCode) {
modKey = false;
}
The above suggestion is made with assumption that you have no specific requirement to have both 'keydown' and 'keyup'.
I've come up with a fix, albeit a sort of crappy fix, but a fix nonetheless.
The fix I went with was to reset the modifier var when any key combo was successful. I.e. one the p in alt+p is pressed reset the modKey to false like this:
var modKey = false;
var modKeyCode = 18; //16
document.body.addEventListener('keydown', function (e) {
if (!modKey && modKeyCode == e.keyCode) {
modKey = true;
}
if (modKey && e.keyCode == 80) {
console.log('Yay!');
modKey = false; //THIS
}
});
document.body.addEventListener('keyup', function (e) {
if (modKey && modKeyCode == e.keyCode) {
modKey = false;
}
});
The problem with this tho is that you can't do back to back key commands. Most of the time this is alright because the user will do a key command like "save" or "preview" or something, type some more, then do another key command. But you wouldn't be able to, let's say: alt+p s to trigger alt+p then alt+s without having to let go of the alt key.
How to detect Ctrl+V, Ctrl+C using JavaScript?
I need to restrict pasting in my textareas, end user should not copy and paste the content, user should only type text in textarea.
How can I achieve this?
I just did this out of interest. I agree it's not the right thing to do, but I think it should be the op's decision... Also the code could easily be extended to add functionality, rather than take it away (like a more advanced clipboard, or Ctrl+S triggering a server-side save).
$(document).ready(function() {
var ctrlDown = false,
ctrlKey = 17,
cmdKey = 91,
vKey = 86,
cKey = 67;
$(document).keydown(function(e) {
if (e.keyCode == ctrlKey || e.keyCode == cmdKey) ctrlDown = true;
}).keyup(function(e) {
if (e.keyCode == ctrlKey || e.keyCode == cmdKey) ctrlDown = false;
});
$(".no-copy-paste").keydown(function(e) {
if (ctrlDown && (e.keyCode == vKey || e.keyCode == cKey)) return false;
});
// Document Ctrl + C/V
$(document).keydown(function(e) {
if (ctrlDown && (e.keyCode == cKey)) console.log("Document catch Ctrl+C");
if (ctrlDown && (e.keyCode == vKey)) console.log("Document catch Ctrl+V");
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h3>Ctrl+c Ctrl+v disabled</h3>
<textarea class="no-copy-paste"></textarea>
<br><br>
<h3>Ctrl+c Ctrl+v allowed</h3>
<textarea></textarea>
Also just to clarify, this script requires the jQuery library.
Codepen demo
EDIT: removed 3 redundant lines (involving e.which) thanks to Tim Down's suggestion (see comments)
EDIT: added support for Macs (CMD key instead of Ctrl)
With jquery you can easy detect copy, paste, etc by binding the function:
$("#textA").bind('copy', function() {
$('span').text('copy behaviour detected!')
});
$("#textA").bind('paste', function() {
$('span').text('paste behaviour detected!')
});
$("#textA").bind('cut', function() {
$('span').text('cut behaviour detected!')
});
More information here: http://www.mkyong.com/jquery/how-to-detect-copy-paste-and-cut-behavior-with-jquery/
While it can be annoying when used as an anti-piracy measure, I can see there might be some instances where it'd be legitimate, so:
function disableCopyPaste(elm) {
// Disable cut/copy/paste key events
elm.onkeydown = interceptKeys
// Disable right click events
elm.oncontextmenu = function() {
return false
}
}
function interceptKeys(evt) {
evt = evt||window.event // IE support
var c = evt.keyCode
var ctrlDown = evt.ctrlKey||evt.metaKey // Mac support
// Check for Alt+Gr (http://en.wikipedia.org/wiki/AltGr_key)
if (ctrlDown && evt.altKey) return true
// Check for ctrl+c, v and x
else if (ctrlDown && c==67) return false // c
else if (ctrlDown && c==86) return false // v
else if (ctrlDown && c==88) return false // x
// Otherwise allow
return true
}
I've used event.ctrlKey rather than checking for the key code as on most browsers on Mac OS X Ctrl/Alt "down" and "up" events are never triggered, so the only way to detect is to use event.ctrlKey in the e.g. c event after the Ctrl key is held down. I've also substituted ctrlKey with metaKey for macs.
Limitations of this method:
Opera doesn't allow disabling right click events
Drag and drop between browser windows can't be prevented as far as I know.
The edit->copy menu item in e.g. Firefox can still allow copy/pasting.
There's also no guarantee that for people with different keyboard layouts/locales that copy/paste/cut are the same key codes (though layouts often just follow the same standard as English), but blanket "disable all control keys" mean that select all etc will also be disabled so I think that's a compromise which needs to be made.
If you use the ctrlKey property, you don't need to maintain state.
$(document).keydown(function(event) {
// Ctrl+C or Cmd+C pressed?
if ((event.ctrlKey || event.metaKey) && event.keyCode == 67) {
// Do stuff.
}
// Ctrl+V or Cmd+V pressed?
if ((event.ctrlKey || event.metaKey) && event.keyCode == 86) {
// Do stuff.
}
// Ctrl+X or Cmd+X pressed?
if ((event.ctrlKey || event.metaKey) && event.keyCode == 88) {
// Do stuff.
}
}
There's another way of doing this: onpaste, oncopy and oncut events can be registered and cancelled in IE, Firefox, Chrome, Safari (with some minor problems), the only major browser that doesn't allow cancelling these events is Opera.
As you can see in my other answer intercepting Ctrl+V and Ctrl+C comes with many side effects, and it still doesn't prevent users from pasting using the Firefox Edit menu etc.
function disable_cutcopypaste(e) {
var fn = function(evt) {
// IE-specific lines
evt = evt||window.event
evt.returnValue = false
// Other browser support
if (evt.preventDefault)
evt.preventDefault()
return false
}
e.onbeforepaste = e.onbeforecopy = e.onbeforecut = fn
e.onpaste = e.oncopy = e.oncut = fn
}
Safari still has some minor problems with this method (it clears the clipboard in place of cut/copy when preventing default) but that bug appears to have been fixed in Chrome now.
See also: http://www.quirksmode.org/dom/events/cutcopypaste.html and the associated test page http://www.quirksmode.org/dom/events/tests/cutcopypaste.html for more information.
Live Demo :
http://jsfiddle.net/abdennour/ba54W/
$(document).ready(function() {
$("#textA").bind({
copy : function(){
$('span').text('copy behaviour detected!');
},
paste : function(){
$('span').text('paste behaviour detected!');
},
cut : function(){
$('span').text('cut behaviour detected!');
}
});
});
Short solution for preventing user from using context menu, copy and cut in jQuery:
jQuery(document).bind("cut copy contextmenu",function(e){
e.preventDefault();
});
Also disabling text selection in CSS might come handy:
.noselect {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
Another approach (no plugin needed) it to just use ctrlKey property of the event object that gets passed in. It indicates if Ctrl was pressed at the time of the event, like this:
$(document).keypress("c",function(e) {
if(e.ctrlKey)
alert("Ctrl+C was pressed!!");
});
See also jquery: keypress, ctrl+c (or some combo like that).
You can use this code for rightclick, CTRL+C, CTRL+V, CTRL+X detect and prevent their action
$(document).bind('copy', function(e) {
alert('Copy is not allowed !!!');
e.preventDefault();
});
$(document).bind('paste', function() {
alert('Paste is not allowed !!!');
e.preventDefault();
});
$(document).bind('cut', function() {
alert('Cut is not allowed !!!');
e.preventDefault();
});
$(document).bind('contextmenu', function(e) {
alert('Right Click is not allowed !!!');
e.preventDefault();
});
instead of onkeypress, use onkeydown.
<input type="text" onkeydown="if(event.ctrlKey && event.keyCode==86){return false;}" name="txt">
If anyone is interested in a simple vanilla JavaScript approach, see below.
Fiddle Link: DEMO
let ctrlActive = false;
let cActive = false;
let vActive = false
document.body.addEventListener('keyup', event => {
if (event.key == 'Control') ctrlActive = false;
if (event.code == 'KeyC') cActive = false;
if (event.code == 'KeyV') vActive = false;
})
document.body.addEventListener('keydown', event => {
if (event.key == 'Control') ctrlActive = true;
if (ctrlActive == true && event.code == 'KeyC') {
// this disables the browsers default copy functionality
event.preventDefault()
// perform desired action(s) here...
console.log('The CTRL key and the C key are being pressed simultaneously.')
}
if (ctrlActive == true && event.code == 'KeyV') {
// this disables the browsers default paste functionality
event.preventDefault()
// perform desired action(s) here...
console.log('The CTRL key and the V key are being pressed simultaneously.')
}
})
The code above would disable the default copy in the browser. If you'd like keep the copy functionality in the browser, just comment out this bit: event.preventDefault() and you can then run any desired actions while allowing the user to copy content.
I wrote a jQuery plugin, which catches keystrokes. It can be used to enable multiple language script input in html forms without the OS (except the fonts). Its about 300 lines of code, maybe you like to take a look:
http://miku.github.com/jquery-retype
Generally, be careful with such kind of alterations. I wrote the plugin for a client because other solutions weren't available.
Don't forget that, while you might be able to detect and block Ctrl+C/V, you can still alter the value of a certain field.
Best example for this is Chrome's Inspect Element function, this allows you to change the value-property of a field.
A hook that allows for overriding copy events, could be used for doing the same with paste events. The input element cannot be display: none; or visibility: hidden; sadly
export const useOverrideCopy = () => {
const [copyListenerEl, setCopyListenerEl] = React.useState(
null as HTMLInputElement | null
)
const [, setCopyHandler] = React.useState<(e: ClipboardEvent) => void | null>(
() => () => {}
)
// appends a input element to the DOM, that will be focused.
// when using copy/paste etc, it will target focused elements
React.useEffect(() => {
const el = document.createElement("input")
// cannot focus a element that is not "visible" aka cannot use display: none or visibility: hidden
el.style.width = "0"
el.style.height = "0"
el.style.opacity = "0"
el.style.position = "fixed"
el.style.top = "-20px"
document.body.appendChild(el)
setCopyListenerEl(el)
return () => {
document.body.removeChild(el)
}
}, [])
// adds a event listener for copying, and removes the old one
const overrideCopy = (newOverrideAction: () => any) => {
setCopyHandler((prevCopyHandler: (e: ClipboardEvent) => void) => {
const copyHandler = (e: ClipboardEvent) => {
e.preventDefault()
newOverrideAction()
}
copyListenerEl?.removeEventListener("copy", prevCopyHandler)
copyListenerEl?.addEventListener("copy", copyHandler)
copyListenerEl?.focus() // when focused, all copy events will trigger listener above
return copyHandler
})
}
return { overrideCopy }
}
Used like this:
const customCopyEvent = () => {
console.log("doing something")
}
const { overrideCopy } = useOverrideCopy()
overrideCopy(customCopyEvent)
Every time you call overrideCopy it will refocus and call your custom event on copy.
Another simple way using Jquery:
$(document).keydown( function(e)
{
if (e.ctrlKey && e.key == 'c')
{
console.log('got ctrl c');
}
else if (e.ctrlKey && e.key == 'v')
{
console.log('got ctrl v');
}
});
element.addEventListener('keydown', function (e) {
if (e.key == 'c' && e.ctrlKey) {
e.preventDefault(); // prevent from copying
}
if (e.key == 'v' && e.ctrlKey) {
e.preventDefault(); // prevent from pasting
}
}
i already have your problem and i solved it by the following code .. that accept only numbers
$('#<%= mobileTextBox.ClientID %>').keydown(function(e) {
///// e.which Values
// 8 : BackSpace , 46 : Delete , 37 : Left , 39 : Rigth , 144: Num Lock
if (e.which != 8 && e.which != 46 && e.which != 37 && e.which != 39 && e.which != 144
&& (e.which < 96 || e.which > 105 )) {
return false;
}
});
you can detect Ctrl id e.which == 17
Important note
I was using e.keyCode for a while and i detected that when i press Ctrl+., This attribute returns a wrong number, 190, while the ascii code of . is 46!
So you should use e.key.toUpperCase().charCodeAt(0) instead of e.keyCode.
$(document).keydown(function(event) {
let keyCode = e.key.toUpperCase().charCodeAt(0);
...
}
You can listen to the keypress event, and halt the default event (entering the text) if it matches the specific keycodes
There is some ways to prevent it.
However the user will be always able to turn the javascript off or just look on the source code of the page.
Some examples (require jQuery)
/**
* Stop every keystroke with ctrl key pressed
*/
$(".textbox").keydown(function(){
if (event.ctrlKey==true) {
return false;
}
});
/**
* Clear all data of clipboard on focus
*/
$(".textbox").focus(function(){
if ( window.clipboardData ) {
window.clipboardData.setData('text','');
}
});
/**
* Block the paste event
*/
$(".textbox").bind('paste',function(e){return false;});
Edit: How Tim Down said, this functions are all browser dependents.
On IE I can do this with the (terribly non-standard, but working) jQuery
if ($.browser.msie)
$(document).keydown(function(e) { if (e.keyCode == 8) window.event.keyCode = 0;});
But is it possible to do in a way which works on Firefox, or in a cross-browser way for a bonus?
For the record:
$(document).keydown(function(e) { if (e.keyCode == 8) e.stopPropagation(); });
does nothing.
$(document).keydown(function(e) { if (e.keyCode == 8) e.preventDefault(); });
solves the problem, but renders the backspace key unusable on the page, which is even worse than the original behaviour.
EDIT:
The reason I do this is that I'm not creating a simple web page but a large application. It is incredibly annoying to lose 10 minutes of work just because you pressed backspace in the wrong place. The ratio of preventing mistakes vs. annoying users should be way above 1000/1 by preventing the backspace key from navigating back.
EDIT2: I'm not trying to prevent history navigation, just accidents.
EDIT3: #brentonstrines comment (moved here since the question is so popular): This is a long-term 'fix', but you could throw your support behind the Chromium bug to change this behavior in webkit
This code solves the problem, at least in IE and Firefox (haven't tested any other, but I give it a reasonable chance of working if the problem even exists in other browsers).
// Prevent the backspace key from navigating back.
$(document).unbind('keydown').bind('keydown', function (event) {
if (event.keyCode === 8) {
var doPrevent = true;
var types = ["text", "password", "file", "search", "email", "number", "date", "color", "datetime", "datetime-local", "month", "range", "search", "tel", "time", "url", "week"];
var d = $(event.srcElement || event.target);
var disabled = d.prop("readonly") || d.prop("disabled");
if (!disabled) {
if (d[0].isContentEditable) {
doPrevent = false;
} else if (d.is("input")) {
var type = d.attr("type");
if (type) {
type = type.toLowerCase();
}
if (types.indexOf(type) > -1) {
doPrevent = false;
}
} else if (d.is("textarea")) {
doPrevent = false;
}
}
if (doPrevent) {
event.preventDefault();
return false;
}
}
});
This code works on all browsers and swallows the backspace key when not on a form element, or if the form element is disabled|readOnly. It is also efficient, which is important when it is executing on every key typed in.
$(function(){
/*
* this swallows backspace keys on any non-input element.
* stops backspace -> back
*/
var rx = /INPUT|SELECT|TEXTAREA/i;
$(document).bind("keydown keypress", function(e){
if( e.which == 8 ){ // 8 == backspace
if(!rx.test(e.target.tagName) || e.target.disabled || e.target.readOnly ){
e.preventDefault();
}
}
});
});
The other answers here have established that this cannot be done without whitelisting elements in which Backspace is allowed. This solution is not ideal because the whitelist is not as straightforward as merely textareas and text/password inputs, but is repeatedly found to be incomplete and needing to be updated.
However, since the purpose of suppressing the backspace functionality is merely to prevent users from accidentally losing data, the beforeunload solution is a good one because the modal popup is surprising--modal popups are bad when they are triggered as part of a standard workflow, because the user gets used to dismissing them without reading them, and they are annoying. In this case, the modal popup would only appear as an alternative to a rare and surprising action, and is therefore acceptable.
The problem is that an onbeforeunload modal must not pop up whenever the user navigates away from the page (such as when clicking a link or submitting a form), and we don't want to start whitelisting or blacklisting specific onbeforeunload conditions.
The ideal combination of tradeoffs for a generalized solution is as follows: keep track of whether backspace is pressed, and only pop up the onbeforeunload modal if it is. In other words:
function confirmBackspaceNavigations () {
// http://stackoverflow.com/a/22949859/2407309
var backspaceIsPressed = false
$(document).keydown(function(event){
if (event.which == 8) {
backspaceIsPressed = true
}
})
$(document).keyup(function(event){
if (event.which == 8) {
backspaceIsPressed = false
}
})
$(window).on('beforeunload', function(){
if (backspaceIsPressed) {
backspaceIsPressed = false
return "Are you sure you want to leave this page?"
}
})
} // confirmBackspaceNavigations
This has been tested to work in IE7+, FireFox, Chrome, Safari, and Opera. Just drop this function into your global.js and call it from any page where you don't want users to accidentally lose their data.
Note that an onbeforeunload modal can only be triggered once, so if the user presses backspace again, the modal will not fire again.
Note that this will not trigger on hashchange events, however in that context you can use other techniques to keep users from accidentally losing their data.
A more elegant/concise solution:
$(document).on('keydown',function(e){
var $target = $(e.target||e.srcElement);
if(e.keyCode == 8 && !$target.is('input,[contenteditable="true"],textarea'))
{
e.preventDefault();
}
})
Modification of erikkallen's Answer to address different input types
I've found that an enterprising user might press backspace on a checkbox or a radio button in a vain attempt to clear it and instead they would navigate backwards and lose all of their data.
This change should address that issue.
New Edit to address content editable divs
//Prevents backspace except in the case of textareas and text inputs to prevent user navigation.
$(document).keydown(function (e) {
var preventKeyPress;
if (e.keyCode == 8) {
var d = e.srcElement || e.target;
switch (d.tagName.toUpperCase()) {
case 'TEXTAREA':
preventKeyPress = d.readOnly || d.disabled;
break;
case 'INPUT':
preventKeyPress = d.readOnly || d.disabled ||
(d.attributes["type"] && $.inArray(d.attributes["type"].value.toLowerCase(), ["radio", "checkbox", "submit", "button"]) >= 0);
break;
case 'DIV':
preventKeyPress = d.readOnly || d.disabled || !(d.attributes["contentEditable"] && d.attributes["contentEditable"].value == "true");
break;
default:
preventKeyPress = true;
break;
}
}
else
preventKeyPress = false;
if (preventKeyPress)
e.preventDefault();
});
Example
To test make 2 files.
starthere.htm - open this first so you have a place to go back to
Navigate to here to test
test.htm - This will navigate backwards when backspace is pressed while the checkbox or submit has focus (achieved by tabbing). Replace with my code to fix.
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).keydown(function(e) {
var doPrevent;
if (e.keyCode == 8) {
var d = e.srcElement || e.target;
if (d.tagName.toUpperCase() == 'INPUT' || d.tagName.toUpperCase() == 'TEXTAREA') {
doPrevent = d.readOnly || d.disabled;
}
else
doPrevent = true;
}
else
doPrevent = false;
if (doPrevent)
e.preventDefault();
});
</script>
</head>
<body>
<input type="text" />
<input type="radio" />
<input type="checkbox" />
<input type="submit" />
</body>
</html>
Based on the comments it appears you want to stop people losing information in forms, if they press backspace to delete but the field is not focused.
In which case, you want to look at the onunload event handler. Stack Overflow uses it - if you try to leave a page when you've started writing an answer, it pops up a warning.
Most of the answers are in jquery. You can do this perfectly in pure Javascript, simple and no library required. This article was a good starting point for me but since keyIdentifier is deprecated, I wanted this code to be more secure so I added ||e.keyCode==8 to the if statement. Also, the code wasn't working well on Firefox so I added return false; and now it works perfectly well. Here it is:
<script type="text/javascript">
window.addEventListener('keydown',function(e){if(e.keyIdentifier=='U+0008'||e.keyIdentifier=='Backspace'||e.keyCode==8){if(e.target==document.body){e.preventDefault();return false;}}},true);
</script>
This code works great because,
It is in pure javascript (no library required).
Not only it checks the key pressed, it confirms if the action is really a browser "back" action.
Together with the above, user can type and delete text from input text boxes on the web page without any problems while still preventing the back button action.
It is short, clean, fast and straight to the point.
You can add console.log(e); for your your test purposes, and hit F12 in chrome, go to "console" tab and hit "backspace" on the page and look inside it to see what values are returned, then you can target all of those parameters to further enhance the code above to suit your needs.
Stop from navigating this code works!
$(document).on("keydown", function (event) {
if (event.keyCode === 8) {
event.preventDefault();
}
});
But for not to restricting text fields but others
$(document).on("keydown", function (event) {
if (event.which === 8 && !$(event.target).is("input, textarea")) {
event.preventDefault();
}
});
To prevent it for specific field simply use
$('#myOtherField').on("keydown", function (event) {
if (event.keyCode === 8 || event.which === 8) {
event.preventDefault();
}
});
Referring to this one below!
Prevent BACKSPACE from navigating back with jQuery (Like Google's Homepage)
Combining solutions given by "thetoolman" && "Biff MaGriff"
following code seems to work correctly in IE 8/Mozilla/Chrome
$(function () {
var rx = /INPUT|TEXTAREA/i;
var rxT = /RADIO|CHECKBOX|SUBMIT/i;
$(document).bind("keydown keypress", function (e) {
var preventKeyPress;
if (e.keyCode == 8) {
var d = e.srcElement || e.target;
if (rx.test(e.target.tagName)) {
var preventPressBasedOnType = false;
if (d.attributes["type"]) {
preventPressBasedOnType = rxT.test(d.attributes["type"].value);
}
preventKeyPress = d.readOnly || d.disabled || preventPressBasedOnType;
} else {preventKeyPress = true;}
} else { preventKeyPress = false; }
if (preventKeyPress) e.preventDefault();
});
});
Not sure why no-one's just answered this - seems like a perfectly reasonable technical question to ask whether it's possible.
No, I don't think there's a cross-browser way to disable the backspace button. I know it's not enabled by default in FF these days though.
I had a hard time finding a non-JQUERY answer. Thanks to Stas for putting me on the track.
Chrome: If you don't need cross browser support, you can just use a blacklist, rather than whitelisting. This pure JS version works in Chrome, but not in IE. Not sure about FF.
In Chrome (ver. 36, mid 2014), keypresses not on an input or contenteditable element seem to be targeted to <BODY>. This makes it possible use a blacklist, which I prefer to whitelisting. IE uses the last click target - so it might be a div or anything else. That makes this useless in IE.
window.onkeydown = function(event) {
if (event.keyCode == 8) {
//alert(event.target.tagName); //if you want to see how chrome handles keypresses not on an editable element
if (event.target.tagName == 'BODY') {
//alert("Prevented Navigation");
event.preventDefault();
}
}
}
Cross Browser: For pure javascript, I found Stas' answer to be the best. Adding one more condition check for contenteditable made it work for me*:
document.onkeydown = function(e) {stopDefaultBackspaceBehaviour(e);}
document.onkeypress = function(e) {stopDefaultBackspaceBehaviour(e);}
function stopDefaultBackspaceBehaviour(event) {
var event = event || window.event;
if (event.keyCode == 8) {
var elements = "HTML, BODY, TABLE, TBODY, TR, TD, DIV";
var d = event.srcElement || event.target;
var regex = new RegExp(d.tagName.toUpperCase());
if (d.contentEditable != 'true') { //it's not REALLY true, checking the boolean value (!== true) always passes, so we can use != 'true' rather than !== true/
if (regex.test(elements)) {
event.preventDefault ? event.preventDefault() : event.returnValue = false;
}
}
}
}
*Note that IEs [edit: and Spartan/TechPreview] have a "feature" that makes table-related elements uneditable. If you click one of those and THEN press backspace, it WILL navigate back. If you don't have editable <td>s, this is not an issue.
This solution is similar to others that have been posted, but it uses a simple whitelist making it easily customizable to allow the backspace in specified elements just by setting the selector in the .is() function.
I use it in this form to prevent the backspace on pages from navigating back:
$(document).on("keydown", function (e) {
if (e.which === 8 && !$(e.target).is("input:not([readonly]), textarea")) {
e.preventDefault();
}
});
To elaborate slightly on #erikkallen's excellent answer, here is a function that allows all keyboard-based input types, including those introduced in HTML5:
$(document).unbind('keydown').bind('keydown', function (event) {
var doPrevent = false;
var INPUTTYPES = [
"text", "password", "file", "date", "datetime", "datetime-local",
"month", "week", "time", "email", "number", "range", "search", "tel",
"url"];
var TEXTRE = new RegExp("^" + INPUTTYPES.join("|") + "$", "i");
if (event.keyCode === 8) {
var d = event.srcElement || event.target;
if ((d.tagName.toUpperCase() === 'INPUT' && d.type.match(TEXTRE)) ||
d.tagName.toUpperCase() === 'TEXTAREA') {
doPrevent = d.readOnly || d.disabled;
} else {
doPrevent = true;
}
}
if (doPrevent) {
event.preventDefault();
}
});
JavaScript - jQuery way:
$(document).on("keydown", function (e) {
if (e.which === 8 && !$(e.target).is("input, textarea")) {
e.preventDefault();
}
});
Javascript - the native way, that works for me:
<script type="text/javascript">
//on backspace down + optional callback
function onBackspace(e, callback){
var key;
if(typeof e.keyIdentifier !== "undefined"){
key = e.keyIdentifier;
}else if(typeof e.keyCode !== "undefined"){
key = e.keyCode;
}
if (key === 'U+0008' ||
key === 'Backspace' ||
key === 8) {
if(typeof callback === "function"){
callback();
}
return true;
}
return false;
}
//event listener
window.addEventListener('keydown', function (e) {
switch(e.target.tagName.toLowerCase()){
case "input":
case "textarea":
break;
case "body":
onBackspace(e,function(){
e.preventDefault();
});
break;
}
}, true);
</script>
I had some problems with the accepted solution and the Select2.js plugin; I was not able to delete characters in the editable box as the delete action was being prevented. This was my solution:
//Prevent backwards navigation when trying to delete disabled text.
$(document).unbind('keydown').bind('keydown', function (event) {
if (event.keyCode === 8) {
var doPrevent = false,
d = event.srcElement || event.target,
tagName = d.tagName.toUpperCase(),
type = (d.type ? d.type.toUpperCase() : ""),
isEditable = d.contentEditable,
isReadOnly = d.readOnly,
isDisabled = d.disabled;
if (( tagName === 'INPUT' && (type === 'TEXT' || type === 'PASSWORD'))
|| tagName === 'PASSWORD'
|| tagName === 'TEXTAREA') {
doPrevent = isReadOnly || isDisabled;
}
else if(tagName === 'SPAN'){
doPrevent = !isEditable;
}
else {
doPrevent = true;
}
}
if (doPrevent) {
event.preventDefault();
}
});
Select2 creates a Span with an attribute of "contentEditable" which is set to true for the editable combo box in it. I added code to account for the spans tagName and the different attribute. This solved all my problems.
Edit: If you are not using the Select2 combobox plugin for jquery, then this solution may not be needed by you, and the accepted solution might be better.
document.onkeydown = function (e) {
e.stopPropagation();
if ((e.keyCode==8 || e.keyCode==13) &&
(e.target.tagName != "TEXTAREA") &&
(e.target.tagName != "INPUT")) {
return false;
}
};
This code solves the problem in all browsers:
onKeydown:function(e)
{
if (e.keyCode == 8)
{
var d = e.srcElement || e.target;
if (!((d.tagName.toUpperCase() == 'BODY') || (d.tagName.toUpperCase() == 'HTML')))
{
doPrevent = false;
}
else
{
doPrevent = true;
}
}
else
{
doPrevent = false;
}
if (doPrevent)
{
e.preventDefault();
}
}
Simplest way to prevent navigation on pressing backspace
$(document).keydown(function () {
if (event.keyCode == 8) {
if (event.target.nodeName == 'BODY') {
event.preventDefault();
}
}
});
Using Dojo toolkit 1.7, this works in IE 8:
require(["dojo/on", "dojo/keys", "dojo/domReady!"],
function(on, keys) {
on(document.body,"keydown",function(evt){if(evt.keyCode == keys.BACKSPACE)evt.preventDefault()});
});
Have you tried the very simple solution of just adding the following attribute to your read only text field:
onkeydown="return false;"
This will keep the browser from going back in history when the Backspace key is pressed in a read only text field. Maybe I am missing your true intent, but seems like this would be the simplest solution to your issue.
A much neater solution -
$(document).on('keydown', function (e) {
var key = e == null ? event.keyCode : e.keyCode;
if(key == 8 && $(document.activeElement.is(':not(:input)'))) //select, textarea
e.preventDefault();
});
Alternately, you could only check if
$(document.activeElement).is('body')
Pure javascript version, which works in all browsers:
document.onkeydown = function(e) {stopDefaultBackspaceBehaviour(e);}
document.onkeypress = function(e) {stopDefaultBackspaceBehaviour(e);}
function stopDefaultBackspaceBehaviour(event) {
var event = event || window.event;
if (event.keyCode == 8) {
var elements = "HTML, BODY, TABLE, TBODY, TR, TD, DIV";
var d = event.srcElement || event.target;
var regex = new RegExp(d.tagName.toUpperCase());
if (regex.test(elements)) {
event.preventDefault ? event.preventDefault() : event.returnValue = false;
}
}
}
Of course you can use "INPUT, TEXTAREA" and use "if (!regex.test(elements))" then. The first worked fine for me.
Performance?
I was worried about performance and made a fiddle: http://jsfiddle.net/felvhage/k2rT6/9/embedded/result/
var stresstest = function(e, method, index){...
I have analyzed the most promising methods i found in this thread. It turns out, they were all very fast and most probably do not cause a problem in terms of "sluggishness" when typing.
The slowest Method i looked at was about 125 ms for 10.000 Calls in IE8. Which is 0.0125ms per Stroke.
I found the methods posted by Codenepal and Robin Maben to be fastest ~ 0.001ms (IE8) but beware of the different semantics.
Perhaps this is a relief to someone introducing this kind of functionality to his code.
Modified erikkallen answer:
$(document).unbind('keydown').bind('keydown', function (event) {
var doPrevent = false, elem;
if (event.keyCode === 8) {
elem = event.srcElement || event.target;
if( $(elem).is(':input') ) {
doPrevent = elem.readOnly || elem.disabled;
} else {
doPrevent = true;
}
}
if (doPrevent) {
event.preventDefault();
return false;
}
});
This solution worked very well when tested.
I did add some code to handle some input fields not tagged with input, and to integrate in an Oracle PL/SQL application that generates an input form for my job.
My "two cents":
if (typeof window.event != ''undefined'')
document.onkeydown = function() {
//////////// IE //////////////
var src = event.srcElement;
var tag = src.tagName.toUpperCase();
if (event.srcElement.tagName.toUpperCase() != "INPUT"
&& event.srcElement.tagName.toUpperCase() != "TEXTAREA"
|| src.readOnly || src.disabled
)
return (event.keyCode != 8);
if(src.type) {
var type = ("" + src.type).toUpperCase();
return type != "CHECKBOX" && type != "RADIO" && type != "BUTTON";
}
}
else
document.onkeypress = function(e) {
//////////// FireFox
var src = e.target;
var tag = src.tagName.toUpperCase();
if ( src.nodeName.toUpperCase() != "INPUT" && tag != "TEXTAREA"
|| src.readOnly || src.disabled )
return (e.keyCode != 8);
if(src.type) {
var type = ("" + src.type).toUpperCase();
return type != "CHECKBOX" && type != "RADIO" && type != "BUTTON";
}
}
I created a NPM project with a clean version of the currently accepted (of erikkallen)
https://github.com/slorber/backspace-disabler
It uses basically the same principles but:
No dependency
Support for contenteditable
More readable / maintainable code base
Will be supported as it will be used in production by my company
MIT license
var Backspace = 8;
// See http://stackoverflow.com/questions/12949590/how-to-detach-event-in-ie-6-7-8-9-using-javascript
function addHandler(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
}
function removeHandler(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
}
// Test wether or not the given node is an active contenteditable,
// or is inside an active contenteditable
function isInActiveContentEditable(node) {
while (node) {
if ( node.getAttribute && node.getAttribute("contenteditable") === "true" ) {
return true;
}
node = node.parentNode;
}
return false;
}
var ValidInputTypes = ['TEXT','PASSWORD','FILE','EMAIL','SEARCH','DATE'];
function isActiveFormItem(node) {
var tagName = node.tagName.toUpperCase();
var isInput = ( tagName === "INPUT" && ValidInputTypes.indexOf(node.type.toUpperCase()) >= 0 );
var isTextarea = ( tagName === "TEXTAREA" );
if ( isInput || isTextarea ) {
var isDisabled = node.readOnly || node.disabled;
return !isDisabled;
}
else if ( isInActiveContentEditable(node) ) {
return true;
}
else {
return false;
}
}
// See http://stackoverflow.com/questions/1495219/how-can-i-prevent-the-backspace-key-from-navigating-back
function disabler(event) {
if (event.keyCode === Backspace) {
var node = event.srcElement || event.target;
// We don't want to disable the ability to delete content in form inputs and contenteditables
if ( isActiveFormItem(node) ) {
// Do nothing
}
// But in any other cases we prevent the default behavior that triggers a browser backward navigation
else {
event.preventDefault();
}
}
}
/**
* By default the browser issues a back nav when the focus is not on a form input / textarea
* But users often press back without focus, and they loose all their form data :(
*
* Use this if you want the backspace to never trigger a browser back
*/
exports.disable = function(el) {
addHandler(el || document,"keydown",disabler);
};
/**
* Reenable the browser backs
*/
exports.enable = function(el) {
removeHandler(el || document,"keydown",disabler);
};
Here is my rewrite of the top-voted answer. I tried to check element.value!==undefined (since some elements like may have no html attribute but may have a javascript value property somewhere on the prototype chain), however that didn't work very well and had lots of edge cases. There doesn't seem to be a good way to future-proof this, so a whitelist seems the best option.
This registers the element at the end of the event bubble phase, so if you want to handle Backspace in any custom way, you can do so in other handlers.
This also checks instanceof HTMLTextAreElement since one could theoretically have a web component which inherits from that.
This does not check contentEditable (combine with other answers).
https://jsfiddle.net/af2cfjc5/15/
var _INPUTTYPE_WHITELIST = ['text', 'password', 'search', 'email', 'number', 'date'];
function backspaceWouldBeOkay(elem) {
// returns true if backspace is captured by the element
var isFrozen = elem.readOnly || elem.disabled;
if (isFrozen) // a frozen field has no default which would shadow the shitty one
return false;
else {
var tagName = elem.tagName.toLowerCase();
if (elem instanceof HTMLTextAreaElement) // allow textareas
return true;
if (tagName=='input') { // allow only whitelisted input types
var inputType = elem.type.toLowerCase();
if (_INPUTTYPE_WHITELIST.includes(inputType))
return true;
}
return false; // everything else is bad
}
}
document.body.addEventListener('keydown', ev => {
if (ev.keyCode==8 && !backspaceWouldBeOkay(ev.target)) {
//console.log('preventing backspace navigation');
ev.preventDefault();
}
}, true); // end of event bubble phase
Sitepoint: Disable back for Javascript
event.stopPropagation() and event.preventDefault() do nothing in IE. I had to send return event.keyCode == 11 (I just picked something) instead of just saying "if not = 8, run the event" to make it work, though. event.returnValue = false also works.
Another method using jquery
<script type="text/javascript">
//set this variable according to the need within the page
var BACKSPACE_NAV_DISABLED = true;
function fnPreventBackspace(event){if (BACKSPACE_NAV_DISABLED && event.keyCode == 8) {return false;}}
function fnPreventBackspacePropagation(event){if(BACKSPACE_NAV_DISABLED && event.keyCode == 8){event.stopPropagation();}return true;}
$(document).ready(function(){
if(BACKSPACE_NAV_DISABLED){
//for IE use keydown, for Mozilla keypress
//as described in scr: http://www.codeproject.com/KB/scripting/PreventDropdownBackSpace.aspx
$(document).keypress(fnPreventBackspace);
$(document).keydown(fnPreventBackspace);
//Allow Backspace is the following controls
var jCtrl = null;
jCtrl = $('input[type="text"]');
jCtrl.keypress(fnPreventBackspacePropagation);
jCtrl.keydown(fnPreventBackspacePropagation);
jCtrl = $('input[type="password"]');
jCtrl.keypress(fnPreventBackspacePropagation);
jCtrl.keydown(fnPreventBackspacePropagation);
jCtrl = $('textarea');
jCtrl.keypress(fnPreventBackspacePropagation);
jCtrl.keydown(fnPreventBackspacePropagation);
//disable backspace for readonly and disabled
jCtrl = $('input[type="text"][readonly="readonly"]')
jCtrl.keypress(fnPreventBackspace);
jCtrl.keydown(fnPreventBackspace);
jCtrl = $('input[type="text"][disabled="disabled"]')
jCtrl.keypress(fnPreventBackspace);
jCtrl.keydown(fnPreventBackspace);
}
});
</script>
I've been using this in my code for some time now. I write online tests for students and ran into the problem when students were pressing backspace during their test and it would take them back to the login screen. Frustrating! It works on FF for sure.
document.onkeypress = Backspace;
function Backspace(event) {
if (event.keyCode == 8) {
if (document.activeElement.tagName == "INPUT") {
return true;
} else {
return false;
}
}
}
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.
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;
}
}
});
$(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.
You could use a shortcut library to handle the browser specific stuff.
shortcut.add("Ctrl+S",function() {
alert("Hi there!");
});
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;
});
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
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;
}
});
$(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.
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.
#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.
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; });
I like this little plugin. It needs a bit more cross browser friendliness though.
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;
}
});
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/#
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.
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;
}
}
});
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;
});
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.