मानक इनपुट से वर्णों को कैप्चर करें, जिसमें प्रवेश के लिए प्रतीक्षा किए बिना दबाया जा सके


174

मैं कभी याद नहीं कर सकता कि मैं यह कैसे करता हूं क्योंकि यह मेरे लिए इतनी बार आता है। लेकिन सी या सी ++ में, नई इनपुट (प्रेस दर्ज) की प्रतीक्षा किए बिना मानक इनपुट से एक चरित्र को पढ़ने का सबसे अच्छा तरीका क्या है।

आदर्श रूप से यह स्क्रीन पर इनपुट चरित्र को भी प्रतिध्वनित नहीं करेगा। मैं बस कंसोल स्क्रीन को प्रभावित करने के साथ कीस्ट्रोक्स पर कब्जा करना चाहता हूं।


1
@ आदम - क्या आप स्पष्ट कर सकते हैं: क्या आप किसी ऐसे फंक्शन की चाहत रखते हैं, जिसमें कोई पात्र उपलब्ध न होने पर तुरंत वापस आ जाए, या जो हमेशा एक कीस्ट्रोके का इंतजार करेगा?
रॉडी

2
@Roddy - मुझे एक फंक्शन चाहिए जो हमेशा सिंगल कीस्ट्रोक का इंतजार करेगा।
एडम

जवाबों:


99

यह शुद्ध सी ++ में पोर्टेबल तरीके से संभव नहीं है, क्योंकि यह उपयोग किए जाने वाले टर्मिनल पर बहुत अधिक निर्भर करता है, जो इसके साथ जुड़ा हो सकता है stdin(वे आमतौर पर लाइन बफर होते हैं)। हालाँकि आप इसके लिए एक पुस्तकालय का उपयोग कर सकते हैं:

  1. विंडोज कंपाइलर्स के साथ उपलब्ध कॉनियो। _getch()Enter कुंजी की प्रतीक्षा किए बिना आपको वर्ण देने के लिए फ़ंक्शन का उपयोग करें । मैं बार-बार विंडोज डेवलपर नहीं हूं, लेकिन मैंने अपने सहपाठियों को बस इसमें शामिल होने <conio.h>और इसका उपयोग करने के लिए देखा है। conio.hविकिपीडिया पर देखें । यह सूचीबद्ध है getch(), जिसे विजुअल C ++ में पदावनत घोषित किया गया है।

  2. लिनक्स के लिए उपलब्ध शाप। विंडोज के लिए संगत शाप कार्यान्वयन भी उपलब्ध हैं। इसका एक getch()फंक्शन भी है । ( man getchइसके मैनपेज को देखने की कोशिश करें)। विकिपीडिया पर शाप देखें ।

यदि आप क्रॉस प्लेटफॉर्म संगतता के लिए लक्ष्य रखते हैं तो मैं आपको शाप का उपयोग करने की सलाह दूंगा। उस ने कहा, मुझे यकीन है कि ऐसे कार्य हैं जो आप लाइन बफ़रिंग को स्विच करने के लिए उपयोग कर सकते हैं (मेरा मानना ​​है कि इसे "रॉ मोड" कहा जाता है, जैसा कि "पका हुआ मोड" के विपरीत है - देखो man stty)। अगर मैं गलत नहीं हूं तो शाप आपके लिए पोर्टेबल तरीके से काम करेगा।


7
ध्यान दें कि आजकल, ncursesअनुशंसित संस्करण है curses
निधि मोनिका का मुकदमा

4
अगर आपको लाइब्रेरी की जरूरत है तो उन्होंने इसे कैसे बनाया? लाइब्रेरी बनाने के लिए आपको निश्चित रूप से इसे प्रोग्राम करना था और इसका मतलब है कि कोई भी इसे प्रोग्राम कर सकता है इसलिए हम सिर्फ लाइब्रेरी कोड को ही क्यों प्रोग्राम कर सकते हैं जो हमें खुद की आवश्यकता है? यह भी है कि यह संभवतः शुद्ध c ++ गलत में नहीं है
ओवरलोडेडकोर

@ बच्चे 8 मुझे समझ में नहीं आता
-

1
@ जोहान्सचैब-लिट वह शायद यह कहने की कोशिश कर रहा है कि लाइब्रेरी के कार्यान्वयनकर्ता ने उस पोर्टेबल विधि को शुद्ध c / c ++ में कैसे बनाया जब आप कहते हैं कि यह संभव नहीं है।
अभिनव गौनियाल

@AbhinavGauniyal आह, मैं देख रहा हूँ। हालाँकि मैंने यह नहीं कहा है कि पुस्तकालय के कार्यान्वयनकर्ता ने पोर्टेबल तरीके (यानी यथोचित पोर्टेबल कार्यक्रमों द्वारा उपयोग किए जाने वाले) नहीं बनाए हैं। मैंने आरोप लगाया है कि उन्होंने पोर्टेबल C ++ का उपयोग नहीं किया है। जैसा कि स्पष्ट रूप से वे नहीं करते हैं, मुझे समझ नहीं आता कि उनकी टिप्पणी यह ​​क्यों कहती है कि मेरे उत्तर का यह हिस्सा गलत है।
जोहान्स स्काउब -

81

लिनक्स पर (और अन्य यूनिक्स की तरह सिस्टम) यह निम्नलिखित तरीके से किया जा सकता है:

#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);
}

मूल रूप से आपको कैनोनिकल मोड को बंद करना होगा (और गूंज को दबाने के लिए इको मोड)।


मैंने इस कोड को लागू करने का प्रयास किया, लेकिन मुझे कॉल करने में त्रुटि हुई read। मैंने दोनों हेडर शामिल किए हैं।
माइकल डोरस्ट

6
संभवतः क्योंकि यह कोड गलत है, जैसा कि पढ़ा () unistd.h में परिभाषित एक POSIX सिस्टम कॉल है। stdio.h इसे संयोग से शामिल कर सकता है, लेकिन आपको वास्तव में इस कोड के लिए stdio.h की आवश्यकता नहीं है; इसे unistd.h से बदलें और यह अच्छा होना चाहिए।
फाल्कन मोमेंट

1
मुझे नहीं पता कि मैं रास्पबेरी पाई में आरओएस टर्मिनल पर कीबोर्ड इनपुट प्राप्त करने के लिए मैं यहां कैसे समाप्त हुआ। कोड का यह स्निपेट मेरे लिए काम करता है।
एकनाय

2
@FalconMomot मेरी NetBeans IDE 8.1 (काली लिनक्स में) यह कहती है: error: ‘perror’ was not declared in this scopeजब संकलित किया जाता है, लेकिन stdio.hसाथ में शामिल होने पर ठीक काम करता है unistd.h
अभिषेक कश्यप

3
क्या इसे ब्लॉक करने का कोई आसान तरीका है?
जो स्ट्रैट जूल

18

मैंने उसी समस्या को हल करने की तलाश में एक और मंच पर पाया। मैंने इसे जो कुछ भी पाया है उससे थोड़ा संशोधित किया है। यह बहुत अच्छा काम करता है। मैं OS X चला रहा हूं, इसलिए यदि आप Microsoft चला रहे हैं, तो आपको कच्चे और पके हुए मोड में जाने के लिए सही सिस्टम () कमांड खोजने की आवश्यकता होगी।

#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; 
}

13
हालांकि यह काम करता है, जो इसके लायक है, उसके लिए सिस्टम से अलग होना शायद ही कभी मेरी राय में ऐसा करने का "सबसे अच्छा" तरीका हो। स्ट्टी प्रोग्राम C में लिखा गया है, इसलिए आप <termios.h> या <sgtty.h> को शामिल कर सकते हैं और एक ही कोड को कॉल कर सकते हैं जो बिना किसी बाहरी प्रोग्राम / कांटे / व्हाट्नॉट के आधार पर स्टटी का उपयोग करता है।
क्रिस लुट्ज़

1
मुझे अवधारणा सामान के यादृच्छिक प्रमाण और चारों ओर गड़बड़ करने के लिए इसकी आवश्यकता थी। मुझे जिस चीज की जरूरत थी। धन्यवाद। यह ध्यान दिया जाना चाहिए: मैं निश्चित रूप से कार्यक्रम के अंत में पकाए गए स्टेंट को डालूंगा अन्यथा आपका शेल स्ट्टी रॉ मोड में रहेगा, जो कि प्रोग्राम बंद होने के बाद मूल रूप से मेरे शेल लोल को तोड़ दिया था।
बेंजामिन

मुझे लगता है कि आप भूल गए#include <stdlib.h>
NerdOfCode

14

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

या

लिनक्स c ++ का conio.h http://sourceforge.net/projects/linux-conioh का कार्यान्वयन


9

यदि आप खिड़कियों पर हैं, तो आप 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

ईमानदार होने के लिए यह मेरे पास मौजूद कुछ पुराने कोड से है, इसलिए आपको इसके साथ थोड़ा फील करना होगा।

हालांकि यह अच्छी बात है कि यह किसी चीज के लिए संकेत दिए बिना इनपुट पढ़ता है, इसलिए पात्रों को प्रदर्शित नहीं किया जाता है।


9
#include <conio.h>

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

यह kbhit()जांचने के लिए उपयोग करता है कि क्या कीबोर्ड दबाया जा रहा है और getch()उस चरित्र को प्राप्त करने के लिए उपयोग करता है जिसे दबाया जा रहा है।


5
conio.h ? "conio.h एक सी हैडर फ़ाइल है जिसका उपयोग पुराने MS-DOS कंपाइलरों में टेक्स्ट यूजर इंटरफेस बनाने के लिए किया जाता है।" कुछ पुराना लगता है।
- एसई बुराई है


5

C और C ++, I / O का एक बहुत ही सारगर्भित दृश्य लेते हैं, और जो आप चाहते हैं, उसे करने का कोई मानक तरीका नहीं है। मानक इनपुट स्ट्रीम से वर्ण प्राप्त करने के मानक तरीके हैं, यदि कोई भी प्राप्त करना है, और किसी भी अन्य भाषा द्वारा परिभाषित नहीं है। इसलिए किसी भी उत्तर को प्लेटफ़ॉर्म-विशिष्ट होना चाहिए, शायद न केवल ऑपरेटिंग सिस्टम पर बल्कि सॉफ्टवेयर फ्रेमवर्क पर भी निर्भर करता है।

यहां कुछ उचित अनुमान हैं, लेकिन आपके लक्ष्य पर्यावरण के बारे में जाने बिना आपके प्रश्न का उत्तर देने का कोई तरीका नहीं है।


5

मैं kbhit () का उपयोग यह देखने के लिए करता हूं कि क्या कोई char मौजूद है और फिर डेटा पढ़ने के लिए 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;
}

4

पोर्टेबल के लिए निकटतम बात यह है ncursesकि टर्मिनल को "क्रैक मोड" में डालने के लिए लाइब्रेरी का उपयोग करना है । एपीआई विशाल है; रूटीन आप सबसे अधिक चाहते हैं

  • initscr तथा endwin
  • cbreak तथा nocbreak
  • getch

सौभाग्य!


3

निम्नलिखित विशेषज्ञ सी प्रोग्रामिंग से निकाला गया एक समाधान है : डीप सीक्रेट , जिसे SVr4 पर काम करना चाहिए। इसमें स्ट्टी और 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");
}

3

मैं हमेशा एक लूप चाहता था कि रिटर्न इनपुट को दबाए बिना मेरे इनपुट को पढ़ें। यह मेरे लिए काम किया।

#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
      }

    }

1
एक बार जब आप रॉ मोड में होंगे तो इस प्रक्रिया को मारना मुश्किल है। इसलिए प्रक्रिया को मारने के लिए एक बिंदु रखें जैसा कि मैंने "~" दबाने पर किया था। ................ अन्य बुद्धिमान आप KILL का उपयोग करके अन्य टर्मिनल से प्रक्रिया को मार सकते हैं।
सेतु गुप्ता

3

ncurses ऐसा करने का एक अच्छा तरीका प्रदान करता है! इसके अलावा यह मेरी पहली पोस्ट है (जो मुझे याद है), इसलिए किसी भी टिप्पणी का स्वागत है। मैं उपयोगी लोगों की सराहना करूंगा, लेकिन सभी का स्वागत है!

संकलन करने के लिए: g ++ -std = c ++ 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;
}

2

खिड़कियों पर मेरे लिए काम करता है:

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

1

आप इसे एसडीएल (सिंपल डायरेक्टमीडिया लाइब्रेरी) का उपयोग करते हुए कर सकते हैं, हालांकि मुझे संदेह है कि आप इसके व्यवहार को पसंद नहीं करेंगे। जब मैंने इसकी कोशिश की, तो मुझे SDL एक नई वीडियो विंडो बनानी पड़ी (भले ही मुझे अपने कार्यक्रम के लिए इसकी आवश्यकता नहीं थी) और इस विंडो को लगभग सभी कीबोर्ड और माउस इनपुट "हड़पने" के लिए था (जो मेरे उपयोग के लिए ठीक था लेकिन परेशान होना या अन्य स्थितियों में अस्थिर होना)। मुझे संदेह है कि यह ओवरकिल है और इसके लायक नहीं है जब तक कि पूर्ण पोर्टेबिलिटी जरूरी नहीं है - अन्यथा अन्य सुझाए गए समाधानों में से एक का प्रयास करें।

वैसे, यह आपको मुख्य प्रेस और घटनाओं को अलग से जारी करेगा, यदि आप उस में हैं।


1

यहाँ एक संस्करण है जो सिस्टम पर नहीं लिखा गया है (macOS 10.14 पर लिखित और परीक्षित)

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

char* getStr( char* buffer , int maxRead ) {
  int  numRead  = 0;
  char ch;

  struct termios old = {0};
  struct termios new = {0};
  if( tcgetattr( 0 , &old ) < 0 )        perror( "tcgetattr() old settings" );
  if( tcgetattr( 0 , &new ) < 0 )        perror( "tcgetaart() new settings" );
  cfmakeraw( &new );
  if( tcsetattr( 0 , TCSADRAIN , &new ) < 0 ) perror( "tcssetattr makeraw new" );

  for( int i = 0 ; i < maxRead ; i++)  {
    ch = getchar();
    switch( ch )  {
      case EOF: 
      case '\n':
      case '\r':
        goto exit_getStr;
        break;

      default:
        printf( "%1c" , ch );
        buffer[ numRead++ ] = ch;
        if( numRead >= maxRead )  {
          goto exit_getStr;
        }
        break;
    }
  }

exit_getStr:
  if( tcsetattr( 0 , TCSADRAIN , &old) < 0)   perror ("tcsetattr reset to old" );
  printf( "\n" );   
  return buffer;
}


int main( void ) 
{
  const int maxChars = 20;
  char      stringBuffer[ maxChars+1 ];
  memset(   stringBuffer , 0 , maxChars+1 ); // initialize to 0

  printf( "enter a string: ");
  getStr( stringBuffer , maxChars );
  printf( "you entered: [%s]\n" , stringBuffer );
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.