tweaking, refactoring and .keyHandler(..) action/event (experimental)...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2017-01-12 21:23:16 +03:00
parent c8645d3f6f
commit 3c4b538b7a
3 changed files with 155 additions and 61 deletions

View File

@ -69,8 +69,8 @@ module.GLOBAL_KEYBOARD2 = {
// handle in next section... // handle in next section...
'(': 'NEXT_SECTION', '(': 'NEXT',
')': 'NEXT_SECTION', ')': 'NEXT',
// zooming... // zooming...
'#1': 'fitScreen', '#1': 'fitScreen',
@ -388,21 +388,6 @@ module.GLOBAL_KEYBOARD2 = {
//---------------------------------------------------------------------
/*/ XXX DEBUG: remove when done...
window.kb = keyboard.Keyboard(
GLOBAL_KEYBOARD,
function checkGlobalMode(mode, keyboard, context){
var pattern = keyboard[mode].pattern
return !pattern
|| pattern == '*'
|| $(keyboard[mode].pattern).length > 0 })
//*/
/*********************************************************************/ /*********************************************************************/
// XXX add loading/storing of kb bindings... // XXX add loading/storing of kb bindings...
@ -429,6 +414,14 @@ var KeyboardActions = actions.Actions({
// the handler by cycling the toggler off and on... // the handler by cycling the toggler off and on...
// NOTE: the target element must be focusable... // NOTE: the target element must be focusable...
'keyboard-event-source': 'window', 'keyboard-event-source': 'window',
// If true enable .keyPressed(..) action calling on keyboard
// activity...
//
// NOTE: if updated the keyboard handler will need to be restarted
// for changes to take effect.
// XXX EXPERIMENTAL
'keyboard-key-pressed-action': false,
}, },
get keybindings(){ get keybindings(){
@ -569,6 +562,8 @@ var KeyboardActions = actions.Actions({
toggleKeyboardHandling: ['- Interface/Keyboard handling', toggleKeyboardHandling: ['- Interface/Keyboard handling',
toggler.Toggler(null, function(_, state){ toggler.Toggler(null, function(_, state){
var that = this
if(state == null){ if(state == null){
return this.__keyboard_handler ? 'on' : 'off' return this.__keyboard_handler ? 'on' : 'off'
} }
@ -591,6 +586,24 @@ var KeyboardActions = actions.Actions({
return true return true
}).bind(this) }).bind(this)
// pass keys pressed to .keyPressed(..) action...
// XXX EXPERIMENTAL...
var keyPressdCall = function(handler){
return that.config['keyboard-key-pressed-action'] ?
function(evt){
var e = that.keyPressed.pre(
that,
[keyboard.joinKey(keyboard.event2key(evt))])
var res = handler.apply(that, arguments)
e.result = res
that.keyPressed.post(that, e)
return res
}
: handler
}
var kb = this.__keyboard_object = var kb = this.__keyboard_object =
this.__keyboard_object this.__keyboard_object
|| keyboard.KeyboardWithCSSModes( || keyboard.KeyboardWithCSSModes(
@ -599,8 +612,6 @@ var KeyboardActions = actions.Actions({
// start/reset keyboard handling... // start/reset keyboard handling...
if(state == 'on'){ if(state == 'on'){
var that = this
// NOTE: the target element must be focusable... // NOTE: the target element must be focusable...
var target = var target =
this.__keyboard_event_source = this.__keyboard_event_source =
@ -611,41 +622,35 @@ var KeyboardActions = actions.Actions({
: $(this.config['keyboard-event-source']) : $(this.config['keyboard-event-source'])
// need to reset... // need to reset...
if(this.__keyboard_handler != null){ this.__keyboard_handler
target.off('keydown', this.__keyboard_handler) && target.off('keydown', this.__keyboard_handler)
}
// make the base handler...
var handler =
keyboard.stoppableKeyboardRepeat(
// XXX EXPERIMENTAL...
keyPressdCall(
keyboard.makeKeyboardHandler(
this.keyboard,
function(k){ window.DEBUG && console.log('KEY:', k) },
this)),
check)
// setup base keyboard for devel, in case something breaks... // setup base keyboard for devel, in case something breaks...
// This branch does not drop keys... // This branch does not drop keys...
if(this.config['max-key-repeat-rate'] < 0 if(this.config['max-key-repeat-rate'] < 0
|| this.config['max-key-repeat-rate'] == null){ || this.config['max-key-repeat-rate'] == null){
//this.ribbons.viewer this.__keyboard_handler = handler
var handler =
this.__keyboard_handler =
keyboard.stoppableKeyboardRepeat(
keyboard.makeKeyboardHandler(
this.keyboard,
//function(){ return that.__keyboard_config },
function(k){ window.DEBUG && console.log('KEY:', k) },
this),
check)
// drop keys if repeating too fast... // drop keys if repeating too fast...
// NOTE: this is done for smoother animations... // NOTE: this is done for smoother animations...
} else { } else {
var handler = handler =
this.__keyboard_handler = this.__keyboard_handler =
keyboard.stoppableKeyboardRepeat(
keyboard.dropRepeatingkeys( keyboard.dropRepeatingkeys(
keyboard.makeKeyboardHandler( handler,
this.keyboard,
//function(){ return that.__keyboard_config },
function(k){ window.DEBUG && console.log(k) },
this),
function(){ function(){
return that.config['max-key-repeat-rate'] return that.config['max-key-repeat-rate'] })
}),
check)
} }
target.keydown(handler) target.keydown(handler)
@ -663,6 +668,21 @@ var KeyboardActions = actions.Actions({
}, },
['on', 'off'])], ['on', 'off'])],
// XXX EXPERIMENTAL: event for actions to be able to handle keys...
// ...not working yet...
// XXX not sure if we need this...
// ...the main reason being that this may be a way to bypass the
// .keyboard handler and config and handle keys within an action
// if overdone this can be a mess...
keyPressed: ['- Interface/Key pressed event',
'This is called by the keyboard handler when a key is pressed, '
+'the key is passed as argument.',
core.notUserCallable(function(key){
// This is the keyboard hook protocol root function
//
// Not for direct use.
})],
// interface stuff... // interface stuff...
@ -715,7 +735,7 @@ var KeyboardActions = actions.Actions({
{ {
not_filtered_out: true, not_filtered_out: true,
// XXX should sections be searchable??? // XXX should sections be searchable???
//not_searchable: true, not_searchable: true,
}) })
.addClass('mode') .addClass('mode')

View File

@ -182,7 +182,12 @@ function event2key(evt){
evt.altKey && key.push('alt') evt.altKey && key.push('alt')
evt.metaKey && key.push('meta') evt.metaKey && key.push('meta')
evt.shiftKey && key.push('shift') evt.shiftKey && key.push('shift')
key.push(code2key(evt.keyCode))
var k = code2key(evt.keyCode)
// add the key if it's not already in, this can happen if we just
// pressed a modifier key...
key.indexOf(k.toLowerCase()) < 0 && key.push(k)
return key return key
} }
@ -241,6 +246,12 @@ function splitKey(key){
.concat(sep.indexOf(key.slice(-1)) >= 0 ? key.slice(-1) : []) .concat(sep.indexOf(key.slice(-1)) >= 0 ? key.slice(-1) : [])
.filter(function(c){ return c != '' }) } .filter(function(c){ return c != '' }) }
var joinKey =
module.joinKey =
function joinKey(key){
return key instanceof Array ?
key.join(KEY_SEPARATORS[0] || '+')
: key }
// Normalize key string/array... // Normalize key string/array...
// //
@ -276,7 +287,7 @@ function normalizeKey(key){
return output == 'array' ? return output == 'array' ?
key key
: key.join(KEY_SEPARATORS[0] || '+') : joinKey(key)
} }
@ -305,7 +316,7 @@ function shifted(key){
return s == null ? null return s == null ? null
: output == 'string' ? : output == 'string' ?
res.join(KEY_SEPARATORS[0] || '+') joinKey(res)
: res : res
} }
@ -314,6 +325,63 @@ function shifted(key){
/*********************************************************************/ /*********************************************************************/
// Generic keyboard handler... // Generic keyboard handler...
//
// Key binding format:
// {
// <section-title>: {
// doc: <section-doc>,
//
// // list of keys to drop after this section is done.
// //
// // Setting this to '*' will drop all keys...
// //
// // NOTE: these keys will be handled in current section.
// // NOTE: these keys will not get propagated to the next
// // matching section...
// // NOTE: it is possible to override this and explicitly pass
// // a key to the next section via 'NEXT' (see below).
// drop: [ <key>, ... ] | '*',
//
// // Key mapped to action...
// //
// // NOTE: the system poses no restrictions on action format,
// // but it is recommended to stick to strings or use the
// // doc(..) wrapper...
// <key>: <action>,
//
// // Key mapped to an alias...
// //
// // An alias is any string that is also a key in bindings, it
// // can be just a string or a key, when matching the string of
// // aliases will be resolved till either an action (non-alias)
// // is found or a loop is detected.
// //
// // NOTE: in case of a loop, nothing will get called...
// <key>: <alias> | <key>,
//
// // Alias-action mapping...
// <alias>: <action>,
//
// // Explicitly drop key...
// //
// // NOTE: this is similar in effect to .drop
// <key>: 'DROP',
//
// // Explicitly pass key to next section...
// //
// // This can be useful when it is needed to drop all keys
// // except for a small sub-group, this can be dune by setting
// // .drop to '*' (drop all) and explicitly setting the keys to
// // be propagated to 'NEXT'.
// //
// // NOTE: his takes precedence over .drop
// <key>: 'NEXT',
//
// ...
// },
// ...
// }
//
var KeyboardClassPrototype = { var KeyboardClassPrototype = {
service_fields: ['doc', 'drop'], service_fields: ['doc', 'drop'],
@ -323,6 +391,7 @@ var KeyboardClassPrototype = {
code2key: code2key, code2key: code2key,
isKey: isKey, isKey: isKey,
splitKey: splitKey, splitKey: splitKey,
joinKey: joinKey,
normalizeKey: normalizeKey, normalizeKey: normalizeKey,
shifted: shifted shifted: shifted
} }
@ -331,7 +400,7 @@ var KeyboardPrototype = {
//service_fields: ['doc', 'drop'], //service_fields: ['doc', 'drop'],
special_handlers: { special_handlers: {
DROP: 'drop key', DROP: 'drop key',
NEXT_SECTION: 'handle key in next section', NEXT: 'handle key in next section',
}, },
// Format: // Format:
@ -352,7 +421,7 @@ var KeyboardPrototype = {
// - DROP - drop checking of key // - DROP - drop checking of key
// NOTE: this will prevent handling next sections // NOTE: this will prevent handling next sections
// for this key. // for this key.
// - NEXT_SECTION - force check next section, this has priority // - NEXT - force check next section, this has priority
// over .drop // over .drop
// //
__keyboard: null, __keyboard: null,
@ -372,6 +441,7 @@ var KeyboardPrototype = {
code2key: KeyboardClassPrototype.code2key, code2key: KeyboardClassPrototype.code2key,
shifted: KeyboardClassPrototype.shifted, shifted: KeyboardClassPrototype.shifted,
splitKey: KeyboardClassPrototype.splitKey, splitKey: KeyboardClassPrototype.splitKey,
joinKey: KeyboardClassPrototype.joinKey,
normalizeKey: KeyboardClassPrototype.normalizeKey, normalizeKey: KeyboardClassPrototype.normalizeKey,
isKey: KeyboardClassPrototype.isKey, isKey: KeyboardClassPrototype.isKey,
@ -435,10 +505,10 @@ var KeyboardPrototype = {
mod = mod || [] mod = mod || []
if(key in rev){ if(key in rev){
rev[key].forEach(function(k){ rev[key].forEach(function(k){
k = that.normalizeKey(mod k = that.normalizeKey(
that.joinKey(mod
.concat(that.splitKey(k)) .concat(that.splitKey(k))
.unique() .unique()))
.join(key_separators[0]))
res.indexOf(k) < 0 res.indexOf(k) < 0
&& res.push(k) && res.push(k)
&& walkAliases(res, rev, bindings, k, mod) && walkAliases(res, rev, bindings, k, mod)
@ -688,7 +758,7 @@ var KeyboardPrototype = {
// if key in .drop then ignore the rest... // if key in .drop then ignore the rest...
if(drop if(drop
// explicit go to next section... // explicit go to next section...
&& handler != 'NEXT_SECTION' && handler != 'NEXT'
&& (bindings.drop == '*' && (bindings.drop == '*'
// XXX should this be more flexible by adding a // XXX should this be more flexible by adding a
// specific key combo? // specific key combo?

View File

@ -380,6 +380,10 @@ var BrowserPrototype = {
// keep text editing action from affecting the selection... // keep text editing action from affecting the selection...
drop: '*', drop: '*',
// XXX not sure about this...
Up: 'NEXT',
Down: 'NEXT',
Enter: 'push!', Enter: 'push!',
Esc: 'update!', Esc: 'update!',
}, },
@ -400,8 +404,8 @@ var BrowserPrototype = {
// keep text editing action from affecting the selection... // keep text editing action from affecting the selection...
drop: '*', drop: '*',
Up: 'NEXT_SECTION', Up: 'NEXT',
Down: 'NEXT_SECTION', Down: 'NEXT',
Enter: 'push!', Enter: 'push!',
Esc: 'stopFilter!', Esc: 'stopFilter!',