Tags: figure, forthis, getch, isrunning, key, pressing, programming, python, script

How to use getch()?

On Programmer » Python

13,170 words with 10 Comments; publish: Mon, 05 May 2008 13:52:00 GMT; (20078.00, « »)

I'm trying to figure out how to change what a script does while it is

running, by pressing a key, such as "k". Can getch() be used for

this? As a first test:

c = 0

while True:

c += 1

if getch() == "k":

break

print c

This produces "NameError: name 'getch' is not defined".

Am I on the wrong track?

Thanks,

**** Moores

Win XP, Python 2.43

Tutor maillist - Tutor (AT) python (DOT) org

All Comments

Leave a comment...

  • 10 Comments
    • **** Moores wrote:

      I'm trying to figure out how to change what a script does while it is

      running, by pressing a key, such as "k". Can getch() be used for

      this?

      Google 'python getch' or see this recipe by our very own Danny Yoo:

      Kent

      Tutor maillist - Tutor (AT) python (DOT) org

      #1; Mon, 05 May 2008 13:53:00 GMT
    • At 09:51 AM 8/27/2006, Kent Johnson wrote:

      >**** Moores wrote:

      I'm trying to figure out how to change what a script does while it is

      running, by pressing a key, such as "k". Can getch() be used for

      this?

      >Google 'python getch' or see this recipe by our very own Danny Yoo:

      So now I have, thanks to Danny Yoo:

      class _Getch:

      """Gets a single character from standard input. Does not echo to the

      screen."""

      def __init__(self):

      try:

      self.impl = _GetchWindows()

      except ImportError:

      self.impl = _GetchUnix()

      def __call__(self): return self.impl()

      class _GetchWindows:

      def __init__(self):

      import msvcrt

      def __call__(self):

      import msvcrt

      return msvcrt.getch()

      c = 0

      getch = _Getch()

      while True:

      c += 1

      if getch == "k":

      break

      print c

      No more errors, but it doesn't do what I wanted. More help, please.

      **** Moores

      Tutor maillist - Tutor (AT) python (DOT) org

      #2; Mon, 05 May 2008 13:54:00 GMT
    • **** Moores wrote:

      At 09:51 AM 8/27/2006, Kent Johnson wrote:

      >**** Moores wrote:

      >

      I'm trying to figure out how to change what a script does while it is

      running, by pressing a key, such as "k". Can getch() be used for

      this?

      >Google 'python getch' or see this recipe by our very own Danny Yoo:

      >

      >

      So now I have, thanks to Danny Yoo:

      class _Getch:

      """Gets a single character from standard input. Does not echo to the

      screen."""

      def __init__(self):

      try:

      self.impl = _GetchWindows()

      except ImportError:

      self.impl = _GetchUnix()

      def __call__(self): return self.impl()

      class _GetchWindows:

      def __init__(self):

      import msvcrt

      def __call__(self):

      import msvcrt

      return msvcrt.getch()

      c = 0

      getch = _Getch()

      while True:

      c += 1

      if getch == "k":

      This should be

      if getch() == "k":

      getch is a callable object (it implements __call__()) and is used like a

      function.

      If you only want to run on Windows, as your code suggests, just call

      msvcrt.getch() directly. This is a blocking call - it won't return until

      a key is pressed. If you don't want to block, use msvcrt.kbhit() to

      check whether a key is available before calling getch().

      break

      print c

      No more errors, but it doesn't do what I wanted. More help, please.

      **** Moores

      Tutor maillist - Tutor (AT) python (DOT) org

      --

      Tutor maillist - Tutor (AT) python (DOT) org

      #3; Mon, 05 May 2008 13:55:00 GMT
    • At 10:55 AM 8/27/2006, Kent Johnson wrote:

      >getch is a callable object (it implements __call__()) and is used like a

      >function.

      >

      >If you only want to run on Windows, as your code suggests, just call

      >msvcrt.getch() directly. This is a blocking call - it won't return until

      >a key is pressed. If you don't want to block, use msvcrt.kbhit() to

      >check whether a key is available before calling getch().

      Thanks, Kent, but I'm afraid I don't know what a blocking call is.

      Yes, I only want to run on Windows.

      import msvcrt

      c = 0

      while True:

      c += 1

      (What goes here?) # Not 'if msvcrt.getch() == "k":', it seems.

      break

      print c

      What I want to do is start the loop spinning, then hit "k" at some

      point, and see what c is.

      ****

      Tutor maillist - Tutor (AT) python (DOT) org

      #4; Mon, 05 May 2008 13:56:00 GMT
    • **** Moores wrote:

      At 10:55 AM 8/27/2006, Kent Johnson wrote:

      >getch is a callable object (it implements __call__()) and is used like a

      >function.

      >>

      >If you only want to run on Windows, as your code suggests, just call

      >msvcrt.getch() directly. This is a blocking call - it won't return until

      >a key is pressed. If you don't want to block, use msvcrt.kbhit() to

      >check whether a key is available before calling getch().

      >

      >

      Thanks, Kent, but I'm afraid I don't know what a blocking call is.

      Blocking I/ is an I/ operation that doesn't return to the caller until

      it completes. In the case of blocking input, the input call (getch() in

      this case) won't return until some data is available. This is not what

      you want - you don't want to press a key each time through the loop, you

      want the loop to free-run until you press 'k', then exit. A non-blocking

      getch() would be perfect - a call that returns a character if one is

      available, but returns some kind of non-character marker if there is no

      character.

      I think this will work, using None as the marker for no character available:

      def getch_nonblocking():

      if msvcrt.kbhit():

      return msvcrt.getch()

      return None

      Then substitute getch_nonblocking() for getch() in your loop below.

      Kent

      Yes, I only want to run on Windows.

      import msvcrt

      c = 0

      while True:

      c += 1

      (What goes here?) # Not 'if msvcrt.getch() == "k":', it seems.

      break

      print c

      What I want to do is start the loop spinning, then hit "k" at some

      point, and see what c is.

      ****

      >

      >

      >

      Tutor maillist - Tutor (AT) python (DOT) org

      --

      Tutor maillist - Tutor (AT) python (DOT) org

      #5; Mon, 05 May 2008 13:57:00 GMT
    • At 11:48 AM 8/27/2006, Kent Johnson wrote:

      >Blocking I/ is an I/ operation that doesn't return to the caller until

      >it completes. In the case of blocking input, the input call (getch() in

      >this case) won't return until some data is available. This is not what

      >you want - you don't want to press a key each time through the loop, you

      >want the loop to free-run until you press 'k', then exit. A non-blocking

      >getch() would be perfect - a call that returns a character if one is

      >available, but returns some kind of non-character marker if there is no

      >character.

      >

      >I think this will work, using None as the marker for no character available:

      >def getch_nonblocking():

      if msvcrt.kbhit():

      return msvcrt.getch()

      return None

      >

      >Then substitute getch_nonblocking() for getch() in your loop below.

      >

      >Kent

      Yes, I only want to run on Windows.

      import msvcrt

      c = 0

      while True:

      c += 1

      (What goes here?) # Not 'if msvcrt.getch() == "k":', it seems.

      break

      print c

      What I want to do is start the loop spinning, then hit "k" at some

      point, and see what c is.

      import msvcrt

      def getch_nonblocking():

      if msvcrt.kbhit():

      return msvcrt.getch()

      return None

      c = 0

      while True:

      c += 1

      if getch_nonblocking() == "k":

      print c

      When I run this, wait a bit, then press "k", "k" is printed. In fact,

      whatever I type gets printed. No break, no c.

      ****

      Tutor maillist - Tutor (AT) python (DOT) org

      #6; Mon, 05 May 2008 13:58:00 GMT
    • Alan Gauld has also been trying to help me by direct email. But his suggested

      import msvcrt

      c = 0

      while True:

      c += 1

      if msvcrt.kbhit():

      if msvcrt.getch() == 'k':

      break

      else: continue

      print c

      didn't work for me either. I was just about to tell him so, when I

      remembered to try to run it not using IDLE, i.e., by just clicking on

      the script icon (to use the console that the term?) I knew I'd

      have to add a line something like

      raw_input("\n\nPress the enter key to exit.")

      and when I did the script ran just as I'd hoped!

      My thanks to Kent and Alan.

      **** Moores

      Tutor maillist - Tutor (AT) python (DOT) org

      #7; Mon, 05 May 2008 13:59:00 GMT
    • So now I have keyPress-b.py. It works well, except that I have to ^C

      to quit it.

      #keyPress-b.py

      import msvcrt, time

      print \

      """

      After pressing Enter to start,

      press Space to get first and subsequent measurements of spin.

      Use Ctrl+C to quit.

      """

      answer = raw_input("Press Enter to start ")

      while answer == "":

      c = 0

      timeStart = time.time()

      while True:

      c += 1

      if msvcrt.kbhit():

      if msvcrt.getch() == ' ':

      break

      else:

      continue

      timeEnd = time.time()

      print

      print c, "spins"

      print "Time was %.4g seconds" % (timeEnd - timeStart)

      print "Spin rate was %.f per second" % (c/(timeEnd - timeStart))

      print "Bye."

      time.sleep(1)

      end of keyPress-b.py

      I've tried revising in all sorts of ways, but none are satisfactory.

      Here's keyPress-b3.py, into which I've added ways to get "Hello" by a

      key press, and also a way to quit by pressing "q".

      It's flaky. I usually have to hit Space, "h" or "q" several times (or

      hold them down) before they will work.

      #keyPress-b3.py

      import msvcrt, time

      print \

      """

      After pressing Enter to start,

      press Space to get first and subsequent measurements.

      Press h to print "Hello".

      Press and hold down q to quit.

      """

      answer = raw_input("Press Enter to start ")

      while answer == "":

      c = 0

      timeStart = time.time()

      while True:

      c += 1

      if msvcrt.kbhit():

      if msvcrt.getch() == ' ':

      break

      if msvcrt.kbhit():

      if msvcrt.getch() == 'h':

      print "Hello"

      if msvcrt.kbhit():

      if msvcrt.getch() == 'q':

      answer = "quit"

      timeEnd = time.time()

      print

      print c, "spins"

      print "Time was %.4g seconds" % (timeEnd - timeStart)

      print "Spin rate was %.f per second" % (c/(timeEnd - timeStart))

      print "Bye."

      time.sleep(5)

      end of

      Advice, please, on how to correct the flakiness.

      Also, I can't figure out why the FIRST spin measurement of

      spins/second is usually almost double the subsequent measurements. E.g.,

      26536 spins

      Time was 0.765 seconds

      Spin rate was 34688 per second

      27632 spins

      Time was 1.547 seconds

      Spin rate was 17862 per second

      **** Moores

      Windows XP, Python 2.43

      Tutor maillist - Tutor (AT) python (DOT) org

      #8; Mon, 05 May 2008 14:00:00 GMT
    • Hi ****,

      I'll move my replies back into the public discussion

      while answer == "":

      c = 0

      timeStart = time.time()

      while True:

      c += 1

      if msvcrt.kbhit():

      if msvcrt.getch() == ' ':

      break

      if msvcrt.kbhit():

      if msvcrt.getch() == 'h':

      print "Hello"

      if msvcrt.kbhit():

      if msvcrt.getch() == 'q':

      answer = "quit"

      You only need one kbhit to tell you if any key has been hit at all.

      Then you can use getch to fetch that key and store it in a variable.

      Then the code above turns into:

      while True:

      if kbhit(): key = getch()

      if key == ' ': break

      elif key == 'h': print 'hello'

      elif key == 'q': answer = 'quit'

      Does that make sense?

      Alan G.

      Tutor maillist - Tutor (AT) python (DOT) org

      #9; Mon, 05 May 2008 14:02:00 GMT
    • At 01:57 AM 8/28/2006, Alan Gauld wrote:

      while answer == "":

      c = 0

      timeStart = time.time()

      while True:

      c += 1

      if msvcrt.kbhit():

      if msvcrt.getch() == ' ':

      break

      if msvcrt.kbhit():

      if msvcrt.getch() == 'h':

      print "Hello"

      if msvcrt.kbhit():

      if msvcrt.getch() == 'q':

      answer = "quit"

      >

      >You only need one kbhit to tell you if any key has been hit at all.

      >Then you can use getch to fetch that key and store it in a variable.

      >Then the code above turns into:

      >

      >while True:

      if kbhit(): key = getch()

      if key == ' ': break

      elif key == 'h': print 'hello'

      elif key == 'q': answer = 'quit'

      >

      >Does that make sense?

      Yes! Now my script runs perfectly. And I can add other keys for doing

      other things on the fly, as it were. That's what I was after.

      Thanks, Alan.

      ****

      Tutor maillist - Tutor (AT) python (DOT) org

      #10; Mon, 05 May 2008 14:03:00 GMT