1

In the following program, which I am running on Windows 7 professional 64, I am trying to allow the user to intervene if needed (through the inner while loop) and cause the outer while loop to repeat an action. Otherwise, the inner while loop would timeout and the program would just continue unimpeded:

import msvcrt
import time

decision = 'do not repeat' # default setting

for f in ['f1', 'f2', 'f3']:

    print ('doing some prepartory actions on f')

    while True: # outer while loop to allow repeating actions on f

        print ('doing some more actions on f')

        t0 = time.time()
        while time.time() - t0 < 10:        # inner while loop to allow user to intervene 
            if msvcrt.kbhit():              # and repeat actions by pressing ENTER if
                if msvcrt.getch() == '\r':  # needed or allow timeout continuation
                    decision = "repeat"
                    break
                else:
                    break
            time.sleep(0.1)

        if decision == "repeat":
            print ("Repeating f in the outer while loop...")
            continue

        else:
            break

    print ('doing final actions on f in the for loop')

However, the user-input part (pressing ENTER to repeat) of the inner loop is not working and I don't know why. I took its idea from the solution offered here. Any thoughts on how to get this to work?

Community
  • 1
  • 1
  • 1
    `kbhit` and `getch` require the process to be attached to a console window. If you're using IDLE, then the process doesn't have a console -- at least not when run the default way using pythonw.exe. Even if you do run IDLE with an attached console (e.g. use the Win+R run dialog to run `py -3 -m idlelib`), I doubt you'd want the user to have to switch to the console window to enter input. – Eryk Sun Jan 26 '17 at 21:28
  • 1
    Anyway, IDLE and other IDE shells are just development environments. If you're intending this to be a console script, you can mock up fake console I/O functions for use in testing when there's no attached console (e.g. `open("CONIN$")` fails). If it's not supposed to be a console program, then use a GUI toolkit to create your own window and read keyboard input. – Eryk Sun Jan 26 '17 at 21:40

2 Answers2

1

You are comparing variable decision and string "repeat" in your inner loop since you are using == operator. You should use = instead to assign a value to the variable:

decision = 'repeat'
Reaper
  • 747
  • 1
  • 5
  • 15
  • Thank you for noticing this. I fixed it, but it had no bearing on the inner loop. I also changed the `for` loop set into strings to allow the code to run. – Muhamed Al Khalil Jan 25 '17 at 20:52
  • Are you sure that `msvcrt.getch()` returns '\r'? – Reaper Jan 25 '17 at 21:06
  • It seems this is what it is expected to return when you press ENTER on Windows. That's what the code I borrowed had. – Muhamed Al Khalil Jan 25 '17 at 21:09
  • Could be a problem with time since everything else looks ok. Try debugging your code stepping lines in the inner loop one by one. I'm away from PC so can't test right now. – Reaper Jan 25 '17 at 21:16
  • Thanks. I did the step-through debugging. The `msvcrt.kbhit()` is not returning `True` even when a key is pressed. – Muhamed Al Khalil Jan 25 '17 at 21:40
  • Maybe it's because of `time.sleep(0.1)` because it makes the thread sleep. Try without `time.sleep(0.1)`. – Reaper Jan 25 '17 at 22:03
0

I have now managed to resolve this issue. The kbhit process did not work in the IDLE I was using (Wing IDE), but worked if called from the command prompt (This may apply, just as @eryksun said, to all IDLEs and not just Wing). Another issue I found is that the getch() process does not do what I need, and that I have to use getwch() which returns unicode. With one more minor adjustment ( defaulting decision with decision = 'Reset decision to not repeat', the code is now in good working order:

import msvcrt
import time

decision = 'do not repeat' # default setting

for f in ['f1', 'f2', 'f3']:

    print ('doing some prepartory actions on f')

    while True: # outer while loop to allow repeating actions on f

        print ('doing some more actions on f')

        t0 = time.time()
        while time.time() - t0 < 10:        # inner while loop to allow user to intervene 
            if msvcrt.kbhit():              # and repeat actions by pressing ENTER if
                if msvcrt.getchw() == '\r': # needed or allow timeout continuation
                    decision = "repeat"
                    break
                else:
                    break
            time.sleep(0.5)

        if decision == "repeat":
            print ("Repeating f in the outer while loop...")
            decision = 'Reset decision to not repeat'
            continue

        else:
            break

    print ('doing final actions on f in the for loop')