1
1
mirror of https://github.com/Eugeny/tabby.git synced 2024-12-02 11:44:01 +03:00

hotkey handling fixes

This commit is contained in:
Eugene Pankov 2021-08-06 09:43:54 +02:00
parent 426606ba06
commit 08f1ad4c75
No known key found for this signature in database
GPG Key ID: 5896FCBBDD1CF4F4

View File

@ -64,6 +64,7 @@ export class HotkeysService {
private pressedKeystroke: Keystroke|null = null private pressedKeystroke: Keystroke|null = null
private lastKeystrokes: PastKeystroke[] = [] private lastKeystrokes: PastKeystroke[] = []
private shouldSaveNextKeystroke = true private shouldSaveNextKeystroke = true
private lastEventTimestamp = 0
private constructor ( private constructor (
private zone: NgZone, private zone: NgZone,
@ -75,12 +76,10 @@ export class HotkeysService {
events.forEach(eventType => { events.forEach(eventType => {
document.addEventListener(eventType, (nativeEvent: KeyboardEvent) => { document.addEventListener(eventType, (nativeEvent: KeyboardEvent) => {
this._keyEvent.next(nativeEvent) this._keyEvent.next(nativeEvent)
if (eventType === 'keyup' || document.querySelectorAll('input:focus').length === 0) { this.pushKeyEvent(eventType, nativeEvent)
this.pushKeyEvent(eventType, nativeEvent) if (hostApp.platform === Platform.Web && this.matchActiveHotkey(true) !== null) {
if (hostApp.platform === Platform.Web && this.matchActiveHotkey(true) !== null) { nativeEvent.preventDefault()
nativeEvent.preventDefault() nativeEvent.stopPropagation()
nativeEvent.stopPropagation()
}
} }
}) })
}) })
@ -103,6 +102,10 @@ export class HotkeysService {
* @param nativeEvent event object * @param nativeEvent event object
*/ */
pushKeyEvent (eventName: string, nativeEvent: KeyboardEvent): void { pushKeyEvent (eventName: string, nativeEvent: KeyboardEvent): void {
if (nativeEvent.timeStamp === this.lastEventTimestamp) {
return
}
nativeEvent['event'] = eventName nativeEvent['event'] = eventName
const eventData = { const eventData = {
@ -119,15 +122,13 @@ export class HotkeysService {
for (const [key, time] of this.pressedKeyTimestamps.entries()) { for (const [key, time] of this.pressedKeyTimestamps.entries()) {
if (time < performance.now() - 5000) { if (time < performance.now() - 5000) {
this.pressedKeys.delete(key) this.removePressedKey(key)
this.pressedKeyTimestamps.delete(key)
} }
} }
const keyName = getKeyName(eventData) const keyName = getKeyName(eventData)
if (eventName === 'keydown') { if (eventName === 'keydown') {
this.pressedKeys.add(keyName) this.addPressedKey(eventData)
this.pressedKeyTimestamps.set(keyName, eventData.registrationTime)
this.shouldSaveNextKeystroke = true this.shouldSaveNextKeystroke = true
this.updateModifiers(eventData) this.updateModifiers(eventData)
} }
@ -141,8 +142,7 @@ export class HotkeysService {
}) })
this.shouldSaveNextKeystroke = false this.shouldSaveNextKeystroke = false
} }
this.pressedKeys.delete(keyName) this.removePressedKey(keyName)
this.pressedKeyTimestamps.delete(keyName)
} }
if (this.pressedKeys.size) { if (this.pressedKeys.size) {
@ -151,25 +151,25 @@ export class HotkeysService {
this.pressedKeystroke = null this.pressedKeystroke = null
} }
this.processKeystrokes() const matched = this.matchActiveHotkey()
this.zone.run(() => {
if (matched) {
this.emitHotkeyOn(matched)
} else if (this.pressedHotkey) {
this.emitHotkeyOff(this.pressedHotkey)
}
})
this.zone.run(() => { this.zone.run(() => {
this._key.next(getKeyName(eventData)) this._key.next(getKeyName(eventData))
}) })
}
private updateModifiers (event: KeyEventData) { if (process.platform === 'darwin' && eventData.metaKey && eventName === 'keydown' && !['Ctrl', 'Shift', altKeyName, metaKeyName].includes(keyName)) {
for (const [prop, key] of Object.entries({ // macOS will swallow non-modified keyups if Cmd is held down
ctrlKey: 'Ctrl', this.pushKeyEvent('keyup', nativeEvent)
metaKey: metaKeyName,
altKey: altKeyName,
shiftKey: 'Shift',
})) {
if (!event[prop] && this.pressedKeys.has(key)) {
this.pressedKeys.delete(key)
this.pressedKeyTimestamps.delete(key)
}
} }
this.lastEventTimestamp = nativeEvent.timeStamp
} }
getCurrentKeystrokes (): Keystroke[] { getCurrentKeystrokes (): Keystroke[] {
@ -262,24 +262,31 @@ export class HotkeysService {
).reduce((a, b) => a.concat(b)) ).reduce((a, b) => a.concat(b))
} }
private processKeystrokes () { private updateModifiers (event: KeyEventData) {
const matched = this.matchActiveHotkey() for (const [prop, key] of Object.entries({
this.zone.run(() => { ctrlKey: 'Ctrl',
if (matched) { metaKey: metaKeyName,
this.emitHotkeyOn(matched) altKey: altKeyName,
} else if (this.pressedHotkey) { shiftKey: 'Shift',
this.emitHotkeyOff(this.pressedHotkey) })) {
if (!event[prop] && this.pressedKeys.has(key)) {
this.removePressedKey(key)
} }
}) }
} }
private emitHotkeyOn (hotkey: string) { private emitHotkeyOn (hotkey: string) {
if (this.pressedHotkey) { if (this.pressedHotkey) {
if (this.pressedHotkey === hotkey) {
return
}
this.emitHotkeyOff(this.pressedHotkey) this.emitHotkeyOff(this.pressedHotkey)
} }
console.debug('Matched hotkey', hotkey) if (document.querySelectorAll('input:focus').length === 0) {
this._hotkey.next(hotkey) console.debug('Matched hotkey', hotkey)
this.pressedHotkey = hotkey this._hotkey.next(hotkey)
this.pressedHotkey = hotkey
}
} }
private emitHotkeyOff (hotkey: string) { private emitHotkeyOff (hotkey: string) {
@ -316,4 +323,15 @@ export class HotkeysService {
} }
return keys return keys
} }
private addPressedKey (eventData: KeyEventData) {
const keyName = getKeyName(eventData)
this.pressedKeys.add(keyName)
this.pressedKeyTimestamps.set(keyName, eventData.registrationTime)
}
private removePressedKey (key: KeyName) {
this.pressedKeys.delete(key)
this.pressedKeyTimestamps.delete(key)
}
} }