191 lines
5.7 KiB
Python
191 lines
5.7 KiB
Python
# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
|
|
# See LICENSE for details.
|
|
|
|
# You can run this .tac file directly with:
|
|
# twistd -ny window.tac
|
|
|
|
from __future__ import division
|
|
|
|
import string, random
|
|
|
|
from twisted.python import log
|
|
from twisted.internet import protocol, task
|
|
from twisted.application import internet, service
|
|
from twisted.cred import checkers, portal
|
|
|
|
from twisted.conch.insults import insults, window
|
|
from twisted.conch.telnet import TelnetTransport, TelnetBootstrapProtocol
|
|
from twisted.conch.manhole_ssh import ConchFactory, TerminalRealm
|
|
|
|
from twisted.internet import reactor
|
|
|
|
class DrawableCanvas(window.Canvas):
|
|
x = 0
|
|
y = 0
|
|
|
|
def func_LEFT_ARROW(self, modifier):
|
|
self.x -= 1
|
|
self.repaint()
|
|
|
|
def func_RIGHT_ARROW(self, modifier):
|
|
self.x += 1
|
|
self.repaint()
|
|
|
|
def func_UP_ARROW(self, modifier):
|
|
self.y -= 1
|
|
self.repaint()
|
|
|
|
def func_DOWN_ARROW(self, modifier):
|
|
self.y += 1
|
|
self.repaint()
|
|
|
|
def characterReceived(self, keyID, modifier):
|
|
self[self.x, self.y] = keyID
|
|
self.x += 1
|
|
self.repaint()
|
|
|
|
def keystrokeReceived(self, keyID, modifier):
|
|
if keyID == '\r' or keyID == '\v':
|
|
return
|
|
window.Canvas.keystrokeReceived(self, keyID, modifier)
|
|
if self.x >= self.width:
|
|
self.x = 0
|
|
elif self.x < 0:
|
|
self.x = self.width - 1
|
|
|
|
if self.y >= self.height:
|
|
self.y = 0
|
|
elif self.y < 0:
|
|
self.y = self.height - 1
|
|
self.repaint()
|
|
|
|
def render(self, width, height, terminal):
|
|
window.Canvas.render(self, width, height, terminal)
|
|
if self.focused:
|
|
terminal.cursorPosition(self.x, self.y)
|
|
window.cursor(terminal, self[self.x, self.y])
|
|
|
|
|
|
class ButtonDemo(insults.TerminalProtocol):
|
|
width = 80
|
|
height = 24
|
|
|
|
def _draw(self):
|
|
self.window.draw(self.width, self.height, self.terminal)
|
|
|
|
def _redraw(self):
|
|
self.window.filthy()
|
|
self._draw()
|
|
|
|
def _schedule(self, f):
|
|
reactor.callLater(0, f)
|
|
|
|
def connectionMade(self):
|
|
self.terminal.eraseDisplay()
|
|
self.terminal.resetPrivateModes([insults.privateModes.CURSOR_MODE])
|
|
|
|
self.window = window.TopWindow(self._draw, self._schedule)
|
|
self.output = window.TextOutput((15, 1))
|
|
self.input = window.TextInput(15, self._setText)
|
|
self.select1 = window.Selection(map(str, range(100)), self._setText, 10)
|
|
self.select2 = window.Selection(map(str, range(200, 300)), self._setText, 10)
|
|
self.button = window.Button("Clear", self._clear)
|
|
self.canvas = DrawableCanvas()
|
|
|
|
hbox = window.HBox()
|
|
hbox.addChild(self.input)
|
|
hbox.addChild(self.output)
|
|
hbox.addChild(window.Border(self.button))
|
|
hbox.addChild(window.Border(self.select1))
|
|
hbox.addChild(window.Border(self.select2))
|
|
|
|
t1 = window.TextOutputArea(longLines=window.TextOutputArea.WRAP)
|
|
t2 = window.TextOutputArea(longLines=window.TextOutputArea.TRUNCATE)
|
|
t3 = window.TextOutputArea(longLines=window.TextOutputArea.TRUNCATE)
|
|
t4 = window.TextOutputArea(longLines=window.TextOutputArea.TRUNCATE)
|
|
for _t in t1, t2, t3, t4:
|
|
_t.setText((('This is a very long string. ' * 3) + '\n') * 3)
|
|
|
|
vp = window.Viewport(t3)
|
|
d = [1]
|
|
def spin():
|
|
vp.xOffset += d[0]
|
|
if vp.xOffset == 0 or vp.xOffset == 25:
|
|
d[0] *= -1
|
|
self.call = task.LoopingCall(spin)
|
|
self.call.start(0.25, now=False)
|
|
hbox.addChild(window.Border(vp))
|
|
|
|
vp2 = window.ScrolledArea(t4)
|
|
hbox.addChild(vp2)
|
|
|
|
texts = window.VBox()
|
|
texts.addChild(window.Border(t1))
|
|
texts.addChild(window.Border(t2))
|
|
|
|
areas = window.HBox()
|
|
areas.addChild(window.Border(self.canvas))
|
|
areas.addChild(texts)
|
|
|
|
vbox = window.VBox()
|
|
vbox.addChild(hbox)
|
|
vbox.addChild(areas)
|
|
self.window.addChild(vbox)
|
|
self.terminalSize(self.width, self.height)
|
|
|
|
def connectionLost(self, reason):
|
|
self.call.stop()
|
|
insults.TerminalProtocol.connectionLost(self, reason)
|
|
|
|
def terminalSize(self, width, height):
|
|
self.width = width
|
|
self.height = height
|
|
self.terminal.eraseDisplay()
|
|
self._redraw()
|
|
|
|
|
|
def keystrokeReceived(self, keyID, modifier):
|
|
self.window.keystrokeReceived(keyID, modifier)
|
|
|
|
def _clear(self):
|
|
self.canvas.clear()
|
|
|
|
def _setText(self, text):
|
|
self.input.setText('')
|
|
self.output.setText(text)
|
|
|
|
|
|
def makeService(args):
|
|
checker = checkers.InMemoryUsernamePasswordDatabaseDontUse(username="password")
|
|
|
|
f = protocol.ServerFactory()
|
|
f.protocol = lambda: TelnetTransport(TelnetBootstrapProtocol,
|
|
insults.ServerProtocol,
|
|
args['protocolFactory'],
|
|
*args.get('protocolArgs', ()),
|
|
**args.get('protocolKwArgs', {}))
|
|
tsvc = internet.TCPServer(args['telnet'], f)
|
|
|
|
def chainProtocolFactory():
|
|
return insults.ServerProtocol(
|
|
args['protocolFactory'],
|
|
*args.get('protocolArgs', ()),
|
|
**args.get('protocolKwArgs', {}))
|
|
|
|
rlm = TerminalRealm()
|
|
rlm.chainedProtocolFactory = chainProtocolFactory
|
|
ptl = portal.Portal(rlm, [checker])
|
|
f = ConchFactory(ptl)
|
|
csvc = internet.TCPServer(args['ssh'], f)
|
|
|
|
m = service.MultiService()
|
|
tsvc.setServiceParent(m)
|
|
csvc.setServiceParent(m)
|
|
return m
|
|
|
|
application = service.Application("Window Demo")
|
|
|
|
makeService({'protocolFactory': ButtonDemo,
|
|
'telnet': 6023,
|
|
'ssh': 6022}).setServiceParent(application)
|