How do I use a GUI widget to catch input() request through subprocess's Popen and return it to continue the process, repeat until the end?

Viewed 50

I am using wxPython as my GUI, NVDA as my screen reader, with a Braille refreshable display. NVDA at present doesn't support reading tkinter package properly.

My goal: while getting the output stream to multiline, readonly TextCtrl; to capture the request for input() process and convert input(prompt) --> TextEntry() with default dialog title, prompt for a message, and a empty TextCtl waiting for my one-line string, return after hitting Enter the string I typed in to the input stream and continuing accepting output to the original output TextCtrl.

My goal is to replace my need to use the terminal with this form for limited types of command-line programs that only require one-line input from me as I follow output line by line until the end of the process.

Right now, my program is coded as such:

import os, subprocess

import wx


class PyOutputFrame(wx.Frame):
    
    def __init__(self, title="Program Output"):
        
        wx.Frame.__init__(self, None, title=title)
        
        menubar = wx.MenuBar()
        actionmenu = wx.Menu()
        chdirmenuitem = actionmenu.Append(wx.ID_ANY, 'Change Current Dir')
        menubar.Append(actionmenu, '&Action')
        self.Bind(wx.EVT_MENU, self.OnChange, chdirmenuitem)
        self.SetMenuBar(menubar)
        
        panel = wx.Panel(self)
        self.entxt = wx.TextCtrl(panel, style=wx.TE_PROCESS_ENTER)
        self.entxt.Bind(wx.EVT_TEXT_ENTER, self.OnEnter)
        self.outxt = wx.TextCtrl(panel, style=wx.TE_MULTILINE|
                                              wx.TE_READONLY|
                                              wx.TE_BESTWRAP)
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.entxt, 0, wx.EXPAND)
        sizer.Add(self.outxt, 1, wx.EXPAND)
        panel.SetSizer(sizer)
        
    def OnEnter(self, event):
        
        self.outxt.Clear()
        cmd = self.entxt.GetValue()
        proc = subprocess.run(cmd,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.STDOUT,
                              shell=True)
        self.outxt.WriteText(proc.stdout.decode())
        self.outxt.SetInsertionPoint(0)
        self.outxt.SetFocus()
        
    def OnChange(self, event):
        
        dlg = wx.DirDialog(self, style=wx.DD_CHANGE_DIR)
        dlg.ShowModal()

if __name__ == '__main__':
    app = wx.App()
    frm = PyOutputFrame()
    frm.Show()
    app.MainLoop()

This needs a new code for:

1: When the process starts, if the output require no inpuq, just print straight to output TextCtrl, line by line 2: When output line require input from me, automatically either 1) create pop-up messagebox with the prompt as the message and one-line input box to type in my input then ENTER to send it on to the process or 2) expand my original input TextCtrl, originally used to kick off process (e.g. "py echoname.py") to accept multiline input if necessary whenever the process require input, no pop-up dialog used 3: That input is translated to output, beside its prompt output if any 4: Repeat 2 and 3 if any more 5: Finish the process with remainder of output of any

Test script to read from and input to:

print('Hi')
while True:
    ans = input('Tell me your name: ')
    if ans == 'q': break
    print(f'Yo {ans.title()}!')
print('Bye!')

Big picture rationale: I use Braille display for reading text and my goal is move away from terminal in use of command-line programs toward this type of GUI interface because it will my focus to move to the top of multiline output instead of needing to climb line by line to the top in the terminal through Braille display. Terminals are better aimed toward sighted users, not Braille display users. Thank you.

0 Answers
Related