4

I want to make a specific combination of keyboard keys in order to terminate a process e.x I want to terminate the process by pressin CTRL + C ^ 3 (pressing three times C: CTRL +CCC).

So basically I want to replace CTRL + C with CTRL + CCC

peterh
  • 9,731

2 Answers2

9

The default behavior of Ctrl+C is a combination of two things. The terminal driver¹ does not transmit this key press, but instead sends a SIGINT signal to the foreground process². By default, a process dies when it receives a SIGINT, but the process can set a signal handler, and then it'll run the signal handler when it receives SIGINT.

There's no way to configure the terminal driver to only convert the third Ctrl+C in a row to kill the foreground process. To do that, you need to count to three in your program. There are two ways you can do that, which will behave differently if the user presses something else between the Ctrl+C's.

One way is to disable Ctrl+C's behavior of sending a signal and telling the terminal driver to instead pass it through. You can do that by calling stty intr \^- from a shell script or tcsetattr(fd, &termios) with termios.c_cc[VINTR] set to _POSIX_VDISABLE from C. Then, in your program's input processing loop, exit when you've seen three Ctrl+C's in a row.

The other way is to set a signal handler for SIGINT that counts how many times it's been invoked and terminates the program the third time. You may want to reset the counter if there's normal input in between.

¹ Not the terminal emulator, the generic part of the operating system that handles all terminals.
² I'm only explaining the simple case. This is not a treatise on how the terminal driver works.

  • Can you briefly give me an example for second way ? – Albion Shala Jun 01 '19 at 21:06
  • @AlbionShala You never said what programming language you're using. And anyway programming is off-topic here when it goes beyond simple scripting. But a web search with the name of your programming language and "signal handler" and "tutorial" should give you examples. – Gilles 'SO- stop being evil' Jun 01 '19 at 21:14
  • Actually yes i mentioned that i am using C in Linux but it was editted, anyhow thanks a lot, i really appreciate it – Albion Shala Jun 01 '19 at 21:17
  • IGNBRK has nothing to do with Ctrl-C being translated to SIGINT. It's ISIG in c_lflag who is controlling that (also c_cc[VINTR] can be set to 0 to disable it, or to another char). stty -intr is not a valid command. A VINTR/Ctrl-C won't send a signal to the "foreground process", but to the foreground process group (job), ie. when running a|b|c and pressing ^C, a signal will be sent to the a, b and c processes. –  Jun 01 '19 at 21:53
  • @mosvy Thanks, I hadn't done that in a while and I should have spent more than 5s re-reading the man page. Regarding process groups, see footnote 2. – Gilles 'SO- stop being evil' Jun 01 '19 at 22:04
  • @AlbionShala But the fact that a SIGINT will be sent to all the processes in the group is essential, because it makes clear the dangerous futility of setting up a SIGINT handler as a way of key-binding; if the program is run as part of a pipeline or through a wrapper, it will still be (indirectly) killed by the 1st ^C (it will get a SIGPIPE when trying to write to the pipe, or have its children summarily killed while it's still counting up to 3). And changing tty attributes is no better, unless it's a full screen app (like vi or emacs) which has the tty all to itself. –  Jun 01 '19 at 23:22
5

You can't change key binding in your code because a signal is a software generated interrupt that is sent to a process by the OS. when user press ctrl-c another process tell something to your process.

There are fix set of signals that can be sent to a process. signals are similar to interrupts, the difference being that interrupts are mediated by the processor and handled by the kernel while signals are mediated by the kernel (possibly via system calls) and handled by processes. The kernel may pass an interrupt as a signal to the process that caused it (typical examples are SIGSEGV, SIGBUS, SIGILL and SIGFPE).

you can remap signal key binding in your computer with stty

Enable Ctrl+C for copy and Ctrl+Shift+C for interrput

https://docstore.mik.ua/orelly/unix3/upt/ch05_08.htm

if you want exactly 3 times ctrl-c. you can count SIGINT and break the program when 3 times ctrl-c pressed. (pressing three times C: CTRL +CCC).

#include<stdio.h>
#include<signal.h>
#include<unistd.h>

void sig_handler(int signo)
{
    static int counter=0;
    if (signo == SIGINT)
        counter++;
    printf("received SIGINT %d times\n", counter);
    if (counter == 3)
        exit(0);
}

int main() 
{ 
    if (signal(SIGINT, sig_handler) == SIG_ERR)
        printf("\ncan't catch SIGINT\n");
    while(1) 
        sleep(1);
    return 0;
}
  • What happens if I want to terminate with CTRL + AAA instead of CTRL + CCC? – Abhik Bose Jun 01 '19 at 19:22
  • 1
    Changing key binding in your code is not possible as far as i know. but like i said you can change signal key binding in stty and in your terminal emulator. – Rasool Ziafaty Jun 01 '19 at 19:29
  • 1
    you do not use printf and exit in signal handlers, ever. just think what happens if a SIGINT is coming while the program is running another printf or flushing the stdio buffers, or within a handler registered with atexit(3). –  Jun 01 '19 at 19:54
  • @AbhikBose You can easily change the keybinding from Ctrl-C to Ctrl-A with stty intr '^A' (from C you do that with tcsetattr(), look up the termios(3) manpage). –  Jun 01 '19 at 19:56
  • 1
    Thanks @mosvy but this is a proof of concept code not a real one. why you don't add an answer and explain us more about what you know. because i didn't get what you said in your last comment. – Rasool Ziafaty Jun 01 '19 at 20:05
  • 2
    @RasoolZiafaty just because it's a proof of concept it should be correct. Besides, doing it correctly will make it shorter and simpler, not the reverse. Notice that the use of signal() instead of sigaction() is also highly dubious: on some systems, signal(3) will set the handler as with SA_RESETHAND ie the handler will be disabled after the first ^C. –  Jun 01 '19 at 20:11
  • I tried this but actually the program stops at the very first C i press still like in default mode, i press CTRL +C and it stops – Albion Shala Jun 01 '19 at 20:16