diff --git a/CHANGES.rst b/CHANGES.rst index ca5e6147..5a57dc47 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -22,6 +22,7 @@ Release History 0.4.4 (unreleased) ================== +- Improvement (Experimental): Nodes have access to the GUI keyboard state - Improvement: support for nengo-bio Connections - Improvement: show multiple connections between objects - Bugfix: handle new Connection transform in Nengo 3.0.0 diff --git a/nengo_gui/components/netgraph.py b/nengo_gui/components/netgraph.py index dc239cb5..811bf4a3 100644 --- a/nengo_gui/components/netgraph.py +++ b/nengo_gui/components/netgraph.py @@ -395,6 +395,7 @@ def message(self, msg): return action = info.get('act', None) undo = info.get('undo', None) + event = info.get('event', None) if action is not None: del info['act'] if action in ('auto_expand', 'auto_collapse'): @@ -416,6 +417,8 @@ def message(self, msg): self.undo() else: self.redo() + elif event is not None: + self.handle_event(event, info) else: print('received message', msg) @@ -718,3 +721,11 @@ def create_connection(self, client, conn, parent): info = dict(uid=uid, pre=pres, post=posts, type='conn', parent=parent, kind=kind) client.write_text(json.dumps(info)) + + def handle_event(self, event, info): + if event == 'keyup': + self.page.keys_pressed.discard(info['key']) + self.page.key_codes_pressed.discard(info['keyCode']) + elif event == 'keydown': + self.page.keys_pressed.add(info['key']) + self.page.key_codes_pressed.add(info['keyCode']) diff --git a/nengo_gui/page.py b/nengo_gui/page.py index 5c4ab54e..863ca411 100644 --- a/nengo_gui/page.py +++ b/nengo_gui/page.py @@ -86,6 +86,9 @@ def __init__(self, gui, filename, settings, reset_cfg=False): self.config_save_time = None # time of last config file save self.config_save_period = 2.0 # minimum time between saves + self.keys_pressed = set() + self.key_codes_pressed = set() + self.lock = threading.Lock() # use the default filename if none is given @@ -211,6 +214,7 @@ def execute(self, code): code_locals = {} code_locals['nengo_gui'] = nengo_gui code_locals['__file__'] = self.filename + code_locals['__page__'] = self self.code = code self.error = None diff --git a/nengo_gui/static/hotkeys.js b/nengo_gui/static/hotkeys.js index d1b0155d..21d96064 100644 --- a/nengo_gui/static/hotkeys.js +++ b/nengo_gui/static/hotkeys.js @@ -15,24 +15,7 @@ Nengo.Hotkeys = function () { var is_editable = (ev.target.tagName === 'INPUT' || ev.target.tagName == 'TEXTAREA'); - if (typeof ev.key != 'undefined') { - var key = ev.key; - } else { - switch (ev.keyCode) { - case 191: - var key = '?'; - break; - case 8: - var key = 'backspace'; - break; - case 13: - var key = 'enter'; - break; - default: - var key = String.fromCharCode(ev.keyCode) - } - } - var key = key.toLowerCase(); + var key = self.determine_key(ev); var ctrl = ev.ctrlKey || ev.metaKey; // toggle editor with ctrl-e @@ -93,8 +76,33 @@ Nengo.Hotkeys = function () { Nengo.ace.update_trigger = true; ev.preventDefault(); } + + if (!is_editable) { + Nengo.netgraph.ws.send(JSON.stringify( + {event:'keydown', + keyCode:ev.keyCode, + key:key + })); + } + } + }); + + document.addEventListener('keyup', function(ev) { + if (self.active) { + + var is_editable = (ev.target.tagName === 'INPUT' || + ev.target.tagName == 'TEXTAREA'); + + if (!is_editable) { + Nengo.netgraph.ws.send(JSON.stringify( + {event:'keyup', + keyCode:ev.keyCode, + key:self.determine_key(ev) + })); + } } }); + } Nengo.Hotkeys.prototype.callMenu = function () { @@ -111,4 +119,27 @@ Nengo.Hotkeys.prototype.set_active = function(bool) { this.active = bool; } +Nengo.Hotkeys.prototype.determine_key = function(ev) { + if (typeof ev.key != 'undefined') { + var key = ev.key; + } else { + switch (ev.keyCode) { + case 191: + var key = '?'; + break; + case 8: + var key = 'backspace'; + break; + case 13: + var key = 'enter'; + break; + default: + var key = String.fromCharCode(ev.keyCode) + } + } + + var key = key.toLowerCase(); + return key; +} + Nengo.hotkeys = new Nengo.Hotkeys();