Detect if shift key is down React Native - javascript

How can I detect if the shift key is currently pressed down? I have a text input, and when the user presses the enter key I only want to submit the form if they are not currently pressing the enter key (same form functionality as Facebook Messenger on desktop).
Here is my text input:
<TextInput
style={styles.input}
placeholder={'Enter message'}
onKeyPress={this.handleKeyPress}
/>
And here is the handler:
handleMessageInputKeyPress(e) {
if(e.nativeEvent.key == "Enter"){
// Now check if the SHIFT key is currently pressed or not...
}
}

You can use event listeners to detect any time a key is pressed (or unpressed), then filter the results for the key you want to use as a conditional. Here's an example using hooks:
const [shiftHeld, setShiftHeld] = useState(false);
function downHandler({key}) {
if (key === 'Shift') {
setShiftHeld(true);
}
}
function upHandler({key}) {
if (key === 'Shift') {
setShiftHeld(false);
}
}
useEffect(() => {
window.addEventListener('keydown', downHandler);
window.addEventListener('keyup', upHandler);
return () => {
window.removeEventListener('keydown', downHandler);
window.removeEventListener('keyup', upHandler);
};
}, []);
This will change the state to true of false depending on whether the shift key is held down or not. Then you can plug that value in anywhere you need it.
Tip: You can use this format to listen for any other key. I had a hard time finding documentation on what the keys are called. If you have trouble finding the key name, implement this code then console log key just before the if statement in the downHandler.
Also, make sure you leave the listeners in a useEffect, otherwise you'll get data leaks.

For those who are still looking for the solution:
It seems the event received by the callback onKeyPress has the following properties:
It's nice to see it also has ctrlKey & altKey.
So the solution would be:
<TextInput
onKeyPress={event => {
if (event.shiftKey && event.key === "Enter"){
// ...
}
}} />

Related

Prevent useState from multiplying eventListeners [duplicate]

So I made this modal https://codesandbox.io/s/amazing-morning-ukxp2?file=/src/components/Modal.js
Whenever you press the esc key, it is suppose to close the modal. I added a message to show each time I press esc.
But if you check the console it prints my messages in multiples of 2x each time, so after a while it will say the message like 100 times
This is the function I'm referring to
function keyPress(e) {
if (e.key === 'Escape' && showModal) {
setShowModal(false);
console.log('I pressed');
}
}
document.addEventListener('keydown', keyPress);
I tried to put it into a useEffect function and add showModal as a dependency, but I couldn't get it to work properly
How would I prevent the keydown event listener from showing so many times in the console when I only want it to trigger when the modal is open and when I press the esc key once?
It seems like every time I re open the modal, it doubles the esc key message.
You need to handle the event listeners (add, removing) inside useEffect hook:
useEffect(() => {
document.addEventListener("keydown", keyPress);
return () => document.removeEventListener("keydown", keyPress);
});
This way, you will subscribe to keyPress function in every lifecycle.
To improve it further, you could wrap keyPress in useCallback hook (to memoize the function in new renders) and add it as a dependency:
const keyPress = useCallback(
(e) => {
if (e.key === "Escape" && showModal) {
setShowModal(false);
console.log("I pressed");
}
},
[setShowModal, showModal]
);
useEffect(() => {
document.addEventListener("keydown", keyPress);
return () => document.removeEventListener("keydown", keyPress);
}, [keyPress]);
Modified codesandbox
useEffect(()=>{
document.addEventListener('keydown', someFunction);
}, []);
the empty array at the end will till react to not refresh the component once loaded

How to detect that keyboard combination pressed in app? [duplicate]

This question already has answers here:
Call function on keydown (Ctrl + Enter) in React
(2 answers)
Closed 2 years ago.
For example, I when press ctrl+s it will call an action to save something; or when I press combination ctrl + z it will undo an action.
I tried to handle onKeyPress event on div but it doesn't work
<div
onKeyDown={() => {
console.log("key press");
}}
>
...
</div>
You can use Javascript to create a function where you record what you have pressed in an array (on keydown) and then on keyup check that array to see if it includes certain key combinations and then return the desired function if the condition is met. Then clear the array after. Like so:
let pressed = [];
document.addEventListener('keydown', function(event) {
pressed.push(event.which);
return (function() {
function checkKeys(key1, key2) {
return pressed.includes(key1) && pressed.includes(key2)
}
document.addEventListener('keyup', function() {
if (checkKeys(17, 90)) { //ctrl + z - insert the keycodes here
// call the UNDO function
} else if (checkKeys(17, 83)) { //ctrl + s - insert the keycodes here
// call the SAVE function
}
pressed = [];
});
})();
});
You can use this website to check what the keycodes are for all the different keys.
Check out a JSFiddle example here. Just make sure you focus on the display window when you press the keys.
you can go with below code:
<div
onKeyDown={(event) => {
if(event.ctrlKey && event.key === "Z") {
console.log("Ctrl+z captured")
}
}}
>
...
</div>

ReactJS - Keydown event . Preventdefault 229

I'm making text editor.
This is demo image what i made
Using contenteditable, I render code to dangerouslySetInnerHTML.
So the component look like this
But like figure1, I can access next to select
( In second figure, it is between </div> here <select ~~>
I want to prevent a user from accessing and writing at that point
But I did not found preventing access method.
So I thought when user write content then check the parent and execute event.preventDefault() except for left arrow and up arrow.
it works well in English and others.
But when I write Korean. PreventDefault is not working.
How can I execute preventDefault in Korean??
handleKeyDown = (event) => {
let key;
if(window.event) {
key = event.keyCode;
} else {
key = event.which; //For Firefox
}
const selection = document.getSelection();
if (selection.anchorNode) {
const check = selection.anchorNode.parentElement;
if (check.className.includes('src-components') && key !==37 && key !== 38) {
event.preventDefault();
event.stopPropagation();
}
}
}
P.S : the event.target.value return undefined.

Effective onBlur for react-data-grid

I'm jumping in on a pretty big React JS project which is using react-data-grid to display a bunch of editable data. Right now, you have to click an Update button to send changes to the server. My task at hand is to create auto-save functionality like so:
User selects cell to edit text
User changes text
User either moves to another cell or clicks away from data-grid
Changes are persisted to the server
Here's what I've tried:
onBlur event on each column. The event will fire, but it seems like the event was attached to a div and not the underlying input control. Therefore, I don't have access to the cell's values at the time this event is fired.
onCellDeselected on the <ReactDataGrid> component itself. It seems like this method is fired immediately upon render, and it only gets fired subsequent times when moving to another cell. If I'm editing the last cell and click away from the data-grid, this callback isn't fired.
Using react-data-grid, how can I effectively gain access to an editable cell's content when the user finishes editing?
The commits on react-data-grid are handled by the EditorContainer. The commit logic is simple. An editor commits a value when:
The editor unmounts
Enter is pressed
Tab is pressed
In some cases when the arrows are pressed (will skip this part is it may not be necessary for you, you can look at the logic for this on the EditorContainer)
Based on that the way I would recommend to do the autosave is:
Create an an EditorWrapper (HOC) the editors where you want auto save to be turned on
const editorWrapper(WrappedEditor) => {
return class EditorWrapper extends Component {
constructor(props) {
base(props);
this._changeCommitted = false;
this.handleKeyDown.bind(this);
}
handleKeyDown({ key, stopPropagation }) {
if (key === 'Tab' || key === 'Enter') {
stopPropagation();
this.save();
this.props.onCommit({ key });
this._changeCommitted = true;
}
// If you need the logic for the arrows too, check the editorContainer
}
save() {
// Save logic.
}
hasEscapeBeenPressed() {
let pressed = false;
let escapeKey = 27;
if (window.event) {
if (window.event.keyCode === escapeKey) {
pressed = true;
} else if (window.event.which === escapeKey) {
pressed = true;
}
}
return pressed;
}
componentWillUnmount() {
if (!this._changeCommitted && !this.hasEscapeBeenPressed()) {
this.save();
}
}
render() {
return (
<div onKeyDown={this.handleKeyDown}>
<WrappedComponent {...this.props} />
</div>);
}
}
}
When exporting you editor just wrap them with the EditorWrapper
const Editor = ({ name }) => <div>{ name }</div>
export default EditorWrapper(Editor);
Use one of the start or stop event callback handlers at the DataGrid level like onCellEditCommit
<DataGrid
onCellEditCommit={({ id, field, value }, event) => {
...
}
/>
or a valueSetter for a single the column definition:
const columns: GridColDef[] = [
{
valueSetter: (params: GridValueSetterParams) => {
// params.row contains the current row model
// params.value contains the entered value
},
},
];
<DataGrid columns={columns} />

Why does Javascript drop keyUp events when the metaKey is pressed on Mac browsers?

On Mac browsers, javascript does not receive keyup events for most keys (other modifier keys seem to be an exception) when the metakey is down. Use this jsfiddle to demonstrate (focus the result area and try something like cmd + x, the x will not receive a keyup event):
http://jsfiddle.net/mUEaV/
I've reproduced this in stable releases for Chrome, FF, Safari and Opera. The same thing does not seem to happen with the control key in Windows 7.
Is the OS hijacking the keyup event? This seems especially strange since commands that use the metakey such as save, find, cut, copy, etcetera all activate on keydown not on keyup, and can be hijacked by the javascript just fine.
It's simply not possible to get the onKeyUp events when meta is used, I learned today. Very unfortunate and difficult to work around. You'll have to emulate them some other way.
Edit: To clarify, this is only on Mac and occurs due to OS level handling of the event. It cannot be overridden. Sorry to be the bearer of bad news.
Although event.metaKey returns false, event.keyCode and event.key are still populated.
document.addEventListener('keyup', function(e) {
console.log(e.metaKey || e.key);
});
Click here then press the Command, Control, or Option keys.
Is the browser window retaining the focus when you press those keys? In windows you can get similar result when pressing windows+R or CTRL+ESC and similar key combinations that make browser to loose focus and that results in missed events.
While keyup events are indeed not available when the meta key is pressed, you can still get keydown events for all keys, as well as keyup events for the meta key itself.
This allows us to just simply keep track of the state of the meta key ourselves, like so:
let metaKeyDown = false;
window.addEventListener("keydown", event => {
if (event.key == 'Meta') { metaKeyDown = true; }
});
window.addEventListener("keyup", event => {
if (event.key == 'Meta') { metaKeyDown = false; }
});
By now additionally checking for the main key, plus cancelling the default behavior with Event.preventDefault() we can easily listen for key combinations (like here e.g. CMD+K) and prevent the browser from handling them:
let metaKeyDown = false;
window.addEventListener("keydown", event => {
if (event.key == 'Meta') { metaKeyDown = true; }
if (event.key == 'k' && metaKeyDown) {
event.preventDefault();
console.log('CMD+K pressed!');
}
});
window.addEventListener("keyup", event => {
if (event.key == 'Meta') { metaKeyDown = false; }
});
(Note the observation of the k key taking place already on keydown.)
Also, please be aware that when used incorrectly, this can break standard browser functionality (e.g. like CMD+C or CMD+R), and lead to poor user experience.
You can create an artificial keyup event by waiting for a certain period after the last keydown event. The only caveat is people will have different repeat rates on their os.
https://jsfiddle.net/u7t43coz/10/
const metaKeyCodes = ["MetaLeft", "MetaRight"];
const shiftKeyCodes = ["ShiftLeft", "ShiftRight"];
const ctrlKeyCodes = ["ControlLeft", "ControlRight"];
const altKeyCodes = ["AltLeft", "AltRight"];
const modifierKeyCodes = [
...metaKeyCodes,
...shiftKeyCodes,
...ctrlKeyCodes,
...altKeyCodes
];
// record which keys are down
const downKeys = new Set()
const artificialKeyUpTimes = {}
function onKeydown(e) {
downKeys.add(e.code);
// do other keydown stuff here
console.log("meta", e.metaKey, e.code, "down")
// check if metaKey is down
if (metaKeyCodes.some(k => downKeys.has(k))) {
downKeys.forEach(dk => {
// we want to exclude modifier keys has they dont repeat
if (!modifierKeyCodes.includes(dk)) {
// fire artificial keyup on timeout
if (!artificialKeyUpTimes[dk])
setTimeout(
() => fireArtificialKeyUp(dk, e),
500
);
artificialKeyUpTimes[dk] = Date.now();
}
});
}
}
function fireArtificialKeyUp(code, e) {
// if enough time has passed fire keyup
if (Date.now() - artificialKeyUpTimes[code] > 100) {
delete artificialKeyUpTimes[code];
//if key is still down, fire keyup
if (downKeys.has(code)) {
const eCode = isNaN(code) ? { code: code } : { keyCode: code };
document.dispatchEvent(
new KeyboardEvent("keyup", { ...e, ...eCode })
);
}
} else {
setTimeout(() => fireArtificialKeyUp(code, e), 100);
}
}
function onKeyup(e) {
downKeys.delete(e.code);
// do keyup stuff here
console.log("meta", e.metaKey, e.code, "up")
}
document.addEventListener("keydown", onKeydown)
document.addEventListener("keyup", onKeyup)

Categories

Resources