I'd like to add support for keyboard shortcuts to a couple of pages in my web application by intercepting the keypress event handler of the document object, not the accesskey attribute.
The problem is that every browser has its own keyboard combinations, so it's impossible to come up with a set of keyboard combinations that work on all web browsers and yet consistent.(e.g. It'd be silly if the shortcut for save was Ctrl + Shift + S while one for delete was Alt + D.)
So I figured it would be just simpler to override browser shortcuts altogether in a couple of pages with mine.
All downside aside, is it possible? If so, how do you do it?
onkeydown = function(e){
if(e.ctrlKey && e.keyCode == 'S'.charCodeAt(0)){
e.preventDefault();
//your saving code
}
}
There's an excellent coverage of this here: http://unixpapa.com/js/key.html
As for whether this is something that should be done, stackoverflow's question editor override's quite a few keys without disrupting too much (hover over the toolbar buttons).
Here is my solution to this problem:
Most (if not all) of the browser's shortcuts will be overriden. Only system ones, like Alt + Tab or the Windows key won't.
document.onkeydown = overrideKeyboardEvent;
document.onkeyup = overrideKeyboardEvent;
var keyIsDown = {};
function overrideKeyboardEvent(e){
switch(e.type){
case "keydown":
if(!keyIsDown[e.keyCode]){
keyIsDown[e.keyCode] = true;
// do key down stuff here
}
break;
case "keyup":
delete(keyIsDown[e.keyCode]);
// do key up stuff here
break;
}
disabledEventPropagation(e);
e.preventDefault();
return false;
}
function disabledEventPropagation(e){
if(e){
if(e.stopPropagation){
e.stopPropagation();
} else if(window.event){
window.event.cancelBubble = true;
}
}
}
Here is my Solution:
document.onkeydown = function () {
if ((window.event.keyCode == 121) && (window.event.ctrlKey))) {
window.event.returnValue = false;
window.event.cancelBubble = true;
window.event.keyCode = 0;
return false;
}
}
Related
How could I identify which Ctrl / Shift / Alt keys are pressed in the following code ?
$("#my_id").click(function() {
if (<left control key is pressed>) { alert("Left Ctrl"); }
if (<right shift and left alt keys are pressed>) { alert("Right Shift + Left Alt"); }
});
Well you this wont work in all browsers just IE 8. Microsoft implemented the ability to determine which (right/left) key was pressed. Here is a link http://msdn.microsoft.com/en-us/library/ms534630(VS.85).aspx
I also found this wonder article about keypress, keyup, keydown event in browsers.
http://unixpapa.com/js/key.html
$('#someelement').bind('click', function(event){
if(event.ctrlKey) {
if (event.ctrlLeft) {
console.log('ctrl-left');
}
else {
console.log('ctrl-right');
}
}
if(event.altKey) {
if (event.altLeft) {
console.log('alt-left');
}
else {
console.log('alt-right');
}
}
if(event.shiftKey) {
if (event.shiftLeft) {
console.log('shift-left');
}
else
{
console.log('shift-right');
}
}
});
$('#someelement').bind('click', function(event){
if(event.ctrlKey)
console.log('ctrl');
if(event.altKey)
console.log('alt');
if(event.shiftKey)
console.log('shift');
});
I don't know if it's possible to check for left/right keys within a click event, but I don't think it's possible.
e.originalEvent.location returns 1 for left key and 2 for right key. Therefore you can detect which modifier key is pressed like following. Hope this will help you.
var msg = $('#msg');
$(document).keyup(function (e) {
if (e.keyCode == 16) {
if (e.originalEvent.location == 1)
msg.html('Left SHIFT pressed.');
else
msg.html('Right SHIFT pressed.');
} else if (e.keyCode == 17) {
if (e.originalEvent.location == 1)
msg.html('Left CTRL pressed.');
else
msg.html('Right CTRL pressed.');
} else if (e.keyCode == 18) {
if (e.originalEvent.location == 1)
msg.html('Left ALT pressed.');
else
msg.html('Right ALT pressed.');
e.preventDefault(); //because ALT focusout the element
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label>Press modifier key: </label>
<strong id="msg"></strong>
In most instances the ALT, CTRL,and SHIFT key booleans will work to see if those keys were pressed. For example:
var altKeyPressed = instanceOfMouseEvent.altKey
When called upon, it will return true or false. For more info, go to https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/altKey
For future reference, there is also one called metaKey (NS/firefox only) which works when the meta key is pressed.
Just thought I would add an answer appropriate for 2020.
You can now also use MouseEvent.getModifierState() for this - it's supported by most browsers as of time of writing.
document.addEventListener("click", (evn) => {
const shift = evn.getModifierState("Shift");
const ctrl = evn.getModifierState("Control");
const alt = evn.getModifierState("Alt");
console.log("Mouse pressed! Modifiers:");
console.table({shift, ctrl, alt});
});
Caveats:
Notably, this API does not distinguish between left and right modifiers. If you care about that, you are kind of out of luck. But I imagine this only matters for a small number of use cases.
One of the main benefits of this API is that it supports modifiers other than shift, ctrl, and alt. However the specific behaviour is somewhat erratic across different OSes due to innate platform differences. Check here before you use them.
Following my comment, this is possible solution.
To check which specific modifier key is pressed, you can use KeyboardEvent Location (see table support)
To support IE8, fortunately you could use already posted solution.
Now the workaround is to set a global object with relevant properties regarding which modifier keys are held. Other ways without using global object would be possible of course.
Here, i capture event using relevant javascript listener method (jQuery doesn't support capturing phase). We capture event to handle case where keydown/keyup events propagation would be stopped for some reason by already in-use code.
/* global variable used to check modifier keys held */
/* Note: if e.g control left key and control right key are held simultaneously */
/* only first pressed key is handled (default browser behaviour?)*/
window.modifierKeys = (function() {
/* to handle modifier keys except AltGr which is key shortcut for controlRight + alt */
var mKeys = {};
/* to fire keydown event only once per key held*/
var lastEvent, heldKeys = {};
// capture event to avoid any event stopped propagation
document.addEventListener('keydown', function(e) {
if (lastEvent && lastEvent.which == e.which) {
return;
}
lastEvent = e;
heldKeys[e.which] = true;
setModifierKey(e);
}, true);
// capture event to avoid any event stopped propagation
document.addEventListener('keyup', function(e) {
lastEvent = null;
delete heldKeys[e.which];
setModifierKey(e);
}, true);
function setModifierKey(e) {
mKeys.alt = e.altKey;
mKeys.ctrlLeft = e.ctrlKey && e.location === 1;
mKeys.ctrlRight = e.ctrlKey && e.location === 2;
mKeys.shiftLeft = e.shiftKey && e.location === 1;
mKeys.shiftRight = e.shiftKey && e.location === 2;
}
return mKeys;
})();
/* on div click, check for global object */
$('.modifierKey').on('click', function() {
console.log(modifierKeys);
/* for demo purpose */
$('.info').text(function() {
var txt = [];
for (var p in modifierKeys) {
if (modifierKeys[p]) txt.push(p);
}
return txt.toString();
});
})
/* for demo purpose */
.info:not(:empty) {
border: 1px solid red;
padding: .1em .5em;
font-weight: bold;
}
.info:not(:empty):after {
content: " held";
font-weight: normal;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="modifierKey" tabindex="-1">
DIV to catch modifier keys on click
</div>
<br>
<span class="info"></span>
As side notes:
ALT GR key is a shortcut key for CTRL-Right & ALT
keys
holding simultaneously two indentical modifier keys (e.g Shift-Left &
Shift-Rigth keys), would result in only first one to be handled
(seems like default browser behaviour, so anyway, seems right!)
Use js-hotkeys. It is a jQuery plugin.
This is a test to show what you are looking for. It also shows you how to capture left, right, up, down keys standard and those from numeric key pad (the one with numbers 2,4,6,8)!
http://afro.systems.googlepages.com/test-static-08.html
Easier than anything: you use keydown event to check if it's Ctrl (17) or Shift (16), you then use keyup event to check if it's Enter (13) and Ctrl or Shift hit before (on key down)
cancel Ctrl or Shift on any keyup but Enter
Works like a charm! and on Chrome, Firefox, IE, and Edge too ;) https://jsfiddle.net/55g5utsk/2/
var a=[];
function keyName(p){
var cases = {16:'Shift',17:'CTRL',18:'Alt'};
return cases[p] ? cases[p] : 'KeyCode: '+p;
}
function keyPosition(p){
var cases = {1:'Left',2:'Right'};
return cases[p] ? cases[p]+' ' : '';
}
$('input').on('keydown',function(e){
a.push(keyPosition(e.originalEvent.location)+keyName(e.keyCode));
})
$('input').on('keyup',function(){
var c='';
var removeDuplicates = [];
$.each(a, function(i, el){
if ($.inArray(el, removeDuplicates) === -1) {
removeDuplicates.push(el);
c=c+(el)+' + ';
}
});
a=[];
alert(c.slice(0, -3))
});
Following, a version with the click event
http://jsfiddle.net/2pL0tzx9/
var a=[];
function keyName(p){
var cases = {16:'Shift',17:'CTRL',18:'Alt'};
return cases[p] ? cases[p] : '';
}
function keyPosition(p){
var cases = {1:'Left',2:'Right'};
return cases[p] ? cases[p]+' ' : '';
}
$(document).on('keydown',function(e){
a.push(keyPosition(e.originalEvent.location)+keyName(e.keyCode));
})
$('#my_id').on('click',function(){
var c='';
var removeDuplicates = [];
a =a.filter(function(v){return v!==''});
$.each(a, function(i, el){
if ($.inArray(el, removeDuplicates) === -1){
removeDuplicates.push(el);
c=c+(el)+' + ';
}
});
if (c) alert(c.slice(0, -3));
a=[];
});
There are some reasons that right and left CTRL,SHIFT & ALT keys are not distinguishable because
1. keyCodes are same
2. Many laptop keyboards may not have two control keys
Taken a Reference :
How can I tell if an event comes from right Ctrl key?
I'm trying to disable Ctrl+o key combination in IE, the following code works fine in all IE versions except IE 11 unless I do an alert as you see in code below:
document.onkeydown = function(event) {
var x = event.keyCode;
console.log(event.keyCode);
console.log(event.ctrlKey);
if ((x == 79) && (event.ctrlKey)) {
if(navigator.userAgent.match(/rv:11.0/i)){
alert('Disabled');
}
event.cancelBubble = true;
event.returnValue = false;
event.keyCode = 0;
event.stopPropagation();
event.preventDefault();
return false;
}
};
I was wondering if anyone else is experiencing the same issue and they have solved it. :-)
Thanks.
Alex
I have no good solution unfortunately, but have created a case with Microsoft, and made a jfiddle that demonstrates the issue.
The only way we have found around this is the use of the:
<meta http-equiv="X-UA-Compatible" content="IE=7">
header, but there's no telling when support for that will go away - not to mention the obvious side-effects of running in IE7 mode.
Some additional notes:
Although the interception works natively on IE8 and IE9, only the IE=7 UA mode works
A page reload is required for the header to take effect, whether it is in the page or returned in the server response i.e. you cannot selectively jump in an out of IE7 mode in a single page app
Here is a link to the standards that IE11 was built against: http://www.w3.org/TR/DOM-Level-3-Events/#KeyboardEvent-supplemental-interface
Fiddle:
http://jsfiddle.net/bw5sLd15/1/
// The kitchen sink
function killKey( event ) {
event.cancelBubble = true;
event.bubbles = false;
event.returnValue = false;
event.stopPropagation();
event.stopImmediatePropagation();
event.preventDefault();
return false;
}
I came to the same conclusion as Alex & Max. In my specific use case, forcing compatibility mode would break other features.
I believe that in most cases a confirm dialog is the best workaround, as it still feels somewhat natural to the user - save for the extra step involved.
http://jsfiddle.net/dperish/sp72c0wt/3/
HTML:
<h1>Demonstration of IE11 event bubbling issue</h1>
<label>Enable Workaround<input type="checkbox" id="enableWorkaround"></label>
<p>Pressing CTRL-P or CTRL-O should NOT show the default open/print dialogs. The only workaround seems to be to interrupt the main thread either with alert(), confirm(), or by hitting a breakpoint in a debugger. </p>
<p>Unfortunately, a synchronous/blocking XHR call was not useful for this purpose. Nor was using the browser-specific showModalDialog.</p>
<div id="output"></div>
Javascript:
function onKeyDown(e) {
e = e || window.event;
if ((e.keyCode === 79 || e.keyCode === 80) && e.ctrlKey) {
e.preventDefault();
e.stopPropagation();
e.returnValue = false;
if ($("#enableWorkaround").is(":checked")) {
if (confirm("Run some custom method?")) {
customMethod(e.keyCode);
}
}
else {
customMethod(e.keyCode);
}
return false;
}
}
function customMethod(x) {
$("#output").append("<p>CustomMethod Says: KeyCode = " + x + "</p>");
return false;
}
$(document).ready(function() {
$(document).on("keydown", function (e) {
onKeyDown(e);
});
});
My requirement is just easy: user press Ctrl key some notification appear on my page, and when released the notifications just disappear, so i need to track modifier keys such as Ctrl. Unfortunately i google and didn't find any clues, some famous keyboard libs such as Mousetrap and keymaster seem also does not cover this topic.
Any ideas?
Modifier keys trigger keydown (but not keypress). Then you can simply check the flags defined on the event object. shiftKey, altKey, ctrlKey, metaKey, etc.
A full list is here: http://api.jquery.com/category/events/event-object/
With jQuery, you can just use the keydown and keyup event handlers and you will see the Ctrl key go down and up. If you want to keep track of whether it's down or up, then just set a global flag when it goes down and clear the flag when it goes up.
Example code:
$(document).keydown(function(e) {
if (e.which == 17) {
$("#result").append("ctrl key pressed<br>");
}
});
JQuery doc on e.which: http://api.jquery.com/event.which/
Working demo: http://jsfiddle.net/jfriend00/mezwF/
Try this-
var ctrlKey = false;
window.onkeydown = function(e) {
if(e.keyCode == 17) {
ctrlKey = true;
}
};
window.onkeyup = function(e) {
if(e.keyCode == 17) {
ctrlKey = false;
}
};
function notify() {
if(ctrlKey) {
$('#notification').show();
} else {
$('#notification').hide();
}
}
function main() {
var _inter = setInterval(notify, 100);
}
main();
ok... I might be a lazy one to search but it is a bit annoying that all I can find is
"how can i set scroll down event" when I searched "how do i prevent scroll down".
in my javascript code, I set event for down arrow key. When I press down arrow
from the browser, the browser not only does an event I set, but also does
scrolling down the page which is not I intended to. So here is my question.
How can I disable scroll down function which occurs when I press down arrow?
any help will be appreciated.
If you want to prevent the vertical scrollbar and any vertical scrolling action by the user, you can use this javascript:
document.body.style.overflowY = "hidden";
Or, this can also be set with a CSS rule:
body {overflow-y: hidden;}
On the other hand, if what you're trying to do is to prevent the default key handler for the down arrow from doing anything after you process the down array, then you need to call e.preventDefault() like this:
function myKeyDownHandler(e) {
// your code here
e = e || window.event;
if (e.preventDefault) {
e.preventDefault();
} else {
e.returnValue = false; // older versions of IE (yuck)
}
return false;
}
A cleaner way if you need to do this in more than one place would be to make your own cross browser function for this:
function preventDefault(e) {
e = e || window.event;
if (e.preventDefault) {
e.preventDefault();
} else {
e.returnValue = false; // older versions of IE (yuck)
}
}
function myKeyDownHandler(e) {
// your code here
preventDefault(e);
return false;
}
This is one of those perfect examples where a cross-browser framework (jQuery/YUI/etc) saves you time because they've already done all this cross-browser work for you.
Here's an interesting article on preventDefault and stopPropagation().
Here is an example page that doesn't allow for the use of the arrow keys for scrolling:
<script>
document.onkeydown = function(evt) {
evt = evt || window.event;
var keyCode = evt.keyCode;
if (keyCode >= 37 && keyCode <= 40) {
return false;
}
};
</script>
<body style="height:3000px;">
</body>
How could I identify which Ctrl / Shift / Alt keys are pressed in the following code ?
$("#my_id").click(function() {
if (<left control key is pressed>) { alert("Left Ctrl"); }
if (<right shift and left alt keys are pressed>) { alert("Right Shift + Left Alt"); }
});
Well you this wont work in all browsers just IE 8. Microsoft implemented the ability to determine which (right/left) key was pressed. Here is a link http://msdn.microsoft.com/en-us/library/ms534630(VS.85).aspx
I also found this wonder article about keypress, keyup, keydown event in browsers.
http://unixpapa.com/js/key.html
$('#someelement').bind('click', function(event){
if(event.ctrlKey) {
if (event.ctrlLeft) {
console.log('ctrl-left');
}
else {
console.log('ctrl-right');
}
}
if(event.altKey) {
if (event.altLeft) {
console.log('alt-left');
}
else {
console.log('alt-right');
}
}
if(event.shiftKey) {
if (event.shiftLeft) {
console.log('shift-left');
}
else
{
console.log('shift-right');
}
}
});
$('#someelement').bind('click', function(event){
if(event.ctrlKey)
console.log('ctrl');
if(event.altKey)
console.log('alt');
if(event.shiftKey)
console.log('shift');
});
I don't know if it's possible to check for left/right keys within a click event, but I don't think it's possible.
e.originalEvent.location returns 1 for left key and 2 for right key. Therefore you can detect which modifier key is pressed like following. Hope this will help you.
var msg = $('#msg');
$(document).keyup(function (e) {
if (e.keyCode == 16) {
if (e.originalEvent.location == 1)
msg.html('Left SHIFT pressed.');
else
msg.html('Right SHIFT pressed.');
} else if (e.keyCode == 17) {
if (e.originalEvent.location == 1)
msg.html('Left CTRL pressed.');
else
msg.html('Right CTRL pressed.');
} else if (e.keyCode == 18) {
if (e.originalEvent.location == 1)
msg.html('Left ALT pressed.');
else
msg.html('Right ALT pressed.');
e.preventDefault(); //because ALT focusout the element
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label>Press modifier key: </label>
<strong id="msg"></strong>
In most instances the ALT, CTRL,and SHIFT key booleans will work to see if those keys were pressed. For example:
var altKeyPressed = instanceOfMouseEvent.altKey
When called upon, it will return true or false. For more info, go to https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/altKey
For future reference, there is also one called metaKey (NS/firefox only) which works when the meta key is pressed.
Just thought I would add an answer appropriate for 2020.
You can now also use MouseEvent.getModifierState() for this - it's supported by most browsers as of time of writing.
document.addEventListener("click", (evn) => {
const shift = evn.getModifierState("Shift");
const ctrl = evn.getModifierState("Control");
const alt = evn.getModifierState("Alt");
console.log("Mouse pressed! Modifiers:");
console.table({shift, ctrl, alt});
});
Caveats:
Notably, this API does not distinguish between left and right modifiers. If you care about that, you are kind of out of luck. But I imagine this only matters for a small number of use cases.
One of the main benefits of this API is that it supports modifiers other than shift, ctrl, and alt. However the specific behaviour is somewhat erratic across different OSes due to innate platform differences. Check here before you use them.
Following my comment, this is possible solution.
To check which specific modifier key is pressed, you can use KeyboardEvent Location (see table support)
To support IE8, fortunately you could use already posted solution.
Now the workaround is to set a global object with relevant properties regarding which modifier keys are held. Other ways without using global object would be possible of course.
Here, i capture event using relevant javascript listener method (jQuery doesn't support capturing phase). We capture event to handle case where keydown/keyup events propagation would be stopped for some reason by already in-use code.
/* global variable used to check modifier keys held */
/* Note: if e.g control left key and control right key are held simultaneously */
/* only first pressed key is handled (default browser behaviour?)*/
window.modifierKeys = (function() {
/* to handle modifier keys except AltGr which is key shortcut for controlRight + alt */
var mKeys = {};
/* to fire keydown event only once per key held*/
var lastEvent, heldKeys = {};
// capture event to avoid any event stopped propagation
document.addEventListener('keydown', function(e) {
if (lastEvent && lastEvent.which == e.which) {
return;
}
lastEvent = e;
heldKeys[e.which] = true;
setModifierKey(e);
}, true);
// capture event to avoid any event stopped propagation
document.addEventListener('keyup', function(e) {
lastEvent = null;
delete heldKeys[e.which];
setModifierKey(e);
}, true);
function setModifierKey(e) {
mKeys.alt = e.altKey;
mKeys.ctrlLeft = e.ctrlKey && e.location === 1;
mKeys.ctrlRight = e.ctrlKey && e.location === 2;
mKeys.shiftLeft = e.shiftKey && e.location === 1;
mKeys.shiftRight = e.shiftKey && e.location === 2;
}
return mKeys;
})();
/* on div click, check for global object */
$('.modifierKey').on('click', function() {
console.log(modifierKeys);
/* for demo purpose */
$('.info').text(function() {
var txt = [];
for (var p in modifierKeys) {
if (modifierKeys[p]) txt.push(p);
}
return txt.toString();
});
})
/* for demo purpose */
.info:not(:empty) {
border: 1px solid red;
padding: .1em .5em;
font-weight: bold;
}
.info:not(:empty):after {
content: " held";
font-weight: normal;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="modifierKey" tabindex="-1">
DIV to catch modifier keys on click
</div>
<br>
<span class="info"></span>
As side notes:
ALT GR key is a shortcut key for CTRL-Right & ALT
keys
holding simultaneously two indentical modifier keys (e.g Shift-Left &
Shift-Rigth keys), would result in only first one to be handled
(seems like default browser behaviour, so anyway, seems right!)
Use js-hotkeys. It is a jQuery plugin.
This is a test to show what you are looking for. It also shows you how to capture left, right, up, down keys standard and those from numeric key pad (the one with numbers 2,4,6,8)!
http://afro.systems.googlepages.com/test-static-08.html
Easier than anything: you use keydown event to check if it's Ctrl (17) or Shift (16), you then use keyup event to check if it's Enter (13) and Ctrl or Shift hit before (on key down)
cancel Ctrl or Shift on any keyup but Enter
Works like a charm! and on Chrome, Firefox, IE, and Edge too ;) https://jsfiddle.net/55g5utsk/2/
var a=[];
function keyName(p){
var cases = {16:'Shift',17:'CTRL',18:'Alt'};
return cases[p] ? cases[p] : 'KeyCode: '+p;
}
function keyPosition(p){
var cases = {1:'Left',2:'Right'};
return cases[p] ? cases[p]+' ' : '';
}
$('input').on('keydown',function(e){
a.push(keyPosition(e.originalEvent.location)+keyName(e.keyCode));
})
$('input').on('keyup',function(){
var c='';
var removeDuplicates = [];
$.each(a, function(i, el){
if ($.inArray(el, removeDuplicates) === -1) {
removeDuplicates.push(el);
c=c+(el)+' + ';
}
});
a=[];
alert(c.slice(0, -3))
});
Following, a version with the click event
http://jsfiddle.net/2pL0tzx9/
var a=[];
function keyName(p){
var cases = {16:'Shift',17:'CTRL',18:'Alt'};
return cases[p] ? cases[p] : '';
}
function keyPosition(p){
var cases = {1:'Left',2:'Right'};
return cases[p] ? cases[p]+' ' : '';
}
$(document).on('keydown',function(e){
a.push(keyPosition(e.originalEvent.location)+keyName(e.keyCode));
})
$('#my_id').on('click',function(){
var c='';
var removeDuplicates = [];
a =a.filter(function(v){return v!==''});
$.each(a, function(i, el){
if ($.inArray(el, removeDuplicates) === -1){
removeDuplicates.push(el);
c=c+(el)+' + ';
}
});
if (c) alert(c.slice(0, -3));
a=[];
});
There are some reasons that right and left CTRL,SHIFT & ALT keys are not distinguishable because
1. keyCodes are same
2. Many laptop keyboards may not have two control keys
Taken a Reference :
How can I tell if an event comes from right Ctrl key?