القبض على شخصيات من المدخلات القياسية دون انتظار الدخول إلى الضغط

StackOverflow https://stackoverflow.com/questions/421860

  •  05-07-2019
  •  | 
  •  

سؤال

أنا لا يمكن أبدا أن نتذكر كيف أفعل هذا لأنه يأتي بشكل نادر جدا بالنسبة لي.ولكن في C أو C++, ما هي أفضل طريقة لقراءة حرف من المدخلات القياسية دون انتظار السطر (اضغط على enter).

أيضا من الناحية المثالية فإنه لن أردد إدخال حرف على الشاشة.أنا فقط أريد أن التقاط ضربات المفاتيح مع إحداث شاشة وحدة التحكم.

هل كانت مفيدة؟

المحلول

هذا غير ممكن في المحمولة بطريقة نقية C++, لأنه يعتمد كثيرا على المحطة المستخدمة التي قد تكون مرتبطة مع stdin (وعادة ما خط التخزين المؤقت).إلا أنه يمكنك استخدام مكتبة على أن:

  1. conio المتاحة مع ويندوز المجمعين.استخدام _getch() وظيفة تعطيك شخصية دون انتظار المفتاح Enter.أنا لست متكررة ويندوز المطور, ولكن رأيت زملائي تشمل فقط <conio.h> واستخدامه.انظر conio.h في ويكيبيديا.وهو يسرد getch(), الذي أعلن إهمال في Visual C++.

  2. الشتائم المتاحة لينكس.متوافق الشتائم تطبيقات متوفرة على ويندوز أيضا.كما أن لديها getch() وظيفة.(محاولة man getch لعرض manpage).انظر اللعنات في ويكيبيديا.

أنصح لك أن استخدام الشتائم إذا كنت تهدف عبر منصة التوافق.وقال أنا متأكد من أن هناك الدالات التي يمكنك استخدامها لإيقاف خط التخزين المؤقت (أعتقد أن ما يسمى "وضع الخام", بدلا من "المطبوخ الوضعية" - انظر إلى man stty).لعنات أن التعامل مع ذلك لك في المحمولة الطريقة, إذا لم أكن مخطئا.

نصائح أخرى

في لينكس (وغيرها من أنظمة يونكس مثل) يمكن أن يتم ذلك بطريقة التالية:

#include <unistd.h>
#include <termios.h>

char getch() {
        char buf = 0;
        struct termios old = {0};
        if (tcgetattr(0, &old) < 0)
                perror("tcsetattr()");
        old.c_lflag &= ~ICANON;
        old.c_lflag &= ~ECHO;
        old.c_cc[VMIN] = 1;
        old.c_cc[VTIME] = 0;
        if (tcsetattr(0, TCSANOW, &old) < 0)
                perror("tcsetattr ICANON");
        if (read(0, &buf, 1) < 0)
                perror ("read()");
        old.c_lflag |= ICANON;
        old.c_lflag |= ECHO;
        if (tcsetattr(0, TCSADRAIN, &old) < 0)
                perror ("tcsetattr ~ICANON");
        return (buf);
}

وأساسا لديك لإيقاف تشغيل وضع قانوني (ووضع صدى لقمع ارتداد).

ولقد وجدت هذا في منتدى آخر في حين تبحث لحل نفس المشكلة. لقد تعديله قليلا من ما وجدت. يعمل كبيرة. أنا على التوالي OS X، لذلك إذا كنت تقوم بتشغيل مايكروسوفت، سوف تحتاج إلى العثور على الأمر النظام الصحيح () للتبديل إلى وسائط الخام والمطبوخة.

#include <iostream> 
#include <stdio.h>  
using namespace std;  

int main() { 
  // Output prompt 
  cout << "Press any key to continue..." << endl; 

  // Set terminal to raw mode 
  system("stty raw"); 

  // Wait for single character 
  char input = getchar(); 

  // Echo input:
  cout << "--" << input << "--";

  // Reset terminal to normal "cooked" mode 
  system("stty cooked"); 

  // And we're out of here 
  return 0; 
}

وCONIO.H

والوظائف التي تحتاج إليها هي:

int getch();
Prototype
    int _getch(void); 
Description
    _getch obtains a character  from stdin. Input is unbuffered, and this
    routine  will  return as  soon as  a character is  available  without 
    waiting for a carriage return. The character is not echoed to stdout.
    _getch bypasses the normal buffering done by getchar and getc. ungetc 
    cannot be used with _getch. 
Synonym
    Function: getch 


int kbhit();
Description
    Checks if a keyboard key has been pressed but not yet read. 
Return Value
    Returns a non-zero value if a key was pressed. Otherwise, returns 0.

وlibconio http://sourceforge.net/projects/libconio

أو

وينكس ج ++ تنفيذ conio.h http://sourceforge.net/projects/linux-conioh

#include <conio.h>

if (kbhit() != 0) {
    cout << getch() << endl;
}

وهذا يستخدم kbhit() للتحقق ما إذا كان يتم الضغط على لوحة المفاتيح ويستخدم getch() للحصول على الحرف الذي يتم الضغط عليه.

إذا كنت على النوافذ، يمكنك استخدام PeekConsoleInput لاكتشاف ما إذا كان هناك أي مساهمة،

HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
DWORD events;
INPUT_RECORD buffer;
PeekConsoleInput( handle, &buffer, 1, &events );

وبعد ذلك استخدام ReadConsoleInput إلى "استهلاك" الطابع المدخلات ..

PeekConsoleInput(handle, &buffer, 1, &events);
if(events > 0)
{
    ReadConsoleInput(handle, &buffer, 1, &events);  
    return buffer.Event.KeyEvent.wVirtualKeyCode;
}
else return 0

وإلى أن نكون صادقين وهذا هو من بعض رمز القديم لدي، ولذلك عليك أن عزف قليلا معها.

والشيء باردة على الرغم من أن يقرأ المدخلات دون المطالبة بأي شيء، لذلك لا يتم عرض الأحرف على الإطلاق.

على افتراض ويندوز, نلقي نظرة على ReadConsoleInput وظيفة.

وC و C ++ إلقاء نظرة مجردة للغاية من I / O، وليس هناك طريقة قياسية لفعل ما تريد. هناك طرق القياسية للحصول على الأحرف من دفق الإدخال القياسية، وإذا كان هناك أي الحصول عليها، ويعرف أي شيء آخر إما عن طريق اللغة. وبالتالي فإن أي إجابة يجب أن تكون منصة محددة، وربما يتوقف ليس فقط على نظام التشغيل ولكن أيضا إطار البرنامج.

وهناك بعض التخمينات معقولة هنا، ولكن ليس هناك طريقة للإجابة على سؤالك دون معرفة ما هي البيئة التي تستهدفها.

أقرب شيء إلى المحمولة هو استخدام ncurses مكتبة لوضع المحطة إلى "cbreak الوضع".API العملاق ، إجراءات كنت تريد معظم

  • initscr و endwin
  • cbreak و nocbreak
  • getch

حظا سعيدا!

وأنا استخدم kbhit () لمعرفة ما اذا كان حرف موجود ثم getchar () لقراءة البيانات. على النوافذ، يمكنك استخدام "conio.h". على لينكس، سيكون لديك لتنفيذ kbhit الخاص بك ().

وانظر الرمز أدناه:

// kbhit
#include <stdio.h>
#include <sys/ioctl.h> // For FIONREAD
#include <termios.h>
#include <stdbool.h>

int kbhit(void) {
    static bool initflag = false;
    static const int STDIN = 0;

    if (!initflag) {
        // Use termios to turn off line buffering
        struct termios term;
        tcgetattr(STDIN, &term);
        term.c_lflag &= ~ICANON;
        tcsetattr(STDIN, TCSANOW, &term);
        setbuf(stdin, NULL);
        initflag = true;
    }

    int nbbytes;
    ioctl(STDIN, FIONREAD, &nbbytes);  // 0 is STDIN
    return nbbytes;
}

// main
#include <unistd.h>

int main(int argc, char** argv) {
    char c;
    //setbuf(stdout, NULL); // Optional: No buffering.
    //setbuf(stdin, NULL);  // Optional: No buffering.
    printf("Press key");
    while (!kbhit()) {
        printf(".");
        fflush(stdout);
        sleep(1);
    }
    c = getchar();
    printf("\nChar received:%c\n", c);
    printf("Done.\n");

    return 0;
}

وفيما يلي هو الحل المستخرجة من الخبراء C برمجة: أسرار عميقة ، التي من المفترض أن تعمل على SVR4. ويستخدم <م> stty و <م> IOCTL .

#include <sys/filio.h>
int kbhit()
{
 int i;
 ioctl(0, FIONREAD, &i);
 return i; /* return a count of chars available to read */
}
main()
{
 int i = 0;
 intc='';
 system("stty raw -echo");
 printf("enter 'q' to quit \n");
 for (;c!='q';i++) {
    if (kbhit()) {
        c=getchar();
       printf("\n got %c, on iteration %d",c, i);
    }
}
 system("stty cooked echo");
}

ولقد أردت دائما حلقة لقراءة المدخلات بلدي دون الضغط على مفتاح العودة. هذا العمل بالنسبة لي.

#include<stdio.h>
 main()
 {
   char ch;
    system("stty raw");//seting the terminal in raw mode
    while(1)
     {
     ch=getchar();
      if(ch=='~'){          //terminate or come out of raw mode on "~" pressed
      system("stty cooked");
     //while(1);//you may still run the code 
     exit(0); //or terminate
     }
       printf("you pressed %c\n ",ch);  //write rest code here
      }

    }

ويعمل بالنسبة لي على النوافذ:

#include <conio.h>
char c = _getch();

ويمكنك القيام بذلك باستخدام تنقليا SDL (وبسيطة دايركت مكتبة)، على الرغم من أنني أشك أنك قد لا ترغب سلوكها. عندما حاولت ذلك، واضطررت أن يكون SDL إنشاء إطار فيديو جديد (على الرغم من أنني لم أكن في حاجة إليها لبرنامجي) ويكون هذا الإطار "انتزاع" تقريبا كل لوحة المفاتيح والماوس الإدخال (الذي كان حسنا لاستخدامي لكن يمكن أن تكون مزعجة أو غير قابلة للتطبيق في حالات أخرى). وأظن انها مبالغة وليس يستحق ذلك ما لم قابلية كاملة أمر لا بد منه - على خلاف ذلك في محاولة واحدة من الحلول المقترحة الأخرى

وبالمناسبة، فإن هذا سوف تعطيك اضغط على مفتاح والإفراج عن الأحداث على حدة، إذا كنت في ذلك.

وسأركع توفر طريقة لطيفة للقيام بذلك! أيضا هذا هو أول وظيفة جدا (أستطيع أن أتذكر)، لذلك أي تعليقات على الإطلاق هي موضع ترحيب. وسوف نقدر منها مفيدة، ولكن كل وسهلا بكم!

وتجميع: ز ++ -std = ج ++ 11 -pthread -lncurses .CPP -o

#include <iostream>
#include <ncurses.h>
#include <future>

char get_keyboard_input();

int main(int argc, char *argv[])
{
    initscr();
    raw();
    noecho();
    keypad(stdscr,true);

    auto f = std::async(std::launch::async, get_keyboard_input);
    while (f.wait_for(std::chrono::milliseconds(20)) != std::future_status::ready)
    {
        // do some work
    }

    endwin();
    std::cout << "returned: " << f.get() << std::endl;
    return 0;
}

char get_keyboard_input()
{
    char input = '0';
    while(input != 'q')
    {
        input = getch();
    }
    return input;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top