Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ctrl-c not behaving as expected #95737

Open
Fakesum opened this issue Aug 6, 2022 · 7 comments
Open

Ctrl-c not behaving as expected #95737

Fakesum opened this issue Aug 6, 2022 · 7 comments
Labels
3.10 OS-windows type-bug An unexpected behavior, bug, or error

Comments

@Fakesum
Copy link

Fakesum commented Aug 6, 2022

Bug report

ctrl-c does not raise a keyboard interrupt. Problem started when modifed VS 2022 installation to include windows 10 sdk from the visual studio installer. I have already tried to repair and reinstall python and restart my computer but it the problem stays the same. when python is run in shell mode it just exits when ctrl-c is pressed but does not raise the KeyboardInterrupt when ctrl-c is pressed in script without exiting.

Your environment

  • CPython versions tested on: 3.10.5
  • Operating system and architecture: windows 10
vokoscreenNG-2022-08-06_14-28-40.mp4
@Fakesum Fakesum added the type-bug An unexpected behavior, bug, or error label Aug 6, 2022
@eryksun
Copy link
Contributor

eryksun commented Aug 6, 2022

It will help to know what terminal you're using -- classic console, Windows Terminal, ConEmu, something else?

@eryksun
Copy link
Contributor

eryksun commented Aug 6, 2022

Please try the following script to find out whether typing Ctrl-C is sending the console control event CTRL_C_EVENT (0). Typing Ctrl-Break (if available on your keyboard) should send CTRL_BREAK_EVENT (1) and exit.

import time
import ctypes

kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

CTRL_C_EVENT = 0

@ctypes.WINFUNCTYPE(ctypes.c_ulong, ctypes.c_ulong)
def handler(event):
    print('event:', event)
    if event != CTRL_C_EVENT:
        return False 
    return True

print('Type Ctrl-Break to exit.')
kernel32.SetConsoleCtrlHandler(handler, True)
while True:
    time.sleep(1)

@Fakesum
Copy link
Author

Fakesum commented Aug 6, 2022

I am using the standard windows cmd and I don't have break key on my keyboard.When runing the script it does not respond to ctrl-c.

@eryksun
Copy link
Contributor

eryksun commented Aug 6, 2022

Running the CMD shell from Explorer allocates a classic console (i.e. an instance of "conhost.exe"). It's the inherited console that matters here, not the shell.

It seems that the Ctrl-C event is disabled in the Python process. This process state is either inherited from the parent process or enabled by creating a process in a new process group (i.e. the CREATE_NEW_PROCESS_GROUP process creation flag). The CMD shell's start command creates a process in a new group when the /b option is used. This option is meant to run a background process that shouldn't be interrupted by Ctrl-C.

Here's a modified version of the above script that manually enables Ctrl-C via SetConsoleCtrlHandler(). If I'm right, this script should print "event: 0" on a new line each time that Ctrl-C is pressed.

import time
import ctypes

kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

CTRL_C_EVENT = 0

# Enable CTRL_C_EVENT for the current process.
kernel32.SetConsoleCtrlHandler(None, False)

@ctypes.WINFUNCTYPE(ctypes.c_ulong, ctypes.c_ulong)
def handler(event):
    print('event:', event)
    if event != CTRL_C_EVENT:
        return False 
    return True

kernel32.SetConsoleCtrlHandler(handler, True)

print('Type Ctrl-Break to exit.')
while True:
    time.sleep(1)

On a related note, if the Ctrl-C event is disabled, Python's console read has a bug. In this case, the canceled read gets mistakenly handled as an empty read (i.e. EOF), which is why the REPL exits. We know that typing Ctrl-C canceled the read in the console and set the last error to ERROR_OPERATION_ABORTED, so there's no reason to confuse it with EOF.

@Fakesum
Copy link
Author

Fakesum commented Aug 7, 2022

uhmm... The Problem solved itself? after restarting again it is now raising a KeyboardInterrupt, and the script above works fine

@Fakesum
Copy link
Author

Fakesum commented Aug 7, 2022

it seems that my script is disabling Ctrl-c somehow, but why would that stay even after python is reinstalled and all python processes are killed? . The Script Above does print 'event: 0', Is it suppose to exit? if so it doesn't

@eryksun
Copy link
Contributor

eryksun commented Aug 7, 2022

it seems that my script is disabling Ctrl-c somehow, but why would that stay even after python is reinstalled and all python processes are killed?

The Ctrl+C event can be disabled for a process in three ways:

  • call SetConsoleCtrlHandler(NULL, TRUE)
  • inherit the state from the parent process
  • run as a new process group via CREATE_NEW_PROCESS_GROUP

The Script Above does print 'event: 0', Is it suppose to exit? if so it doesn't

No, it's an infinite loop. Desktop keyboards have a pause/break key, in which case Ctrl-Break sends CTRL_BREAK_EVENT (1), for which the default handler calls ExitProcess(). Most laptops have some way to type the break key, such as Fn-B, in which case use Fn-Ctrl-B or maybe just Fn-B. See keyboards without break key.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.10 OS-windows type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

2 participants