Exemplo n.º 1
0
class wxui(base.BaseUI):
  def __init__(self):
    base.BaseUI.__init__(self)
    exported.hook_register("shutdown_hook", self.shutdown)
    exported.hook_register("to_user_hook", self.write)
    exported.hook_register("config_change_hook", self.configChangeHandler)
    exported.hook_register("bell_hook", self.bell)
    exported.hook_register("prompt_hook",
      lambda x: self.write( {
        'message': message.Message(x["prompt"], message.MUDDATA, x["session"])
        } ) )
    self.app = wx.App()
    self.window = window()
    self.window.input.Bind(wx.EVT_CHAR_HOOK, self.process)

  def process(self, event):
    key = event.GetKeyCode()
    if key == wx.WXK_RETURN:
      self.input_data()
    event.Skip()

  def runui(self):
    global HELP_TEXT
    exported.add_help("mudder", HELP_TEXT)
    self.window.Show()
    self.app.MainLoop()

  def wantMainThread(self):
    return 1

  def shutdown(self, args):
    wx.GetApp().ExitMainLoop()

  def bell(self, args):
    """ Handles incoming bell characters."""
    sys.stdout.write('\07')

  def configChangeHandler(self, args):
    """ Handles config changes (including mudecho)."""
    name = args["name"]
    newvalue = args["newvalue"]
    return

  def input_data(self, *args, **kwargs):
    """ This is the poll loop for user input."""
    try:
      data = self.window.input.GetValue()
      self.window.input.SetValue("")
      if data != None:
        self.handleinput(data)
    except select.error, e:
      (errno,name) = e
      if errno == 4:
        exported.write_message("system exit: select.error.")
        event.ShutdownEvent().enqueue()
        return

    except SystemExit:
      exported.write_message("system exit: you'll be back...")
      event.ShutdownEvent().enqueue()
Exemplo n.º 2
0
    def run(self):
        """ This is the poll loop for user input."""
        try:
            while not self.shutdownflag:
                if os.name == 'posix':
                    if self._rline == 1:
                        data = self._posix_readline_input()
                    else:
                        data = self._posix_input()
                else:
                    data = self._non_posix_input()

                if data != None:
                    self.handleinput(data)

                    # FIXME - this is just plain icky.  the issue is that
                    # we need to know we're ending _before_ we block for
                    # the next input.  otherwise Lyntin will shut down except
                    # for this thread which will hang around blocking until
                    # the user hits the enter key.
                    #
                    # any good ideas for dealing with this are more than welcome.
                    if data.find("#end") == 0:
                        break

        except select.error, e:
            (errno, name) = e
            if errno == 4:
                exported.write_message("system exit: select.error.")
                event.ShutdownEvent().enqueue()
                return
Exemplo n.º 3
0
def end_cmd(ses, args, input):
    """
  Closes all sessions and quits out of Lyntin.

  Note: on most muds this will leave your character in a state of 
  linkdeath--it does not sell all your stuff, return you to town, 
  save your character, tell your friends goodbye, or anything of 
  that nature.

  category: commands
  """
    exported.write_message("end: you'll be back...")
    event.ShutdownEvent().enqueue()
Exemplo n.º 4
0
 def input_data(self, *args, **kwargs):
   """ This is the poll loop for user input."""
   try:
     data = self.window.input.GetValue()
     self.window.input.SetValue("")
     if data != None:
       self.handleinput(data)
   except select.error, e:
     (errno,name) = e
     if errno == 4:
       exported.write_message("system exit: select.error.")
       event.ShutdownEvent().enqueue()
       return
Exemplo n.º 5
0
                    # the user hits the enter key.
                    #
                    # any good ideas for dealing with this are more than welcome.
                    if data.find("#end") == 0:
                        break

        except select.error, e:
            (errno, name) = e
            if errno == 4:
                exported.write_message("system exit: select.error.")
                event.ShutdownEvent().enqueue()
                return

        except SystemExit:
            exported.write_message("system exit: you'll be back...")
            event.ShutdownEvent().enqueue()

        except:
            exported.write_traceback()
            event.ShutdownEvent().enqueue()

    def write(self, args):
        """
    Handles writing information from the mud and/or Lyntin
    to the user.
    """
        msg = args["message"]

        if type(msg) == types.StringType:
            msg = message.Message(msg, message.LTDATA)
Exemplo n.º 6
0
def main(defaultoptions={}):
    """
  This parses the command line arguments and makes sure they're all valid,
  instantiates a ui, does some setup, spins off an engine thread, and
  goes into the ui's mainloop.

  @param defaultoptions: the boot options to use.  we update the 
      config.options dict with these options--this is the easiest
      way to override the ui, moduledir, datadir, et al from a
      Lyntin run script.
  @type  defaultoptions: dict
  """
    try:
        import sys, os, traceback, ConfigParser
        from lyntin import config, event, utils, exported
        from lyntin.ui import base
        import locale

        locale.setlocale(locale.LC_ALL, '')

        config.options.update(defaultoptions)

        # read through options and arguments
        optlist = utils.parse_args(sys.argv[1:])

        for mem in optlist:
            if mem[0] == '--help':
                print constants.HELPTEXT
                sys.exit(0)

            elif mem[0] == '--version':
                print constants.VERSION
                sys.exit(0)

            elif mem[0] in ["--configuration", "-c"]:
                # ini files OVERRIDE the default options
                # they can provide multiple ini files, but each new
                # ini file will OVERRIDE the contents of the previous ini file
                # where the two files intersect.
                parser = ConfigParser.ConfigParser()
                parser.read([mem[1]])

                newoptions = {}
                for s in parser.sections():
                    for o in parser.options(s):
                        c = parser.get(s, o).split(",")
                        if newoptions.has_key(o):
                            newoptions[o] += c
                        else:
                            newoptions[o] = c

                config.options.update(newoptions)

            else:
                opt = mem[0]
                while opt.startswith("-"):
                    opt = opt[1:]

                if len(opt) > 0:
                    if config.options.has_key(opt):
                        if type(config.options[opt]) is list:
                            config.options[opt].append(mem[1])
                        else:
                            config.options[opt] = mem[1]
                    else:
                        config.options[opt] = [mem[1]]

        for mem in ["datadir", "ui", "commandchar"]:
            if config.options.has_key(mem) and type(
                    config.options[mem]) is list:
                config.options[mem] = config.options[mem][0]

        # if they haven't set the datadir via the command line, then
        # we go see if they have a HOME in their environment variables....
        if not config.options["datadir"]:
            if os.environ.has_key("HOME"):
                config.options["datadir"] = os.environ["HOME"]
        config.options["datadir"] = utils.fixdir(config.options["datadir"])

        def on_shutdown():
            """
      This gets called by the Python interpreter atexit.  The reason
      we do shutdown stuff here is we're more likely to catch things
      here than we are to let everything cycle through the 
      ShutdownEvent.  This should probably get fixed up at some point
      in the future.
      """
            sys.stderr.write("goodbye.\n")
            #exported.hook_spam("shutdown_hook", {})

        import atexit
        atexit.register(on_shutdown)

        # instantiate the engine
        Engine.instance = Engine()
        exported.myengine = Engine.instance
        Engine.instance._setupConfiguration()

        # instantiate the ui
        uiinstance = None
        try:
            uiname = str(config.options['ui'])
            modulename = uiname + "ui"
            uiinstance = base.get_ui(modulename)
            if not uiinstance:
                raise ValueError("No ui instance.")
        except Exception, e:
            print "Cannot start '%s': %s" % (uiname, e)
            traceback.print_exc()
            sys.exit(0)

        Engine.instance.setUI(uiinstance)

        # do some more silly initialization stuff
        # adds the .lyntinrc file to the readfile list if it exists.
        if config.options["datadir"]:
            lyntinrcfile = config.options["datadir"] + ".lyntinrc"
            if os.path.exists(lyntinrcfile):
                # we want the .lyntinrc file read in first, so then other
                # files can overwrite the contents therein
                config.options['readfile'].insert(0, lyntinrcfile)

        # import modules listed in modulesinit
        exported.write_message("Loading Lyntin modules.")

        try:
            import modules.__init__
            modules.__init__.load_modules()
        except:
            exported.write_traceback("Modules did not load correctly.")
            sys.exit(1)

        # spam the startup hook
        exported.hook_spam("startup_hook", {})

        commandchar = Engine.instance._managers["config"].get("commandchar")

        # handle command files
        for mem in config.options['readfile']:
            exported.write_message("Reading in file " + mem)
            # we have to escape windows os separators because \ has a specific
            # meaning in the argparser
            mem = mem.replace("\\", "\\\\")
            exported.lyntin_command("%sread %s" % (commandchar, mem),
                                    internal=1)

        # we're done initialization!
        exported.write_message(constants.STARTUPTEXT)
        Engine.instance.writePrompt()

        engine_thread = Engine.instance.startthread("engine",
                                                    Engine.instance.runengine)
        timer_thread = Engine.instance.startthread("timer",
                                                   Engine.instance.runtimer)
        try:
            Engine.instance._ui.runui()
        finally:
            sys.stderr.write("Shutting down...")
            event.ShutdownEvent().enqueue()
            engine_thread.join(10)
            timer_thread.join(10)
Exemplo n.º 7
0
    def runui(self):
        #
        # This is the loop for user input polling and for mud output.
        #
        global HELP_TEXT

        exported.add_help("cursesui", HELP_TEXT)

        try:

            stdscr = curses.initscr()
            if curses.has_colors():
                curses.start_color()
                for i in xrange(1, 64):
                    curses.init_pair(i, i % 8, i / 8)
            curses.raw()
            curses.noecho()
            curses.nonl()
            curses.meta(1)

            out = None
            edit = None
            scrollback = None

            lines = self.lines_

            exported.write_message(
                "For Cursesui help, type \"#help cursesui\".")
            exported.write_message(
                "For some commands help, type \"#help curses\".")

            dirty_count = 0
            timestamp = 0
            output_count = 0

            hotkey_buffer = ''
            keyboard_buffer = []

            select_timeout = 100
            keyboard_fd = sys.stdin.fileno()
            output_pipe_fd = self.output_[0]
            select_input_list = [keyboard_fd, output_pipe_fd]

            while self.running_:

                #
                # set output windows:
                #
                if not out:
                    stdscr = curses.initscr()
                    (screen_h, screen_w) = stdscr.getmaxyx()
                    win = curses.newwin(1, screen_w, screen_h - 1, 0)
                    if edit:
                        edit.attach(win)
                    else:
                        edit = inputbox(self, win)
                    if not scrollback:
                        out = scroller(
                            curses.newwin(screen_h - 1, screen_w, 0, 0), lines)
                    else:
                        scroll_h = screen_h / 3 * 2
                        out_h = (screen_h - 2) - scroll_h
                        scrollback = scroller(
                            curses.newwin(scroll_h, screen_w, 0, 0), lines[:])
                        scrollback.redraw()
                        wborder = curses.newwin(1, screen_w, scroll_h, 0)
                        wborder.bkgd(curses.ACS_HLINE)
                        wborder.erase()
                        wborder.noutrefresh()
                        out = scroller(
                            curses.newwin(out_h, screen_w, scroll_h + 1, 0),
                            lines)
                    out.redraw()

                edit._align()

                if keyboard_buffer and not hotkey_buffer:
                    ch = keyboard_buffer.pop()
                else:
                    ch = win.getch()
                    if ch == curses.ERR:

                        # drop the hotkey buffer when the keyboard goes idle
                        hotkey_buffer = ''

                        # enter idle mode:
                        (i, o, x) = select.select(select_input_list, [], [],
                                                  select_timeout)

                        if not i:
                            # timeout was hit:
                            out.redraw(self.cfg_maxscrollback_)
                            select_timeout = 100
                            dirty_count = 0
                            continue
                        else:

                            if keyboard_fd in i:
                                ch = win.getch()

                            if output_pipe_fd in i:
                                line = os.read(output_pipe_fd, 1024)
                                dirty_count += len(line)

                            if ch == curses.ERR:
                                timestamp_now = time()
                                if ((timestamp_now - timestamp) >
                                        0.2) or (dirty_count > self.cfg_lazy_):
                                    out.redraw(self.cfg_maxscrollback_)
                                    select_timeout = 100
                                    dirty_count = 0
                                    output_count = 0
                                else:
                                    select_timeout = 0.2
                                    output_count += 1
                                timestamp = timestamp_now
                                continue

                    keyboard_buffer.insert(0, ch)
                    if ch < 256:
                        keycodename = chr(ch)
                        hotkey_buffer += keycodename

                        if self.cfg_keydebug_:
                            if is_a_char(keycodename):
                                exported.write_message(keycodename)
                            elif ch == 0x1b:
                                exported.write_message("<ESC>")

                        binding = bindings.get(hotkey_buffer)
                        if binding:
                            hotkey_buffer = ''
                            keyboard_buffer = []
                            self.handleinput(binding[1], internal=1)
                            continue
                        elif not filter(lambda x: x.startswith(hotkey_buffer),
                                        bindings.keys()):
                            hotkey_buffer = ''
                        continue
                    else:
                        keycodename = keytext.get(ch)
                        if keycodename:
                            if self.cfg_keydebug_:
                                exported.write_message(keycodename)
                            binding = bindings.get(keycodename)
                            if binding:
                                self.handleinput(binding[1], internal=1)
                                keyboard_buffer.pop()  # get it back
                        hotkey_buffer = ''
                        continue

                if ch == curses.KEY_PPAGE:
                    if not scrollback:
                        scrollback = 1  # create scrollback window at next iteration
                        out = None
                    else:
                        scrollback.redraw(scroll=-(scroll_h / 2 + 1))
                    continue
                if ch == curses.KEY_NPAGE:
                    if scrollback:
                        scrollback.redraw(scroll=scroll_h / 2 + 1)
                    continue

                if ch == curses.ascii.ESC and scrollback:
                    scrollback = None
                    out = None
                    continue

                ch = edit.do_command(ch)

                if ch in (curses.ascii.CR, curses.ascii.LF):
                    self.handleinput(edit.get_string())
                    edit.set("")

                elif ch in (curses.KEY_RESIZE,
                            curses.ascii.FF):  # force screen redraw
                    out = None
                    continue

                elif ch == curses.ascii.ETX:  # Ctrl-C
                    break

        except SystemExit:
            event.ShutdownEvent().enqueue()
            endcurses()

        except:
            import traceback
            endcurses()
            traceback.print_exc(file=sys.stdout)
            raw_input("Press enter to exit...")
            event.ShutdownEvent().enqueue()

        else:
            endcurses()