Python Forum
msvcrt.getch prints twice inside loop
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
msvcrt.getch prints twice inside loop
#1
A recent Windows update (Windows 10 version 1803 feature update) seems to have changed the behaviour of msvcrt.getch(). I confirmed this by testing on a second computer before and after the update.

this code:
import msvcrt

while True:
    character = msvcrt.getch()
    print('Hello World')
prints twice for each keystroke:
Output:
Hello World Hello World
tested with python 3.6.5 and 3.5.3

Am I going crazy, or am I using msvcrt.getch() wrong since the Windows update?

What I really need is to put a keystroke in to a variable and print it to the command line, but it's printing an extra line after each character and my program no longer works.

hitting the 'b' key three times with this code:
import msvcrt

while True:
    character = msvcrt.getch().decode('utf-8')
    print(character)
Gives this output:
Output:
b b b
Any ideas as to what has changed?
Reply
#2
Can do a test,use repr() to see what really going on.
import msvcrt

while True:
    character = msvcrt.getch()
    print(repr(character))
    if character == b'q':
        break
So i get b'\x00' normal key and b'\xe0' for function keys.
>>> import msvcrt
>>> help(msvcrt.getch)
Help on built-in function getch in module msvcrt:

getch()
    Read a keypress and return the resulting character as a byte string.
    
    Nothing is echoed to the console. This call will block if a keypress is
    not already available, but will not wait for Enter to be pressed. If the
    pressed key was a special function key, this will return '\000' or
    '\xe0'; the next call will return the keycode. The Control-C keypress
    cannot be read with this function.
So it say that next call will return keycode.
Then can write it like this.
import msvcrt
import sys

while True:
    ch = msvcrt.getch()
    if ch in b'\x00':
        ch = msvcrt.getch() # Second call returns the scan code
    if ch in b'\xe0':
        ch = msvcrt.getch() # Second call Function keys
    if ch == b'q':
       sys.exit()
    else:
       print(f'Key Pressed: {ch}')
Output:
E:\1 λ python b1.py Key Pressed: b'h' Key Pressed: b'e' Key Pressed: b'l' Key Pressed: b'l' Key Pressed: b'o' Key Pressed: b'I' Key Pressed: b'I' Key Pressed: b'I'
Writing hello and 3 times Page Up,as you see no extra space.
Not doing any encoding here utf-8 may be wrong as key are ASCII.
Here is the table.
I pushed Page Up 3 times last b'I'
Let see if it match with table that say Page Up is 73.
>>> k = b'I'
>>> ord(k)
73
Also look at doc there are eg msvcrt.getwche() which return Unicode.
Did not test that,maybe it easier to keep all as bytes and use ord() if need also need function key decoding.
Reply
#3
Snippsat, I didn't think I'd get such a helpful response so quickly. I think I understand what is happening now.

When I run:
import msvcrt

count = 0

while True:
    count += 1
    character = msvcrt.getch()
    
    print('loop ' + str(count))
    print(character, end='\n\n')
        
    if character == b'q':
        break
I get two lines returned for each key press because the loop goes through two iterations per key press.
Hitting the 'E' key once returns this:
Output:
loop 1 b'e' loop 2 b'\x00'
According to the doc you referenced, what I should have been using all this time is msvcrt.getwch() to put a unicode character in to a variable without echoing the key stroke to the command line.

I still wonder why my programs were running fine until Windows 10 feature update 1803, but at least I have the right fix.

Thank you so much for your help!
Reply
#4
I just realised I have one Windows 10 computer not updated to 1803 yet, and sure enough, msvcrt.getch() does not return the scan code. Only one call to msvcrt.getch() is made when in a loop:

The same script as before only returns the key pressed:

Output:
loop 1 b'e'
What changed with Windows feature update 1803?
Reply
#5
Great stuff!

BTW ReallyBigTeeth,
You can simplify your print statement below with:
print('loop', count)
(Jun-23-2018, 05:29 AM)ReallyBigTeeth Wrote: When I run:
import msvcrt

count = 0

while True:
    count += 1
    character = msvcrt.getch()
    
    print('loop ' + str(count))
    print(character, end='\n\n')
        
    if character == b'q':
        break
Reply
#6
Good point. I think I get that from converting character and string types in C++. It drives me insane. I wish I could you use python syntax for C++ code.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Variable definitions inside loop / could be better? gugarciap 2 375 Jan-09-2024, 11:11 PM
Last Post: deanhystad
  How to create a variable only for use inside the scope of a while loop? Radical 10 1,526 Nov-07-2023, 09:49 AM
Last Post: buran
  zfill prints extra et the end of a var tester_V 4 850 Mar-24-2023, 06:59 PM
Last Post: tester_V
  Help adding a loop inside a loop Extra 31 4,337 Oct-23-2022, 12:16 AM
Last Post: Extra
  variable prints without being declared. ClockPillow 2 1,771 Jul-11-2021, 12:13 AM
Last Post: ClockPillow
  Adding to the dictionary inside the for-loop - weird behaviour InputOutput007 5 2,651 Jan-21-2021, 02:21 PM
Last Post: InputOutput007
  why print('\n') produced 2 new lines instead of 1 - Located inside a FOR loop JulyFire 2 2,466 Jan-10-2021, 01:50 AM
Last Post: JulyFire
  Output prints Account.id at the end? LastStopDEVS 5 2,718 Dec-19-2020, 05:59 AM
Last Post: buran
  Try/Exept prints only ones tester_V 11 3,738 Nov-03-2020, 02:38 AM
Last Post: tester_V
  Creating a variables inside FOR loop zazas321 5 4,040 Sep-16-2020, 04:42 PM
Last Post: Naheed

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020