1

I am writing a C program which takes user input. The user input requires some special characters which I want the reserve special keys on the keyboard for.

To keep it simple, suppose I want any occurrence of the symbol \ to be replaced with λ. So that if the user types \x.x, they see λx.x.

To clarify, I don't want their input to be repeated back to them with \ replaced by λ, I want them to enter \ but see λ immediately in the console.

Is there an easy way to do this?


Edit: Since it seems something like this is OS specific, I'd like a unix/linux solution.

Luke Collins
  • 1,433
  • 3
  • 18
  • 36
  • 1
    Not directly easy no, but it's possible. How to do it depends very much on the terminal and operating system through, so please add tags for at least the OS. – Some programmer dude Feb 11 '19 at 19:27
  • 2
    Not with standard C. You will need something like `curses` library. – Eugene Sh. Feb 11 '19 at 19:27
  • So it's a systems programming thing then. – Luke Collins Feb 11 '19 at 19:28
  • 3
    Yes it is. Generally it's done by reading input without the terminal echoing the input. Then you do the echoing inside your program, and can then replace the special keys with any suitable symbol. And for Linux then do research about the *curses* library (which simplify a lot if you don't want to do the terminal-handling more explicitly yourself). – Some programmer dude Feb 11 '19 at 19:30
  • 2
    Well, yes, you will have to put the keyboard in non-cannonical mode (how depends on the OS being used, e.g. Linux and `tcsetattr`) and then write an input handler that catches the `'\'` and replaces with the little lambda (if your terminal supports it). There are a number of password checking examples that do something similar on this site. – David C. Rankin Feb 11 '19 at 19:30

2 Answers2

0

I think this is a great question with many applications! For this, termios.h is better than curses.h in my opinion because with termios.h you can input to the terminal as you normally would, without requiring a fullscreen application like curses seems to. Also, you do not need to compile with a library (curses requires -lcurses option in your compiler). Note that this solution requires you to implement your own getch-like function. In addition, this solution is linux specific (AFAIK)

#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <locale.h>
#include <wchar.h>

wint_t mygetwch()
{
    // Save the current terminal details
    struct termios echo_allowed;
    tcgetattr(STDIN_FILENO, &echo_allowed);

    /* Change the terminal to disallow echoing - we don't
       want to see anything that we don't explicitly allow. */
    struct termios echo_disallowed = echo_allowed;
    echo_disallowed.c_lflag &= ~(ICANON|ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &echo_disallowed);

    // Get a wide character from keyboard
    wint_t wc = getwchar();

    // Allow echoing again
    tcsetattr(STDIN_FILENO, TCSANOW, &echo_allowed);

    // Return the captured character
    return wc;
}

int main()
{
    // Imbue the locale so unicode has a chance to work correctly
    setlocale(LC_ALL, "");

    // Start endless loop to capture keyboard input
    while (1) {
        wint_t wc = mygetwch(); // get a wide character from stdin
        if (wc==WEOF)           // exit if that character is WEOF
            break;
        else if (wc==L'\\')     // replace all instances of \ with λ
            wprintf(L"%lc",L'λ');
        else                    // otherwise just print the character
            wprintf(L"%lc",wc);
    }
    return 0;
}
0

Is there an easy way to do this?

Yes, it's easy with a readline macro mapping \ to λ. Demo program:

/* cc -lreadline */

#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>

main()
{
    // bind the backslash key to lambda's UTF-8 code 0xCE 0xBB (cebb)
    rl_parse_and_bind((char []){"\"\\\\\":'\xCE\xBB'"});
    unsigned char *line, *cp;
    while (cp = line = readline("? "))
    {
        while (*cp) printf("%3x", *cp++); puts("");
        free(line);
    }
}

Of course a UTF-8 enabled terminal is needed for the display of λ.

Armali
  • 18,255
  • 14
  • 57
  • 171