Skip to content

Instantly share code, notes, and snippets.

Forked from aron-bordin/
Last active September 20, 2019 12:29
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
What would you like to do?
Initial Python/Kivy Terminal Emulator (It's just a performance test. You can use this sample to write your own terminal emulator)
from kivy.base import runTouchApp
from kivy.event import EventDispatcher
from kivy.lang import Builder
from import ObjectProperty, ListProperty, StringProperty, \
NumericProperty, Clock, partial
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
import os
import subprocess
import threading
from multiprocessing import Process
import shlex
import sys
console_input: console_input
scroll_view: scroll_view
id: scroll_view
id: console_input
shell: root
size_hint: (1, None)
font_size: root.font_size
foreground_color: root.foreground_color
background_color: root.background_color
height: max(self.parent.height, self.minimum_height)
def threaded(fn):
def wrapper(*args, **kwargs):
threading.Thread(target=fn, args=args, kwargs=kwargs).start()
return wrapper
class Shell(EventDispatcher):
# , 'on_stop', 'on_start', 'on_complete', 'on_error'
__events__ = ('on_output', 'on_complete')
process = ObjectProperty(None)
'''subprocess process
def run_command(self, command, show_output=True, *args):
output = ''
self.process = subprocess.Popen(command, stdout=subprocess.PIPE)
lines_iterator = iter(self.process.stdout.readline, "")
for line in lines_iterator:
output += line.decode()
if show_output:
self.dispatch('on_output', line)
self.dispatch('on_complete', output)
def stop(self, *args):
if self.process:
class ConsoleInput(TextInput):
'''Displays Output and sends input to Shell. Emits 'on_ready_to_input'
when it is ready to get input from user.
shell = ObjectProperty(None)
'''Instance of KivyConsole(parent) widget
def __init__(self, **kwargs):
super(ConsoleInput, self).__init__(**kwargs)
self._cursor_pos = 0 # position of the cursor before after prompt
def __init_console(self, *args):
'''Create initial values for the prompt and shows it
self.cur_dir = os.getcwd()
self._hostname = 'kivy'
if hasattr(os, 'uname'):
self._hostname = os.uname()[1]
self._hostname = os.environ.get('COMPUTERNAME', 'kivy')
except Exception:
self._username = os.environ.get('USER', '')
if not self._username:
self._username = os.environ.get('USERNAME', 'designer')
def keyboard_on_key_down(self, window, keycode, text, modifiers):
'''Override of _keyboard_on_key_down.
if keycode[0] == 13:
# Enter -> execute the command
text = self.text[self._cursor_pos:]
if text.strip():
Clock.schedule_once(partial(self._run_cmd, text))
elif keycode[0] in [8, 127]:
elif keycode[0] == 99 and modifiers == ['ctrl']:
if self.cursor_index() < self._cursor_pos:
return False
return super(ConsoleInput, self).keyboard_on_key_down(
window, keycode, text, modifiers)
def _run_cmd(self, cmd, *args):
_posix = True
if sys.platform[0] == 'w':
_posix = False
commands = shlex.split(str(cmd), posix=_posix)
def validate_cursor_pos(self, *args):
if self.cursor_index() < self._cursor_pos:
self.cursor = self.get_cursor_from_index(self._cursor_pos)
def prompt(self, *args):
'''Show the PS1 variable
ps1 = "[%s@%s %s]> " % (
self._username, self._hostname,
self._cursor_pos = self.cursor_index() + len(ps1)
self.text += ps1
def on_output(self, output):
self.text += output.decode()
# print(output)
def on_complete(self, output):
class KivyConsole(BoxLayout, Shell):
console_input = ObjectProperty(None)
'''Instance of ConsoleInput
:data:`console_input` is an :class:``
scroll_view = ObjectProperty(None)
'''Instance of :class:`~kivy.uix.scrollview.ScrollView`
:data:`scroll_view` is an :class:``
foreground_color = ListProperty((1, 1, 1, 1))
'''This defines the color of the text in the console
:data:`foreground_color` is an :class:``,
Default to '(.5, .5, .5, .93)'
background_color = ListProperty((0, 0, 0, 1))
'''This defines the color of the text in the console
:data:`foreground_color` is an :class:``,
Default to '(0, 0, 0, 1)'''
# font_name = StringProperty('data/fonts/DroidSansMono.ttf')
'''Indicates the font Style used in the console
:data:`font` is a :class:``,
Default to 'DroidSansMono'
font_size = NumericProperty(14)
'''Indicates the size of the font used for the console
:data:`font_size` is a :class:``,
Default to '9'
def __init__(self, **kwargs):
super(KivyConsole, self).__init__(**kwargs)
# = Shell()
# self.run_command =
def on_output(self, output):
'''Event handler to send output data
def on_complete(self, output):
'''Event handler to send output data
if __name__ == '__main__':
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment