2022-09-28 00:38:36 +02:00
import Debug from '../../conf/Debug' ;
import PlayerData from '../video-data/PlayerData' ;
import ExtensionMode from '../../../common/enums/ExtensionMode.enum' ;
import Logger from '../Logger' ;
import PageInfo from '../video-data/PageInfo' ;
import Settings from '../Settings' ;
import VideoData from '../video-data/VideoData' ;
import EventBus , { EventBusCommand } from '../EventBus' ;
2022-11-20 14:46:01 +01:00
import KbmBase from './KbmBase' ;
2023-01-07 18:57:47 +01:00
import { SiteSettings } from '../settings/SiteSettings' ;
2018-11-14 23:32:37 +01:00
2020-04-13 15:20:29 +02:00
if ( process . env . CHANNEL !== 'stable' ) {
2022-09-28 00:38:36 +02:00
console . info ( "Loading KeyboardHandler" ) ;
2020-04-13 15:20:29 +02:00
}
2022-09-27 01:48:08 +02:00
/ * *
2022-09-27 22:15:01 +02:00
* Handles keypresses and mouse movement .
*
* EventBus commands :
* kbm - enable enables keyboard shortcuts and mouse panning
* kbm - disable disables keyboard shortcuts and mouse panning
* kbm - set - config sets configuration for this module .
2022-09-27 01:48:08 +02:00
* /
2022-11-20 14:46:01 +01:00
export class KeyboardHandler extends KbmBase {
2022-11-20 17:09:08 +01:00
listenFor : string [ ] = [ 'keyup' ] ;
2021-02-20 00:09:17 +01:00
logger : Logger ;
settings : Settings ;
2023-01-07 18:57:47 +01:00
siteSettings : SiteSettings ;
2022-05-06 00:23:15 +02:00
eventBus : EventBus ;
2021-02-20 00:09:17 +01:00
2022-09-28 00:38:36 +02:00
playerElements : HTMLElement [ ] = [ ] ;
2022-09-27 01:48:08 +02:00
allowShortcuts : boolean = true ;
2021-02-20 00:09:17 +01:00
inputs : string [ ] = [ 'input' , 'select' , 'button' , 'textarea' ] ;
2021-03-06 02:53:58 +01:00
keyboardLocalDisabled : boolean = false ;
2021-02-20 00:09:17 +01:00
2022-09-27 01:48:08 +02:00
mouseMoveActions : any [ ] = [ ] ;
keypressActions : any [ ] = [ ] ;
eventBusCommands : { [ x : string ] : EventBusCommand } = {
2022-11-20 17:09:08 +01:00
2022-09-27 01:48:08 +02:00
}
2022-05-06 00:23:15 +02:00
2022-09-27 01:48:08 +02:00
//#region lifecycle
2023-01-07 18:57:47 +01:00
constructor ( eventBus : EventBus , siteSettings : SiteSettings , settings : Settings , logger : Logger ) {
super ( eventBus , siteSettings , settings , logger ) ;
2022-05-06 00:23:15 +02:00
this . init ( ) ;
2018-11-14 23:32:37 +01:00
}
init() {
2022-09-28 00:38:36 +02:00
this . logger . log ( 'info' , 'debug' , "[KeyboardHandler::init] starting init" ) ;
2018-11-18 18:44:44 +01:00
2022-05-06 00:23:15 +02:00
// build the action list — but only from actions that have shortcuts assigned
for ( const key in this . settings . active . commands ) {
for ( const command of this . settings . active . commands [ key ] ) {
if ( command . shortcut ) {
2022-09-27 01:48:08 +02:00
this . keypressActions . push ( command ) ;
2018-12-31 03:34:26 +01:00
}
2018-11-14 23:32:37 +01:00
}
}
2022-09-27 01:48:08 +02:00
this . load ( ) ;
}
destroy() {
this . removeListener ( ) ;
}
2022-09-28 00:38:36 +02:00
/ * *
* Adds listeners for mouse events , for all player elements associated with the KeyboardHandler instance .
* @param element
* /
addMouseListeners ( element? : HTMLElement ) {
if ( element ) {
this . playerElements . push ( element ) ;
2022-09-27 01:48:08 +02:00
2022-09-28 00:39:49 +02:00
if ( this . settings . active . kbm . mouseEnabled ) {
2022-09-28 00:38:36 +02:00
element . addEventListener ( 'mousemove' , this ) ;
}
} else {
2022-09-28 00:39:49 +02:00
if ( this . settings . active . kbm . mouseEnabled ) {
2022-09-28 00:38:36 +02:00
for ( const playerElement of this . playerElements ) {
playerElement . addEventListener ( 'mousemove' , this ) ;
}
}
}
2022-09-27 01:48:08 +02:00
}
2022-09-28 00:38:36 +02:00
//#endregion
2018-11-14 23:32:37 +01:00
2022-09-28 00:38:36 +02:00
/ * *
* Current instance needs this method for document . addEventListener ( 'keyup' , this ) to work
* @param event
* /
2020-10-21 23:52:16 +02:00
handleEvent ( event ) {
switch ( event . type ) {
2021-11-25 20:00:32 +01:00
case 'keyup' :
2020-10-21 23:52:16 +02:00
this . handleKeyup ( event ) ;
break ;
}
}
2019-06-02 23:54:32 +02:00
setKeyboardLocal ( state ) {
if ( state === ExtensionMode . Enabled ) {
this . keyboardLocalDisabled = false ;
} else if ( state === ExtensionMode . Disabled ) {
this . keyboardLocalDisabled = true ;
}
// don't do shit on invalid value of state
}
2019-10-27 23:37:13 +01:00
preventAction ( event ) {
2018-11-14 23:32:37 +01:00
var activeElement = document . activeElement ;
2020-01-30 01:06:02 +01:00
if ( this . logger . canLog ( 'keyboard' ) ) {
2019-07-18 21:25:58 +02:00
this . logger . pause ( ) ; // temp disable to avoid recursing;
2020-01-30 01:06:02 +01:00
const preventAction = this . preventAction ( event ) ;
2019-10-27 23:37:13 +01:00
this . logger . resume ( ) ; // undisable
2022-09-28 00:38:36 +02:00
this . logger . log ( 'info' , 'keyboard' , "[KeyboardHandler::preventAction] Testing whether we're in a textbox or something. Detailed rundown of conditions:\n" +
2018-11-15 00:18:41 +01:00
"\nis tag one of defined inputs? (yes->prevent):" , this . inputs . indexOf ( activeElement . tagName . toLocaleLowerCase ( ) ) !== - 1 ,
2018-11-14 23:32:37 +01:00
"\nis role = textbox? (yes -> prevent):" , activeElement . getAttribute ( "role" ) === "textbox" ,
"\nis type === 'text'? (yes -> prevent):" , activeElement . getAttribute ( "type" ) === "text" ,
2019-10-27 23:37:13 +01:00
"\nevent.target.isContentEditable? (yes -> prevent):" , event . target . isContentEditable ,
2019-06-02 23:54:32 +02:00
"\nis keyboard local disabled? (yes -> prevent):" , this . keyboardLocalDisabled ,
2023-01-07 18:57:47 +01:00
// "\nis keyboard enabled in settings? (no -> prevent)", this.settings.keyboardShortcutsEnabled(window.location.hostname),
2019-10-27 23:37:13 +01:00
"\nwill the action be prevented? (yes -> prevent)" , preventAction ,
2018-11-14 23:32:37 +01:00
"\n-----------------{ extra debug info }-------------------" ,
"\ntag name? (lowercase):" , activeElement . tagName , activeElement . tagName . toLocaleLowerCase ( ) ,
"\nrole:" , activeElement . getAttribute ( 'role' ) ,
"\ntype:" , activeElement . getAttribute ( 'type' ) ,
2019-10-27 23:37:13 +01:00
"\ninsta-fail inputs:" , this . inputs ,
"\nevent:" , event ,
"\nevent.target:" , event . target
2018-11-14 23:32:37 +01:00
) ;
}
2019-06-02 23:54:32 +02:00
if ( this . keyboardLocalDisabled ) {
return true ;
}
2023-01-07 18:57:47 +01:00
// if (!this.settings.keyboardShortcutsEnabled(window.location.hostname)) {
// return true;
// }
2018-11-14 23:32:37 +01:00
if ( this . inputs . indexOf ( activeElement . tagName . toLocaleLowerCase ( ) ) !== - 1 ) {
return true ;
2021-11-25 20:00:32 +01:00
}
2018-11-14 23:32:37 +01:00
if ( activeElement . getAttribute ( "role" ) === "textbox" ) {
return true ;
}
2019-10-27 23:37:13 +01:00
if ( event . target . isContentEditable ) {
return true ;
}
2018-11-14 23:32:37 +01:00
if ( activeElement . getAttribute ( "type" ) === "text" ) {
return true ;
}
return false ;
}
2022-05-06 00:23:15 +02:00
ghettoLocalizeKeyboardEvent ( event : KeyboardEvent ) {
const realKey = event . key . toLocaleUpperCase ( ) ;
const isLatin = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' . indexOf ( realKey ) !== - 1 ;
if ( ! isLatin ) {
return event ;
}
const nativeKey = event . code . substring ( 3 ) ;
if ( nativeKey !== realKey ) {
return {
. . . event ,
code : ` Key ${ realKey } `
} ;
}
return event ;
}
2019-10-22 01:33:56 +02:00
isLatin ( key ) {
2022-05-06 00:23:15 +02:00
return 'abcdefghijklmnopqrstuvwxyz1234567890' . indexOf ( key . toLocaleLowerCase ( ) ) !== - 1 ;
2019-10-22 01:33:56 +02:00
}
isActionMatchStandard ( shortcut , event ) {
2018-11-14 23:32:37 +01:00
return shortcut . key === event . key &&
shortcut . ctrlKey === event . ctrlKey &&
shortcut . metaKey === event . metaKey &&
shortcut . altKey === event . altKey &&
shortcut . shiftKey === event . shiftKey
}
2019-10-23 19:34:58 +02:00
isActionMatchKeyCode ( shortcut , event ) {
return shortcut . code === event . code &&
2019-10-22 01:33:56 +02:00
shortcut . ctrlKey === event . ctrlKey &&
shortcut . metaKey === event . metaKey &&
shortcut . altKey === event . altKey &&
shortcut . shiftKey === event . shiftKey
}
isActionMatch ( shortcut , event , isLatin = true ) {
2019-10-23 19:34:58 +02:00
// ASCII and symbols fall back to key code matching, because we don't know for sure that
2019-10-22 01:33:56 +02:00
// regular matching by key is going to work
2021-11-25 20:00:32 +01:00
return isLatin ?
this . isActionMatchStandard ( shortcut , event ) :
2019-10-23 19:34:58 +02:00
this . isActionMatchStandard ( shortcut , event ) || this . isActionMatchKeyCode ( shortcut , event ) ;
2019-10-22 01:33:56 +02:00
}
2018-11-14 23:32:37 +01:00
2018-12-02 23:51:34 +01:00
2018-11-14 23:32:37 +01:00
handleKeyup ( event ) {
2022-09-28 01:18:58 +02:00
// if (!this.keyboardEnabled) {
// this.logger.log('info', 'keyboard', "%c[KeyboardHandler::handleKeyup] kbmHandler.keyboardEnabled is set to false. Doing nothing.");
// return;
// }
2022-09-28 00:38:36 +02:00
this . logger . log ( 'info' , 'keyboard' , "%c[KeyboardHandler::handleKeyup] we pressed a key: " , "color: #ff0" , event . key , " | keyup: " , event . keyup , "event:" , event ) ;
2018-11-14 23:32:37 +01:00
2021-08-24 02:13:05 +02:00
try {
if ( this . preventAction ( event ) ) {
2022-09-28 00:38:36 +02:00
this . logger . log ( 'info' , 'keyboard' , "[KeyboardHandler::handleKeyup] we are in a text box or something. Doing nothing." ) ;
2021-08-24 02:13:05 +02:00
return ;
}
2018-11-14 23:32:37 +01:00
2022-09-28 00:38:36 +02:00
this . logger . log ( 'info' , 'keyboard' , "%c[KeyboardHandler::handleKeyup] Trying to find and execute action for event. Actions/event: " , "color: #ff0" , this . keypressActions , event ) ;
2018-11-15 00:18:41 +01:00
2022-05-06 00:23:15 +02:00
const isLatin = this . isLatin ( event . key ) ;
2018-11-15 00:18:41 +01:00
2022-09-27 01:48:08 +02:00
for ( const command of this . keypressActions ) {
2022-05-06 00:23:15 +02:00
if ( this . isActionMatch ( command . shortcut , event , isLatin ) ) {
2022-07-31 01:12:54 +02:00
this . eventBus . send ( command . action , command . arguments ) ;
2022-05-06 00:23:15 +02:00
}
2021-08-24 02:13:05 +02:00
}
} catch ( e ) {
2022-09-28 00:38:36 +02:00
this . logger . log ( 'info' , 'debug' , '[KeyboardHandler::handleKeyup] Failed to handle keyup!' , e ) ;
2021-08-24 02:13:05 +02:00
}
2018-11-14 23:32:37 +01:00
}
2018-12-30 23:41:44 +01:00
}
2020-04-13 15:20:29 +02:00
if ( process . env . CHANNEL !== 'stable' ) {
2022-09-28 00:38:36 +02:00
console . info ( "KeyboardHandler loaded" ) ;
2020-04-13 15:20:29 +02:00
}
2022-09-28 00:38:36 +02:00
export default KeyboardHandler ;