From 35029e92eb1c451f7ba5fb11ce86f29b7c96dbf4 Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Sun, 19 Nov 2023 18:11:13 +0000 Subject: [PATCH 1/8] Added abstract idea --- docs/MDNotes/input/abstracrt.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 docs/MDNotes/input/abstracrt.md diff --git a/docs/MDNotes/input/abstracrt.md b/docs/MDNotes/input/abstracrt.md new file mode 100644 index 00000000..d23df3ec --- /dev/null +++ b/docs/MDNotes/input/abstracrt.md @@ -0,0 +1,28 @@ +# 0.36.0-a +Single Thread, + +``` +TTkInputDriver TTkInput TTK + read() <- stdin + yield inString --> for inString in _readInput.read() + key_process(inString) + inputEvent.emit(kevt, mevt) ----> _processInput + pasteEvent.emit(str) ----> _pasteInput +``` + +# 0.xx.0-a + +multithread +Rework key_process to return kevt,mevt,paste + +``` +TTkInputDriver TTkInput TTK + Thread1 Thread2 (mainn) + read() <- stdin + yield inString --> for inString in _readInput.read() + kevt,mevt,paste = key_process(inString) + queue.put(kevt,mevt,paste) + + queue.get() + inputEvent.emit(kevt, mevt) ------> _processInput + pasteEvent.emit(str) ------> _pasteInput +``` From 9523aad6c0ab3c59f4b98f029abfec590977cbbb Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Sun, 19 Nov 2023 23:10:03 +0000 Subject: [PATCH 2/8] Reworked the input routine to exclude multiple dragging events --- TermTk/TTkCore/TTkTerm/input.py | 163 +------------------ TermTk/TTkCore/TTkTerm/input_mono.py | 183 +++++++++++++++++++++ TermTk/TTkCore/TTkTerm/input_thread.py | 213 +++++++++++++++++++++++++ 3 files changed, 398 insertions(+), 161 deletions(-) create mode 100644 TermTk/TTkCore/TTkTerm/input_mono.py create mode 100644 TermTk/TTkCore/TTkTerm/input_thread.py diff --git a/TermTk/TTkCore/TTkTerm/input.py b/TermTk/TTkCore/TTkTerm/input.py index 27ab9141..44a69504 100644 --- a/TermTk/TTkCore/TTkTerm/input.py +++ b/TermTk/TTkCore/TTkTerm/input.py @@ -20,164 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -__all__ = ['TTkInput'] - -import re -from time import time - -import platform - -from ..drivers import TTkInputDriver - -from TermTk.TTkCore.log import TTkLog -from TermTk.TTkCore.constant import TTkK -from TermTk.TTkCore.signal import pyTTkSignal -from TermTk.TTkCore.TTkTerm.term import TTkTerm -from TermTk.TTkCore.TTkTerm.inputkey import TTkKeyEvent -from TermTk.TTkCore.TTkTerm.inputmouse import TTkMouseEvent - - -class TTkInput: - inputEvent = pyTTkSignal(TTkKeyEvent, TTkMouseEvent) - pasteEvent = pyTTkSignal(str) - _pasteBuffer = "" - _bracketedPaste = False - _readInput = None - _leftLastTime = 0 - _midLastTime = 0 - _rightLastTime = 0 - _leftTap = 0 - _midTap = 0 - _rightTap = 0 - _mouse_re = re.compile(r"\033\[<(\d+);(\d+);(\d+)([mM])") - - class Mouse(int): - ON = 0x01 - DIRECT = 0x02 - - @staticmethod - def init(mouse:bool=False, directMouse:bool=False) -> None: - TTkInput._readInput = TTkInputDriver() - TTkTerm.setMouse(mouse, directMouse) - - @staticmethod - def close() -> None: - TTkTerm.setMouse(False, False) - if TTkInput._readInput: - TTkInput._readInput.close() - - @staticmethod - def stop() -> None: - pass - - @staticmethod - def cont() -> None: - if TTkInput._readInput: - TTkInput._readInput.cont() - - @staticmethod - def start() -> None: - for stdinRead in TTkInput._readInput.read(): - TTkInput.key_process(stdinRead) - TTkLog.debug("Close TTkInput") - - @staticmethod - def key_process(stdinRead:str) -> None: - if TTkInput._bracketedPaste: - if stdinRead.endswith("\033[201~"): - TTkInput._pasteBuffer += stdinRead[:-6] - TTkInput._bracketedPaste = False - # due to the CRNL methos (don't ask me why) the terminal - # is substituting all the \n with \r - TTkInput.pasteEvent.emit(TTkInput._pasteBuffer.replace('\r','\n')) - TTkInput._pasteBuffer = "" - else: - TTkInput._pasteBuffer += stdinRead - return - - mevt,kevt = None, None - - if not stdinRead.startswith("\033[<"): - # Key Event - kevt = TTkKeyEvent.parse(stdinRead) - else: - # Mouse Event - m = TTkInput._mouse_re.match(stdinRead) - if not m: - # TODO: Return Error - hex = [f"0x{ord(x):02x}" for x in stdinRead] - TTkLog.error("UNHANDLED (mouse): "+stdinRead.replace("\033","") + " - "+",".join(hex)) - return None, None - code = int(m.group(1)) - x = int(m.group(2))-1 - y = int(m.group(3))-1 - state = m.group(4) - key = TTkMouseEvent.NoButton - evt = TTkMouseEvent.Move - tap = 0 - - def _checkTap(lastTime, tap): - if state=="M": - t = time() - if (t-lastTime) < 0.4: - return t, tap+1 - else: - return t, 1 - return lastTime, tap - - mod = TTkK.NoModifier - if code & 0x10: - code &= ~0x10 - mod |= TTkK.ControlModifier - if code & 0x08: - code &= ~0x08 - mod |= TTkK.AltModifier - - if code == 0x00: - TTkInput._leftLastTime, TTkInput._leftTap = _checkTap(TTkInput._leftLastTime, TTkInput._leftTap) - tap = TTkInput._leftTap - key = TTkMouseEvent.LeftButton - evt = TTkMouseEvent.Press if state=="M" else TTkMouseEvent.Release - elif code == 0x01: - TTkInput._midLastTime, TTkInput._midTap = _checkTap(TTkInput._midLastTime, TTkInput._midTap) - tap = TTkInput._midTap - key = TTkMouseEvent.MidButton - evt = TTkMouseEvent.Press if state=="M" else TTkMouseEvent.Release - elif code == 0x02: - TTkInput._rightLastTime, TTkInput._rightTap = _checkTap(TTkInput._rightLastTime, TTkInput._rightTap) - tap = TTkInput._rightTap - key = TTkMouseEvent.RightButton - evt = TTkMouseEvent.Press if state=="M" else TTkMouseEvent.Release - elif code == 0x20: - key = TTkMouseEvent.LeftButton - evt = TTkMouseEvent.Drag - elif code == 0x21: - key = TTkMouseEvent.MidButton - evt = TTkMouseEvent.Drag - elif code == 0x22: - key = TTkMouseEvent.RightButton - evt = TTkMouseEvent.Drag - elif code == 0x40: - key = TTkMouseEvent.Wheel - evt = TTkMouseEvent.Up - elif code == 0x41: - key = TTkMouseEvent.Wheel - evt = TTkMouseEvent.Down - elif code == 0x23: - evt = TTkMouseEvent.Move - elif code == 0x27: - mod |= TTkK.ShiftModifier - evt = TTkMouseEvent.Move - - mevt = TTkMouseEvent(x, y, key, evt, mod, tap, m.group(0).replace("\033", "")) - if kevt or mevt: - TTkInput.inputEvent.emit(kevt, mevt) - return - - if stdinRead.startswith("\033[200~"): - TTkInput._pasteBuffer = stdinRead[6:] - TTkInput._bracketedPaste = True - return - - hex = [f"0x{ord(x):02x}" for x in stdinRead] - TTkLog.error("UNHANDLED: "+stdinRead.replace("\033","") + " - "+",".join(hex)) +# from .input_mono import * +from .input_thread import * \ No newline at end of file diff --git a/TermTk/TTkCore/TTkTerm/input_mono.py b/TermTk/TTkCore/TTkTerm/input_mono.py new file mode 100644 index 00000000..27ab9141 --- /dev/null +++ b/TermTk/TTkCore/TTkTerm/input_mono.py @@ -0,0 +1,183 @@ +# MIT License +# +# Copyright (c) 2021 Eugenio Parodi +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +__all__ = ['TTkInput'] + +import re +from time import time + +import platform + +from ..drivers import TTkInputDriver + +from TermTk.TTkCore.log import TTkLog +from TermTk.TTkCore.constant import TTkK +from TermTk.TTkCore.signal import pyTTkSignal +from TermTk.TTkCore.TTkTerm.term import TTkTerm +from TermTk.TTkCore.TTkTerm.inputkey import TTkKeyEvent +from TermTk.TTkCore.TTkTerm.inputmouse import TTkMouseEvent + + +class TTkInput: + inputEvent = pyTTkSignal(TTkKeyEvent, TTkMouseEvent) + pasteEvent = pyTTkSignal(str) + _pasteBuffer = "" + _bracketedPaste = False + _readInput = None + _leftLastTime = 0 + _midLastTime = 0 + _rightLastTime = 0 + _leftTap = 0 + _midTap = 0 + _rightTap = 0 + _mouse_re = re.compile(r"\033\[<(\d+);(\d+);(\d+)([mM])") + + class Mouse(int): + ON = 0x01 + DIRECT = 0x02 + + @staticmethod + def init(mouse:bool=False, directMouse:bool=False) -> None: + TTkInput._readInput = TTkInputDriver() + TTkTerm.setMouse(mouse, directMouse) + + @staticmethod + def close() -> None: + TTkTerm.setMouse(False, False) + if TTkInput._readInput: + TTkInput._readInput.close() + + @staticmethod + def stop() -> None: + pass + + @staticmethod + def cont() -> None: + if TTkInput._readInput: + TTkInput._readInput.cont() + + @staticmethod + def start() -> None: + for stdinRead in TTkInput._readInput.read(): + TTkInput.key_process(stdinRead) + TTkLog.debug("Close TTkInput") + + @staticmethod + def key_process(stdinRead:str) -> None: + if TTkInput._bracketedPaste: + if stdinRead.endswith("\033[201~"): + TTkInput._pasteBuffer += stdinRead[:-6] + TTkInput._bracketedPaste = False + # due to the CRNL methos (don't ask me why) the terminal + # is substituting all the \n with \r + TTkInput.pasteEvent.emit(TTkInput._pasteBuffer.replace('\r','\n')) + TTkInput._pasteBuffer = "" + else: + TTkInput._pasteBuffer += stdinRead + return + + mevt,kevt = None, None + + if not stdinRead.startswith("\033[<"): + # Key Event + kevt = TTkKeyEvent.parse(stdinRead) + else: + # Mouse Event + m = TTkInput._mouse_re.match(stdinRead) + if not m: + # TODO: Return Error + hex = [f"0x{ord(x):02x}" for x in stdinRead] + TTkLog.error("UNHANDLED (mouse): "+stdinRead.replace("\033","") + " - "+",".join(hex)) + return None, None + code = int(m.group(1)) + x = int(m.group(2))-1 + y = int(m.group(3))-1 + state = m.group(4) + key = TTkMouseEvent.NoButton + evt = TTkMouseEvent.Move + tap = 0 + + def _checkTap(lastTime, tap): + if state=="M": + t = time() + if (t-lastTime) < 0.4: + return t, tap+1 + else: + return t, 1 + return lastTime, tap + + mod = TTkK.NoModifier + if code & 0x10: + code &= ~0x10 + mod |= TTkK.ControlModifier + if code & 0x08: + code &= ~0x08 + mod |= TTkK.AltModifier + + if code == 0x00: + TTkInput._leftLastTime, TTkInput._leftTap = _checkTap(TTkInput._leftLastTime, TTkInput._leftTap) + tap = TTkInput._leftTap + key = TTkMouseEvent.LeftButton + evt = TTkMouseEvent.Press if state=="M" else TTkMouseEvent.Release + elif code == 0x01: + TTkInput._midLastTime, TTkInput._midTap = _checkTap(TTkInput._midLastTime, TTkInput._midTap) + tap = TTkInput._midTap + key = TTkMouseEvent.MidButton + evt = TTkMouseEvent.Press if state=="M" else TTkMouseEvent.Release + elif code == 0x02: + TTkInput._rightLastTime, TTkInput._rightTap = _checkTap(TTkInput._rightLastTime, TTkInput._rightTap) + tap = TTkInput._rightTap + key = TTkMouseEvent.RightButton + evt = TTkMouseEvent.Press if state=="M" else TTkMouseEvent.Release + elif code == 0x20: + key = TTkMouseEvent.LeftButton + evt = TTkMouseEvent.Drag + elif code == 0x21: + key = TTkMouseEvent.MidButton + evt = TTkMouseEvent.Drag + elif code == 0x22: + key = TTkMouseEvent.RightButton + evt = TTkMouseEvent.Drag + elif code == 0x40: + key = TTkMouseEvent.Wheel + evt = TTkMouseEvent.Up + elif code == 0x41: + key = TTkMouseEvent.Wheel + evt = TTkMouseEvent.Down + elif code == 0x23: + evt = TTkMouseEvent.Move + elif code == 0x27: + mod |= TTkK.ShiftModifier + evt = TTkMouseEvent.Move + + mevt = TTkMouseEvent(x, y, key, evt, mod, tap, m.group(0).replace("\033", "")) + if kevt or mevt: + TTkInput.inputEvent.emit(kevt, mevt) + return + + if stdinRead.startswith("\033[200~"): + TTkInput._pasteBuffer = stdinRead[6:] + TTkInput._bracketedPaste = True + return + + hex = [f"0x{ord(x):02x}" for x in stdinRead] + TTkLog.error("UNHANDLED: "+stdinRead.replace("\033","") + " - "+",".join(hex)) diff --git a/TermTk/TTkCore/TTkTerm/input_thread.py b/TermTk/TTkCore/TTkTerm/input_thread.py new file mode 100644 index 00000000..2e0808a9 --- /dev/null +++ b/TermTk/TTkCore/TTkTerm/input_thread.py @@ -0,0 +1,213 @@ +# MIT License +# +# Copyright (c) 2021 Eugenio Parodi +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +__all__ = ['TTkInput'] + +import re +from time import time + +import threading, queue + +from ..drivers import TTkInputDriver + +from TermTk.TTkCore.log import TTkLog +from TermTk.TTkCore.constant import TTkK +from TermTk.TTkCore.signal import pyTTkSignal +from TermTk.TTkCore.TTkTerm.term import TTkTerm +from TermTk.TTkCore.TTkTerm.inputkey import TTkKeyEvent +from TermTk.TTkCore.TTkTerm.inputmouse import TTkMouseEvent + + +class TTkInput: + inputEvent = pyTTkSignal(TTkKeyEvent, TTkMouseEvent) + pasteEvent = pyTTkSignal(str) + _pasteBuffer = "" + _bracketedPaste = False + _readInput = None + _inputThread = None + _inputQueue = None + _leftLastTime = 0 + _midLastTime = 0 + _rightLastTime = 0 + _leftTap = 0 + _midTap = 0 + _rightTap = 0 + _mouse_re = re.compile(r"\033\[<(\d+);(\d+);(\d+)([mM])") + + class Mouse(int): + ON = 0x01 + DIRECT = 0x02 + + @staticmethod + def init(mouse:bool=False, directMouse:bool=False) -> None: + TTkInput._readInput = TTkInputDriver() + TTkInput._inputThread = threading.Thread(target=TTkInput._run) + TTkInput._inputQueue = queue.Queue() + TTkTerm.setMouse(mouse, directMouse) + + @staticmethod + def close() -> None: + TTkTerm.setMouse(False, False) + if TTkInput._readInput: + TTkInput._readInput.close() + + @staticmethod + def stop() -> None: + pass + + @staticmethod + def cont() -> None: + if TTkInput._readInput: + TTkInput._readInput.cont() + + @staticmethod + def start() -> None: + TTkInput._inputThread.start() + while inq := TTkInput._inputQueue.get(): + kevt,mevt,paste = inq + + # Try to filter out the queued moved mouse events + while (not kevt and + not paste and + mevt and mevt.evt == TTkK.Drag and + not TTkInput._inputQueue.empty() ): + mevtOld = mevt + kevt, mevt, paste = TTkInput._inputQueue.get() + if (kevt or + paste or + mevt and mevt.evt != TTkK.Drag): + TTkInput.inputEvent.emit(kevt, mevtOld) + break + + if kevt or mevt: + TTkInput.inputEvent.emit(kevt, mevt) + if paste: + TTkInput.pasteEvent.emit(paste) + TTkLog.debug("Close TTkInput") + + @staticmethod + def _run(): + for stdinRead in TTkInput._readInput.read(): + outq = TTkInput.key_process(stdinRead) + TTkInput._inputQueue.put(outq) + TTkInput._inputQueue.put(None) + + @staticmethod + def key_process(stdinRead:str) -> None: + if TTkInput._bracketedPaste: + if stdinRead.endswith("\033[201~"): + TTkInput._pasteBuffer += stdinRead[:-6] + TTkInput._bracketedPaste = False + # due to the CRNL methos (don't ask me why) the terminal + # is substituting all the \n with \r + _paste = TTkInput._pasteBuffer.replace('\r','\n') + TTkInput._pasteBuffer = "" + return None, None, _paste + else: + TTkInput._pasteBuffer += stdinRead + return None, None, None + + mevt,kevt = None,None + + if not stdinRead.startswith("\033[<"): + # Key Event + kevt = TTkKeyEvent.parse(stdinRead) + else: + # Mouse Event + m = TTkInput._mouse_re.match(stdinRead) + if not m: + # TODO: Return Error + hex = [f"0x{ord(x):02x}" for x in stdinRead] + TTkLog.error("UNHANDLED (mouse): "+stdinRead.replace("\033","") + " - "+",".join(hex)) + return None, None, None + code = int(m.group(1)) + x = int(m.group(2))-1 + y = int(m.group(3))-1 + state = m.group(4) + key = TTkMouseEvent.NoButton + evt = TTkMouseEvent.Move + tap = 0 + + def _checkTap(lastTime, tap): + if state=="M": + t = time() + if (t-lastTime) < 0.4: + return t, tap+1 + else: + return t, 1 + return lastTime, tap + + mod = TTkK.NoModifier + if code & 0x10: + code &= ~0x10 + mod |= TTkK.ControlModifier + if code & 0x08: + code &= ~0x08 + mod |= TTkK.AltModifier + + if code == 0x00: + TTkInput._leftLastTime, TTkInput._leftTap = _checkTap(TTkInput._leftLastTime, TTkInput._leftTap) + tap = TTkInput._leftTap + key = TTkMouseEvent.LeftButton + evt = TTkMouseEvent.Press if state=="M" else TTkMouseEvent.Release + elif code == 0x01: + TTkInput._midLastTime, TTkInput._midTap = _checkTap(TTkInput._midLastTime, TTkInput._midTap) + tap = TTkInput._midTap + key = TTkMouseEvent.MidButton + evt = TTkMouseEvent.Press if state=="M" else TTkMouseEvent.Release + elif code == 0x02: + TTkInput._rightLastTime, TTkInput._rightTap = _checkTap(TTkInput._rightLastTime, TTkInput._rightTap) + tap = TTkInput._rightTap + key = TTkMouseEvent.RightButton + evt = TTkMouseEvent.Press if state=="M" else TTkMouseEvent.Release + elif code == 0x20: + key = TTkMouseEvent.LeftButton + evt = TTkMouseEvent.Drag + elif code == 0x21: + key = TTkMouseEvent.MidButton + evt = TTkMouseEvent.Drag + elif code == 0x22: + key = TTkMouseEvent.RightButton + evt = TTkMouseEvent.Drag + elif code == 0x40: + key = TTkMouseEvent.Wheel + evt = TTkMouseEvent.Up + elif code == 0x41: + key = TTkMouseEvent.Wheel + evt = TTkMouseEvent.Down + elif code == 0x23: + evt = TTkMouseEvent.Move + elif code == 0x27: + mod |= TTkK.ShiftModifier + evt = TTkMouseEvent.Move + + mevt = TTkMouseEvent(x, y, key, evt, mod, tap, m.group(0).replace("\033", "")) + if kevt or mevt: + return kevt, mevt, None + + if stdinRead.startswith("\033[200~"): + TTkInput._pasteBuffer = stdinRead[6:] + TTkInput._bracketedPaste = True + return None, None, None + + hex = [f"0x{ord(x):02x}" for x in stdinRead] + TTkLog.error("UNHANDLED: "+stdinRead.replace("\033","") + " - "+",".join(hex)) From c2e5caadf700f79b30af23dba16b409848c84602 Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Mon, 20 Nov 2023 23:05:46 +0000 Subject: [PATCH 3/8] Adapted the sandbox to the new input processing --- tests/sandbox/sandbox.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/sandbox/sandbox.html b/tests/sandbox/sandbox.html index 43e32e20..2aad1556 100644 --- a/tests/sandbox/sandbox.html +++ b/tests/sandbox/sandbox.html @@ -238,7 +238,11 @@ import pyodideProxy def ttk_input(val): - TTkInput.key_process(val) + kevt,mevt,paste = TTkInput.key_process(val) + if kevt or mevt: + TTkInput.inputEvent.emit(kevt, mevt) + if paste: + TTkInput.pasteEvent.emit(paste) def ttk_resize(w,h): ttk.TTkLog.debug(f"Resize: {w=} {h=}") From 72f0535ea47a2fec411260ea03d5232abe1e6d5e Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Mon, 20 Nov 2023 23:56:11 +0000 Subject: [PATCH 4/8] Extracted the bacis js routine from the sandbox --- tests/sandbox/js/ttkproxy.js | 205 +++++++++++++++++++++++++++++++++ tests/sandbox/sandbox.new.html | 184 +++++++++++++++++++++++++++++ 2 files changed, 389 insertions(+) create mode 100644 tests/sandbox/js/ttkproxy.js create mode 100644 tests/sandbox/sandbox.new.html diff --git a/tests/sandbox/js/ttkproxy.js b/tests/sandbox/js/ttkproxy.js new file mode 100644 index 00000000..6eff0038 --- /dev/null +++ b/tests/sandbox/js/ttkproxy.js @@ -0,0 +1,205 @@ +/* +MIT License + +Copyright (c) 2023 Eugenio Parodi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +// Declaration +class TTkProxy { + constructor(term) { + this.term = term + } + + pyodideProxy = { + consoleLog: function(m){ + console.log("TTk:",m) + }, + termPush: function (s) { + this.term.write(s); + }, + termSize: function () { + return [this.term.cols, this.term.rows] + }, + setTimeout: function(t, i) { + // console.log("TIME (Start)",i,t) + return setTimeout(() => this.ttk_timer(i), t) + }, + stopTimeout: function(t) { + // console.log("TIME (Stop)",t) + clearTimeout(t) + }, + clearTimeout: function(){ + let highestTimeoutId = setTimeout(";"); + for (let i = 0 ; i < highestTimeoutId ; i++) { + clearTimeout(i); + } + }, + setInterval: function(t, i) { + setTinterval(() => console.log('WIP -> Interval' + i), t) + } + }; + + async init(){ + this.pyodide = await loadPyodide(); + this.ttk_timer = (i) => console.log("ttk_timer unimplemented") + this.term.write('Pyodide ('+this.pyodide.version+') - Loaded\n\r') + + this.pyodide.registerJsModule("pyodideProxy", this.pyodideProxy); + this.term.write('Pyodide Proxy - Loaded\n\r') + } + + async loadLib(lib) { + let zipResponse = await fetch(lib); + let zipBinary = await zipResponse.arrayBuffer(); + this.pyodide.unpackArchive(zipBinary, ".tar.gz"); + } + + async loadFile(fileUri,file){ + this.pyodide.FS.writeFile(this.pyodide.FS.currentPath+file, await (await fetch(fileUri)).text()); + } + + readFile(file){ + return this.pyodide.FS.readFile(file, {encoding:'utf8'}) + } + + currentPath(){ + return this.pyodide.FS.currentPath + } + + getAllFiles(p){ + let ls = this.pyodide.FS.readdir(p) + let ret = [] + for(let i=0 ; i "+val.replace("\\033","") + " - ") + ttk.TTkHelper.paintAll() + + def ttk_clean(): + if ttk.TTkHelper._rootWidget: + ttk.TTkTimer.pyodideQuit() + ttk.TTkHelper._rootWidget.quit() + ttk.TTkHelper._focusWidget = None + ttk.TTkHelper._rootCanvas = None + ttk.TTkHelper._rootWidget = None + ttk.TTkHelper._updateBuffer = set() + ttk.TTkHelper._updateWidget = set() + ttk.TTkHelper._overlay = [] + ttk.TTkHelper._shortcut = [] + ttk.TTkLog._messageHandler = [message_handler] + + def ttk_init(): + ttk.TTkToolTip.toolTipTimer = ttk.TTkTimer() + ttk.TTkToolTip.toolTipTimer.timeout.connect(ttk.TTkToolTip._toolTipShow) + + def message_handler(mode, context, message): + msgType = "DEBUG" + if mode == ttk.TTkLog.InfoMsg: msgType = "[INFO]" + elif mode == ttk.TTkLog.WarningMsg: msgType = "[WARNING]" + elif mode == ttk.TTkLog.CriticalMsg: msgType = "[CRITICAL]" + elif mode == ttk.TTkLog.FatalMsg: msgType = "[FATAL]" + elif mode == ttk.TTkLog.ErrorMsg: msgType = "[ERROR]" + pyodideProxy.consoleLog(f"{msgType} {context.file} {message}") + # Register the callback to the message handler + ttk.TTkLog.installMessageHandler(message_handler) + `,{ globals: this.namespace } + ); + + this.ttk_log = this.namespace.get("ttk_log"); + this.ttk_input = this.namespace.get("ttk_input"); + this.ttk_timer = this.namespace.get("ttk_timer"); + this.ttk_resize = this.namespace.get("ttk_resize"); + this.ttk_clean = this.namespace.get("ttk_clean"); + this.ttk_init = this.namespace.get("ttk_init"); + + this.pyodideProxy.ttk_timer = this.ttk_timer + this.pyodideProxy.term = this.term + + this.term.onResize( (obj) => { + this.term.reset() + this.ttk_resize(obj.cols, obj.rows) + }); + this.term.onData((d, evt) => { this.ttk_input(d) }) + + this.pyodide.runPython(` + import sys,os + sys.path.append(os.path.join(sys.path[0],'demo')) + __name__ = "__main__" + `,{ globals: this.namespace } + ); + } + + run(code,filename,fps) { + this.ttk_clean() + console.log("Run App") + + let pwd = this.pyodide.PATH.dirname(filename) + + this.pyodide.runPython(` + __file__='`+filename+`' + os.chdir('`+pwd+`') + ttk.TTkCfg.maxFps = `+fps,{ globals: this.namespace }) + + this.ttk_init() + + this.pyodide.runPython(code,{ globals: this.namespace }); + + this.ttk_log(filename + " - LOADED") + } +} \ No newline at end of file diff --git a/tests/sandbox/sandbox.new.html b/tests/sandbox/sandbox.new.html new file mode 100644 index 00000000..036f960d --- /dev/null +++ b/tests/sandbox/sandbox.new.html @@ -0,0 +1,184 @@ + + + + Mr. pyTermTk Sandbox + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + \ No newline at end of file From 5a2b90ba20c550fcc935869f345941f0f82d8a5d Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Tue, 21 Nov 2023 00:12:52 +0000 Subject: [PATCH 5/8] adapted standalone sandbox --- tests/sandbox/standalone.html | 151 ++++++---------------------------- 1 file changed, 23 insertions(+), 128 deletions(-) diff --git a/tests/sandbox/standalone.html b/tests/sandbox/standalone.html index 516250cf..4d8dc01b 100644 --- a/tests/sandbox/standalone.html +++ b/tests/sandbox/standalone.html @@ -8,11 +8,16 @@ + + + + + @@ -20,10 +25,13 @@ From 0ac34765cd39de89026d5ccb289b07e313ad9e23 Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Tue, 21 Nov 2023 08:56:10 +0000 Subject: [PATCH 6/8] Removed currentPath reference from the sandboox --- tests/sandbox/sandbox.new.html | 11 +- tests/sandbox/standalone.fullscreen.html | 148 +++-------------------- tests/sandbox/standalone.html | 15 ++- 3 files changed, 27 insertions(+), 147 deletions(-) diff --git a/tests/sandbox/sandbox.new.html b/tests/sandbox/sandbox.new.html index 036f960d..091dc314 100644 --- a/tests/sandbox/sandbox.new.html +++ b/tests/sandbox/sandbox.new.html @@ -156,15 +156,14 @@ fileUri = urlParams.get("fileUri") filePath = urlParams.get("filePath") if (fileUri != null){ - ttkProxy.loadFile(fileUri, ttkProxy.currentPath()+"/test_file.py"); - loadFile(ttkProxy.currentPath()+"/test_file.py") + ttkProxy.loadFile(fileUri, "test_file.py"); + loadFile("test_file.py") }else if (filePath != null){ - loadFile(ttkProxy.currentPath()+"/"+filePath) + loadFile(filePath) }else{ - loadFile(ttkProxy.currentPath()+"/demo/demo.py") + loadFile("demo/demo.py") } - //loadFile("/home/pyodide/tutorial/calculator/calculator.005.py") - w2ui.sidebar.select(ttkProxy.currentPath()+"/demo/demo.py") + w2ui.sidebar.select("demo/demo.py") term.write('Starting Demo...\n\r') diff --git a/tests/sandbox/standalone.fullscreen.html b/tests/sandbox/standalone.fullscreen.html index 1569d98c..718f234f 100644 --- a/tests/sandbox/standalone.fullscreen.html +++ b/tests/sandbox/standalone.fullscreen.html @@ -10,11 +10,14 @@ + + + + @@ -37,148 +40,27 @@ term.write('xterm.js - Loaded\n\r') - window.addEventListener('resize', (event) => { - setTimeout(()=>{fitAddon.fit()},0.5) - }); + fitAddon.fit() /* pyodide demo */ - var pyodide = null - var run = null - var namespace = null async function main(){ - pyodide = await loadPyodide(); - - let pyodideProxy = { - consoleLog: function(m){ - console.log("TTk:",m) - }, - termPush: function (s) { - term.write(s); - }, - termSize: function () { - return [term.cols, term.rows] - }, - setTimeout: function(t, i) { - // console.log("TIME",i,t) - setTimeout(() => ttk_timer(i), t) - }, - clearTimeout: function(){ - let highestTimeoutId = setTimeout(";"); - for (let i = 0 ; i < highestTimeoutId ; i++) { - clearTimeout(i); - } - }, - setInterval: function(t, i) { - setTinterval(() => console.log('WIP -> Interval' + i), t) - } - }; - pyodide.registerJsModule("pyodideProxy", pyodideProxy); - - term.write('Pyodide Proxy - Loaded\n\r') - - let zipResponse = await fetch("bin/TermTk.tgz"); - let zipBinary = await zipResponse.arrayBuffer(); - pyodide.unpackArchive(zipBinary, ".tar.gz"); + ttkProxy = new TTkProxy(term) + await ttkProxy.init() + await ttkProxy.loadLib("bin/TermTk.tgz"); term.write('TermTk - Loaded\n\r') - zipResponse = await fetch("bin/demo.tgz"); - zipBinary = await zipResponse.arrayBuffer(); - pyodide.unpackArchive(zipBinary, ".tar.gz"); - + await ttkProxy.loadLib("bin/demo.tgz"); term.write('Demos - Loaded\n\r') term.write('Starting Demo...\n\r') - namespace = pyodide.globals.get("dict")(); - pyodide.runPython(` - import sys - import TermTk as ttk - import pyodideProxy - - def ttk_input(val): - if ttk.TTkHelper._rootWidget and ttk.TTkHelper._rootWidget._input: - ttk.TTkHelper._rootWidget._input.key_process(val) - - def ttk_resize(w,h): - ttk.TTkLog.debug(f"Resize: {w=} {h=}") - if ttk.TTkHelper._rootWidget: - ttk.TTkHelper._rootWidget._win_resize_cb(w,h) - ttk.TTkHelper.rePaintAll() - # TODO: I need to get rid of this: - ttk.TTkTerm.push(ttk.TTkTerm.ALT_SCREEN + ttk.TTkTerm.CLEAR + ttk.TTkTerm.Cursor.HIDE + ttk.TTkTerm.escTitle(ttk.TTkTerm.title)) - ttk.TTkTerm.push(ttk.TTkTerm.Mouse.ON) - - def ttk_timer(tid): - ttk.TTkTimer.triggerTimerId(tid) - - def ttk_log(val): - # hex = [f"0x{ord(x):02x}" for x in val] - ttk.TTkLog.debug("---> "+val.replace("\\033","") + " - ") - ttk.TTkHelper.paintAll() - - def ttk_clean(): - if ttk.TTkHelper._rootWidget: - ttk.TTkTimer.pyodideQuit() - ttk.TTkHelper._rootWidget.quit() - ttk.TTkHelper._focusWidget = None - ttk.TTkHelper._rootCanvas = None - ttk.TTkHelper._rootWidget = None - ttk.TTkHelper._updateBuffer = [] - ttk.TTkHelper._updateWidget = [] - ttk.TTkHelper._overlay = [] - ttk.TTkHelper._shortcut = [] - ttk.TTkLog._messageHandler = [message_handler] - - def message_handler(mode, context, message): - msgType = "DEBUG" - if mode == ttk.TTkLog.InfoMsg: msgType = "[INFO]" - elif mode == ttk.TTkLog.WarningMsg: msgType = "[WARNING]" - elif mode == ttk.TTkLog.CriticalMsg: msgType = "[CRITICAL]" - elif mode == ttk.TTkLog.FatalMsg: msgType = "[FATAL]" - elif mode == ttk.TTkLog.ErrorMsg: msgType = "[ERROR]" - pyodideProxy.consoleLog(f"{msgType} {context.file} {message}") - # Register the callback to the message handler - ttk.TTkLog.installMessageHandler(message_handler) - `,{ globals: namespace } - ); - - let ttk_log = namespace.get("ttk_log"); - let ttk_input = namespace.get("ttk_input"); - let ttk_timer = namespace.get("ttk_timer"); - let ttk_resize = namespace.get("ttk_resize"); - let ttk_clean = namespace.get("ttk_clean"); - - term.onResize( (obj) => { - term.reset() - ttk_resize(obj.cols, obj.rows) - }); - term.onData((d, evt) => { ttk_input(d) }) - - pyodide.runPython(` - import sys,os - sys.path.append(os.path.join(sys.path[0],'demo')) - __file__='/home/pyodide/demo/demo.py' - __name__ = "__main__" - os.chdir('/home/pyodide/demo') - `,{ globals: namespace } - ); - - console.log("Run App") - - let content = pyodide.FS.readFile("demo.py", {encoding:'utf8'}) - pyodide.runPython(content,{ globals: namespace }); - - // TODO: I need to get rid of this: - pyodide.runPython(` - # TODO: I need to get rid of this: - ttk.TTkTerm.push(ttk.TTkTerm.ALT_SCREEN + ttk.TTkTerm.CLEAR + ttk.TTkTerm.Cursor.HIDE + ttk.TTkTerm.escTitle(ttk.TTkTerm.title)) - ttk.TTkTerm.push(ttk.TTkTerm.Mouse.ON) - `,{ globals: namespace } - ); - ttk_log("demo/demo.py - LOADED") - console.log("pippo") - fitAddon.fit() + ttkProxy.preRun() + + let file = "demo/demo.py" + let content = ttkProxy.readFile(file) + + ttkProxy.run(content, file, 60) } main() diff --git a/tests/sandbox/standalone.html b/tests/sandbox/standalone.html index 4d8dc01b..62e8c5f8 100644 --- a/tests/sandbox/standalone.html +++ b/tests/sandbox/standalone.html @@ -8,7 +8,9 @@ - + @@ -26,12 +28,12 @@ + @@ -113,87 +114,24 @@ /* pyodide demo */ - var pyodide = null - var run = null - var namespace = null async function main(){ - pyodide = await loadPyodide(); - - let pyodideProxy = { - consoleLog: function(m){ - console.log("TTk:",m) - }, - termPush: function (s) { - term.write(s); - }, - termSize: function () { - return [term.cols, term.rows] - }, - setTimeout: function(t, i) { - // console.log("TIME (Start)",i,t) - return setTimeout(() => ttk_timer(i), t) - }, - stopTimeout: function(t) { - // console.log("TIME (Stop)",t) - clearTimeout(t) - }, - clearTimeout: function(){ - let highestTimeoutId = setTimeout(";"); - for (let i = 0 ; i < highestTimeoutId ; i++) { - clearTimeout(i); - } - }, - setInterval: function(t, i) { - setTinterval(() => console.log('WIP -> Interval' + i), t) - } - }; - - term.write('Pyodide ('+pyodide.version+') - Loaded\n\r') - - pyodide.registerJsModule("pyodideProxy", pyodideProxy); - - term.write('Pyodide Proxy - Loaded\n\r') - - let zipResponse = await fetch("bin/TermTk.tgz"); - let zipBinary = await zipResponse.arrayBuffer(); - pyodide.unpackArchive(zipBinary, ".tar.gz"); + ttkProxy = new TTkProxy(term) + await ttkProxy.init() + await ttkProxy.loadLib("bin/TermTk.tgz"); term.write('TermTk - Loaded\n\r') - zipResponse = await fetch("bin/demo.tgz"); - zipBinary = await zipResponse.arrayBuffer(); - pyodide.unpackArchive(zipBinary, ".tar.gz"); - + await ttkProxy.loadLib("bin/demo.tgz"); term.write('Demos - Loaded\n\r') - zipResponse = await fetch("bin/tutorial.tgz"); - zipBinary = await zipResponse.arrayBuffer(); - pyodide.unpackArchive(zipBinary, ".tar.gz"); - + await ttkProxy.loadLib("bin/tutorial.tgz"); term.write('Tutorials - Loaded\n\r') /* Sidebar Fetch all the files in the pyodide.FS And push them in the sidebar */ - let getAllFiles = function(p){ - let ls = pyodide.FS.readdir(p) - let ret = [] - for(let i=0 ; i "+val.replace("\\033","") + " - ") - ttk.TTkHelper.paintAll() - - def ttk_clean(): - if ttk.TTkHelper._rootWidget: - ttk.TTkTimer.pyodideQuit() - ttk.TTkHelper._rootWidget.quit() - ttk.TTkHelper._focusWidget = None - ttk.TTkHelper._rootCanvas = None - ttk.TTkHelper._rootWidget = None - ttk.TTkHelper._updateBuffer = set() - ttk.TTkHelper._updateWidget = set() - ttk.TTkHelper._overlay = [] - ttk.TTkHelper._shortcut = [] - ttk.TTkLog._messageHandler = [message_handler] - - def ttk_init(): - ttk.TTkToolTip.toolTipTimer = ttk.TTkTimer() - ttk.TTkToolTip.toolTipTimer.timeout.connect(ttk.TTkToolTip._toolTipShow) - - def message_handler(mode, context, message): - msgType = "DEBUG" - if mode == ttk.TTkLog.InfoMsg: msgType = "[INFO]" - elif mode == ttk.TTkLog.WarningMsg: msgType = "[WARNING]" - elif mode == ttk.TTkLog.CriticalMsg: msgType = "[CRITICAL]" - elif mode == ttk.TTkLog.FatalMsg: msgType = "[FATAL]" - elif mode == ttk.TTkLog.ErrorMsg: msgType = "[ERROR]" - pyodideProxy.consoleLog(f"{msgType} {context.file} {message}") - # Register the callback to the message handler - ttk.TTkLog.installMessageHandler(message_handler) - `,{ globals: namespace } - ); - - let ttk_log = namespace.get("ttk_log"); - let ttk_input = namespace.get("ttk_input"); - let ttk_timer = namespace.get("ttk_timer"); - let ttk_resize = namespace.get("ttk_resize"); - let ttk_clean = namespace.get("ttk_clean"); - let ttk_init = namespace.get("ttk_init"); - - term.onResize( (obj) => { - term.reset() - ttk_resize(obj.cols, obj.rows) - }); - term.onData((d, evt) => { ttk_input(d) }) - - pyodide.runPython(` - import sys,os - sys.path.append(os.path.join(sys.path[0],'demo')) - __name__ = "__main__" - `,{ globals: namespace } - ); + ttkProxy.preRun() run = function(){ - ttk_clean() - console.log("Run App") - let filename = document.getElementById("codeUri").value let fps = document.getElementById("fpsCap").value - let pwd = pyodide.PATH.dirname(filename) - - pyodide.runPython(` - __file__='`+filename+`' - os.chdir('`+pwd+`') - ttk.TTkCfg.maxFps = `+fps,{ globals: namespace }) - - ttk_init() - - let content = getCode() - pyodide.runPython(content,{ globals: namespace }); - - ttk_log(filename + " - LOADED") + ttkProxy.run(getCode(), filename,fps) }; run() } diff --git a/tests/sandbox/sandbox.new.html b/tests/sandbox/sandbox.new.html deleted file mode 100644 index 091dc314..00000000 --- a/tests/sandbox/sandbox.new.html +++ /dev/null @@ -1,183 +0,0 @@ - - - - Mr. pyTermTk Sandbox - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - \ No newline at end of file diff --git a/tests/sandbox/sandbox.old.html b/tests/sandbox/sandbox.old.html new file mode 100644 index 00000000..2aad1556 --- /dev/null +++ b/tests/sandbox/sandbox.old.html @@ -0,0 +1,338 @@ + + + + Mr. pyTermTk Sandbox + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + \ No newline at end of file