English 中文(简体)
C I/O: 处理Windows指挥线上的关键投入
原标题:C I/O: Handling keyboard input on the Windows command line

我正在创设一个互动的指挥线应用,该应用应当既适用于六氯环己烷,也适用于Windows操作系统。 在该方案内,有要求从<代码>stdin中获取关键投入的提示。 每当即,用户只能进入特定的ASCII特性和特定特性。 如果<代码><E> or <Enter> keys are pressed;<Enter>提交由内部方案国家迅速评估的指令,<爱因>>和>;触发指示,无须迅速提交。 目前,这只促使在欧罗特开展工作,因为我不知道如何将其用于Windows。

The input prompt is currently implemented via two functions: the generic handler function prompt_user_input, and the platform-layer function platform_console_read_key, which only has a working Linux implementation at the moment--not Windows.

www.un.org/spanish/ecosoc 类似工作:

  1. Immediately read up to six bytes from stdin into a buffer (multiple bytes allows for parsing ANSI escape codes for non-ASCII keys).
  2. If the first byte read is not an escape sequence indicator, the first byte is returned as a regular ASCII character.
  3. If the first byte is an escape sequence indicator, bytes 2-6 of the buffer are parsed.
    1. If the rest of the buffer is empty, then the character is standalone, so do step 2.
    2. If there is something in the latter part of the buffer, then it is actually an escape sequence. Attempt to parse and return it as an "extended key code" (which is just a #define for an integer > 255).
    3. If there is something in the latter part of the buffer, and it is an escape code which is not handled by the function, return the special value 0.
  4. If there is any kind of critical I/O error, return the special value KEY_COUNT.

因此,我照此读了这样的特性,因为我处理通过<条码>归还的每项关键代码,这些代码分别载于<条码>prompt_user_input,以确定如何开展该方案。 <代码>prompt_user_input 类似工作:

  1. Take an argument which is the maximum number of characters which may be input.
  2. Read keys via platform_console_read_key in an infinite loop.
  3. If last key matches <Enter> or <Escape>, break from the loop.
  4. Otherwise, see if it is a valid key using a filter_user_input predicate.
    1. If it is valid, add it to an input buffer, as long as the number of the characters written to the buffer does not exceed that allowed by the function argument. Also print it to the screen (i.e. "echo" functionality).
    2. If max writes reached, or key is invalid, continue (i.e. goto step 2).

我的问题是,我如何为Windows平台层执行platform_console_read_key。 我怎么能立即读到Windows终端的关键板投入的6种? 此外,我如何确定这些六种 by子的编排方式,以便我能够把视窗的关键代码描绘成功能的回报值,从而使功能的行为与光栅版的相同?

下面是实用的六氯环己烷代码,平台层包括<代码><termios.h>和<unistd.h>。 我略去了一些不相干的代码,并添加了一些<条码><>印本/代码>的说明,以澄清和方便测试。 注:prompt_user_input 参考了全球<代码>(*state ).in ,即投入缓冲;假设该代码总是大于所供应的<代码>char_count。

bool
prompt_user_input
(   const u8 char_count
)
{
    printf ( "Type your response: " );

    // Clear any previous user input.
    memset ( ( *state ).in , 0 , sizeof ( ( *state ).in ) );

    KEY key;
    u8 indx = 0;
    for (;;)
    {
        key = platform_console_read_key ();
        
        if ( key == KEY_COUNT )
        {
            // ERROR
            return false;
        }
        
        // Submit response? Y/N
        if ( key == KEY_ENTER )
        {
            return true;
        }
        
        // Quit signal? Y/N
        if ( key == KEY_ESCAPE )
        {
            //...
            return true;
        }

        // Handle backspace.
        if ( key == KEY_BACKSPACE )
        {
            if ( !indx )
            {
                continue;
            }
            indx -= 1;
            ( *state ).in[ indx ] = 0;
        }

        // Response too long? Y/N
        else if ( indx >= char_count )
        {
            indx = char_count;
            continue;
        }

        // Invalid keycode? Y/N
        else if ( !filter_user_input ( key ) )
        {
            continue;
        }

        // Write to input buffer.
        else
        {
            ( *state ).in[ indx ] = key;
            indx += 1;
        }

        // Render the character.
        printf ( "%s"
               , ( key == KEY_BACKSPACE ) ? " "
                                          : ( char[] ){ key , 0 }
               );
    }
}

KEY
platform_console_read_key
( void )
{
    KEY key = KEY_COUNT;

    // Configure terminal for non-canonical input.
    struct termios tty;
    struct termios tty_;
    tcgetattr ( STDIN_FILENO , &tty );
    tty_ = tty;
    tty_.c_lflag &= ~( ICANON | ECHO );
    tcsetattr ( STDIN_FILENO , TCSANOW , &tty_ );
    fflush ( stdout ); // In case echo functionality desired.
    
    // Read the key from the input stream.
    char in[ 6 ]; // Reserve up to six bytes to handle special keys.
    platform_memory_clear ( in , sizeof ( in ) );
    i32 result = read ( STDIN_FILENO , in , sizeof ( in ) );
    
    // I/O error.
    if ( result < 0 )
    {
        key = KEY_COUNT;
        goto platform_console_read_key_end;
    }

    // End of transmission (I/O error).
    if (   in[ 0 ] == 4
        || in[ 1 ] == 4
        || in[ 2 ] == 4
        || in[ 3 ] == 4
        || in[ 4 ] == 4
        || in[ 5 ] == 4
        )
    {
        key = KEY_COUNT;
        goto platform_console_read_key_end;
    }

    // ANSI escape sequence.
    if ( *in ==  33  || *in ==  ~  )
    {
        // Standalone keycode.
        if ( !in[ 1 ] )
        {
            switch ( *in )
            {
                case  33 : key = KEY_ESCAPE ;break;
                case  ~    : key =  ~         ;break;
                default    : key = 0          ;break;
            }
            goto platform_console_read_key_end;
        }

        // Composite keycode.
        else
        {
            if ( in[ 1 ] ==  [  )
            {
                // ...
            }
            else
            {
                key = 0;
            }
            goto platform_console_read_key_end;
        }
    }

    // Standalone ASCII character.
    else
    {
        // Backspace key is mapped to ASCII  delete  (for some reason).
        key = ( *in == KEY_DELETE ) ? KEY_BACKSPACE : *in;
        goto platform_console_read_key_end;
    }

    // Reset terminal to canonical input mode.
    platform_console_read_key_end:
        tcsetattr ( STDIN_FILENO , TCSANOW , &tty );
        fflush ( stdout ); // In case echo functionality desired.
        return key;
}
问题回答

这里是一个简单的解决办法用户:Weather Vane,背后,我已使用多年。 操作该守则还将使你能够发现并从而界定更多的钥匙——你知道,F1,F2,也arrow keys,等等。

NOTE: you want that add of 256 to _getch() for the extended keys in GetKey(). This places extended key values outside the range of common keys like A thru Z....noting that F10 by itself would only be value 68 -- and that matches with the key value for SHIFT + D . No good, see?

该代码还将用于<代码>CTRL+主要 com船。 还在限额内为<代码>ALT关键切船设计。 www.un.org/spanish/ecosoc 主要 com船的发价很少,因为ALT+TAB key,例如,在MSWindows的应用之间转换。 因此,当你开始与监督厅竞争,以开展关键的中风行动时,行为可能会变得不明确。 并且——根据经验——你可以增加100条法典,以纠正这些事情,但只是名义上提高业绩和范围。

守则在视觉演播室汇编,并在Win10上测试,然后张贴到SO。

#include <stdio.h>
#include <conio.h>

#define KEY_ESCAPE  27
#define KEY_BACKSPACE 8  
#define KEY_ENTER 13
#define KEY_F10  324


/*---------------------------------------------

    GetKey()

    Thanks John Wagner
*---------------------------------------------*/
int GetKey(void) 
{
    int c = _getch();
    if(c ==0 || c == 224)
        c = 256 + _getch(); /* If extended key (like F10), add 256. */
    return c;
}

int main () 
{
    int key;

    printf("Hit a key -- ESC key quits
");

    do{
        key = GetKey();

        switch(key)
        {
            case KEY_ENTER:
                printf("ENTER key detected.
");
            break;

            case KEY_BACKSPACE:
                printf("BACKSPACE key detected.
");
            break;

            case KEY_F10:
                printf("MENU(F10) key detected.
");
            break;

            case  y :
            case  Y :
                printf("User says yes!
");
            break;

            case  n :
            case  N :
                printf("User says No!
");
            break;

            default:
                printf("Key value: %d
", key);
            break;
        }

    }while (key != KEY_ESCAPE);

    return 0;
}




相关问题
Fastest method for running a binary search on a file in C?

For example, let s say I want to find a particular word or number in a file. The contents are in sorted order (obviously). Since I want to run a binary search on the file, it seems like a real waste ...

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

Tips for debugging a made-for-linux application on windows?

I m trying to find the source of a bug I have found in an open-source application. I have managed to get a build up and running on my Windows machine, but I m having trouble finding the spot in the ...

Trying to split by two delimiters and it doesn t work - C

I wrote below code to readin line by line from stdin ex. city=Boston;city=New York;city=Chicago and then split each line by ; delimiter and print each record. Then in yet another loop I try to ...

Good, free, easy-to-use C graphics libraries? [closed]

I was wondering if there were any good free graphics libraries for C that are easy to use? It s for plotting 2d and 3d graphs and then saving to a file. It s on a Linux system and there s no gnuplot ...

Encoding, decoding an integer to a char array

Please note that this is not homework and i did search before starting this new thread. I got Store an int in a char array? I was looking for an answer but didn t get any satisfactory answer in the ...

热门标签