এন্টার টিপে যাওয়ার অপেক্ষা না করে স্ট্যান্ডার্ড ইনপুট থেকে অক্ষরগুলি ক্যাপচার করুন


174

আমি কখনই এটি করতে পারি তা কখনই মনে করতে পারি না কারণ এটি আমার জন্য খুব কম সময়ে আসে। তবে সি বা সি ++ এ, কোনও নতুন লাইন অপেক্ষা না করে স্ট্যান্ডার্ড ইনপুট থেকে কোনও অক্ষর পড়ার সর্বোত্তম উপায় (এন্টার টিপুন)।

এছাড়াও আদর্শভাবে এটি স্ক্রিনে ইনপুট চরিত্রটিকে প্রতিধ্বনিত করে না। আমি কেবল কনসোল স্ক্রিনটি কার্যকর করে কীস্ট্রোকগুলি ক্যাপচার করতে চাই।


1
@ অ্যাডাম - আপনি কি স্পষ্ট করে বলতে পারেন: কোনও চরিত্র উপলব্ধ না হলে অবিলম্বে ফিরে আসবে এমন কোনও ফাংশন আপনি চান, বা কোনও একটি যা সর্বদা একক কীস্ট্রোকের জন্য অপেক্ষা করবে?
রডি

2
@ রডি - আমি এমন একটি ফাংশন চাই যা সর্বদা একক কীস্ট্রোকের জন্য অপেক্ষা করবে।
অ্যাডাম

উত্তর:


99

খাঁটি সি ++ তে পোর্টেবল পদ্ধতিতে এটি সম্ভব নয়, কারণ এটি ব্যবহৃত টার্মিনালের উপর খুব বেশি নির্ভর করে যা stdinতারা সংযুক্ত থাকতে পারে (তারা সাধারণত লাইন বাফার হয়)। তবে আপনি এটির জন্য একটি লাইব্রেরি ব্যবহার করতে পারেন:

  1. উইন্ডোজ সংকলকগুলির সাথে কনও উপলব্ধ। _getch()এন্টার কীটির জন্য অপেক্ষা না করে আপনাকে একটি অক্ষর দেওয়ার জন্য ফাংশনটি ব্যবহার করুন । আমি ঘন ঘন উইন্ডোজ বিকাশকারী নই, তবে আমি আমার সহপাঠীদের সবেমাত্র এটি অন্তর্ভুক্ত <conio.h>এবং ব্যবহার করতে দেখেছি । conio.hউইকিপিডিয়া দেখুন । এটি তালিকাবদ্ধ করে getch(), যা ভিজ্যুয়াল সি ++ এ অবমানিত ঘোষণা করা হয়েছে।

  2. লিনাক্সের জন্য অভিশাপ উপলব্ধ। সামঞ্জস্যপূর্ণ অভিশাপ বাস্তবায়ন উইন্ডোজের জন্যও উপলব্ধ। এটি একটি getch()ফাংশন আছে। ( man getchএর ম্যানপেজটি দেখার চেষ্টা করুন )। উইকিপিডিয়ায় অভিশাপ দেখুন ।

যদি আপনি ক্রস প্ল্যাটফর্মের সামঞ্জস্যের লক্ষ করেন তবে আমি আপনাকে অভিশাপগুলি ব্যবহার করার পরামর্শ দিচ্ছি would এটি বলেছিল, আমি নিশ্চিত যে লাইন বাফারিং বন্ধ করতে আপনি ব্যবহার করতে পারেন এমন ফাংশন রয়েছে (আমি বিশ্বাস করি এটিকে "কাঁচা মোড" বলা হয়, "রান্না করা মোড" এর বিপরীতে - দেখুন man stty)। অভিশাপগুলি আপনার পক্ষে বহনযোগ্য পদ্ধতিতে এটি পরিচালনা করবে, যদি আমার ভুল না হয়।


7
নোট করুন যে আজকাল, ncursesএর প্রস্তাবিত বৈকল্পিক curses
ফান্ড মনিকার লসুইট

4
আপনার যদি লাইব্রেরির দরকার হয় তবে তারা এটি কীভাবে তৈরি করবেন? লাইব্রেরিটি তৈরি করার জন্য আপনাকে অবশ্যই এটি প্রোগ্রাম করতে হয়েছিল এবং এর অর্থ যে কেউ এটি প্রোগ্রাম করতে পারে তাই আমরা কেবল লাইব্রেরি কোডটি আমাদের নিজেরাই প্রোগ্রাম করতে পারি না কেন? যে করতে হবে যে না সম্ভবত portably বিশুদ্ধ C ++ এ ভুল
OverloadedCore

@ কিড 8 আমি বুঝতে পারি না
জোহানেস স্কাউব -

1
@ জোহানেস শ্যাব-লিটব তিনি সম্ভবত বলতে চেষ্টা করছেন যে গ্রন্থাগার প্রয়োগকারী কীভাবে খাঁটি সি / সি ++ তে এই পোর্টেবল পদ্ধতি তৈরি করেছিলেন যখন আপনি বলেন যে এটি সম্ভব নয়।
অভিনব গৌনিয়াল

@ অভিনবগৌনিয়াল আহ, আমি দেখছি তবে আমি বলিনি যে লাইব্রেরি প্রয়োগকারীরা পোর্টেবল পদ্ধতি তৈরি করেনি (অর্থাত্ যুক্তিসঙ্গত পোর্টেবল প্রোগ্রামগুলি দ্বারা ব্যবহৃত হওয়া)। আমি বুঝিয়েছি যে তারা পোর্টেবল সি ++ ব্যবহার করেনি। স্পষ্টত তারা নেই, আমি কেন বুঝতে পারি না যে তার মন্তব্য কেন বলেছে যে আমার উত্তরের এই অংশটি ভুল।
জোহানেস স্কাউব - লিটব

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
সম্ভবত এই কোডটি ভুল হওয়ার কারণে, পড়ুন () হ'ল একটি পসিক্স সিস্টেম কল যা আনজিস্টড.কে সংজ্ঞায়িত করা হয়। stdio.h এটি কাকতালীয়ভাবে অন্তর্ভুক্ত করতে পারে তবে এই কোডটির জন্য আপনার আসলে স্টডিওএইচ দরকার নেই; এটি unistd.h এর সাথে প্রতিস্থাপন করুন এবং এটি ভাল হওয়া উচিত।
ফ্যালকন মোমোট

1
আমি জানি না যে আমি এখানে কীভাবে শেষ হয়েছি যখন আমি রাস্পবেরি পাইয়ের আরওএস টার্মিনালে কীবোর্ড ইনপুট পাওয়ার সন্ধান করছিলাম। কোডের এই স্নিপেটটি আমার পক্ষে কাজ করে।
আক্নে

2
@ ফ্যালকনমোট আমার নেটবিন্স আইডিই 8.1 তে (কালি লিনাক্সে) এটি বলেছে: error: ‘perror’ was not declared in this scopeযখন সংকলন করা হয়, তবে stdio.hপাশাপাশি যুক্ত থাকে তখন ঠিকঠাক কাজ করে unistd.h
অভিষেক কশ্যপ

3
এটি অবরুদ্ধ না করার জন্য কি আরও সহজ উপায় আছে?
জো স্ট্রাউট

18

একই সমস্যা সমাধানের জন্য আমি অন্য ফোরামে এটি পেয়েছি। আমি যা পেয়েছি তা থেকে এটি কিছুটা পরিবর্তন করেছি। এটি দুর্দান্ত কাজ করে। আমি ওএস এক্স চালাচ্ছি, সুতরাং আপনি যদি মাইক্রোসফ্ট চালাচ্ছেন তবে কাঁচা এবং রান্না করা মোডগুলিতে স্যুইচ করার জন্য আপনাকে সঠিক সিস্টেম () কমান্ডটি সন্ধান করতে হবে।

#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
যদিও এটি কাজ করে, এটির জন্য মূল্যবান হলেও, সিস্টেমে শেলিং করা আমার মতে এটি করার জন্য খুব সম্ভবত "সেরা" উপায়। স্টাটি প্রোগ্রামটি সি-তে লেখা থাকে, যাতে আপনি <termios.h> বা <sgত্তি.h> অন্তর্ভুক্ত করতে পারেন এবং বহিরাগত প্রোগ্রাম / কাঁটাচামচ / হোয়াট নোটের উপর নির্ভর করে স্টিটি ব্যবহার করে এমন একটি কোড কল করতে পারেন can
ক্রিস লুৎজ 21

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.

লাইবকনিও http://sourceforge.net/projects/libconio

অথবা

লিনাক্স সি ++ কনিওএইচ এর বাস্তবায়ন http: // http://sourceforge.net/projects/linux-conioh


9

আপনি যদি উইন্ডোতে থাকেন তবে কোনও ইনপুট রয়েছে কিনা তা সনাক্ত করতে আপনি পিক কনসোলইনপুট ব্যবহার করতে পারেন,

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 একটি সি শিরোনাম ফাইল যা পুরানো এমএস-ডস সংকলকগুলিতে পাঠ্য ব্যবহারকারী ইন্টারফেস তৈরি করতে ব্যবহৃত হয়" " কিছুটা পুরানো মনে হচ্ছে।
কে - এসই


5

সি এবং সি ++ I / O সম্পর্কে খুব বিমূর্ত দৃষ্টিভঙ্গি নেয় এবং আপনি যা চান তা করার কোনও মানক উপায় নেই। স্ট্যান্ডার্ড ইনপুট স্ট্রিম থেকে অক্ষরগুলি পাওয়ার জন্য স্ট্যান্ডার্ড উপায় রয়েছে, যদি কোনও পেতে থাকে তবে অন্য কোনও কিছুই ভাষা দ্বারা সংজ্ঞায়িত হয় না। যে কোনও উত্তর অবশ্যই প্ল্যাটফর্ম-নির্দিষ্ট হতে হবে, সম্ভবত কেবল অপারেটিং সিস্টেমের উপর নির্ভর করে নয় তবে সফ্টওয়্যার কাঠামোর উপরও নির্ভর করে।

এখানে কিছু যুক্তিসঙ্গত অনুমান রয়েছে, তবে আপনার টার্গেট পরিবেশ কী তা জেনে আপনার প্রশ্নের উত্তর দেওয়ার উপায় নেই।


5

চরটি উপস্থিত রয়েছে কিনা তা দেখার জন্য আমি কেবিট () ব্যবহার করি এবং তারপরে ডেটা পড়ার জন্য গেটচার ()। উইন্ডোজগুলিতে, আপনি "conio.h" ব্যবহার করতে পারেন। লিনাক্সে আপনাকে নিজের কেবিট () প্রয়োগ করতে হবে।

নীচে কোড দেখুন:

// 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

নিম্নলিখিতটি বিশেষজ্ঞ সি প্রোগ্রামিং থেকে প্রাপ্ত একটি সমাধান : ডিপ সিক্রেটস , যা এসভিআর 4 এ কাজ করার কথা রয়েছে। এটি ব্যবহার করে 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");
}

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

আপনি এটি এসডিএল (সিম্পল ডাইরেক্টমিডিয়া লাইব্রেরি) ব্যবহার করে বহনযোগ্যভাবে করতে পারেন, যদিও আমার সন্দেহ হয় আপনি এটির আচরণ পছন্দ করতে পারেন না। যখন আমি এটি চেষ্টা করেছিলাম তখন আমার এসডিএলকে একটি নতুন ভিডিও উইন্ডো তৈরি করতে হবে (যদিও আমার প্রোগ্রামের জন্য আমার এটির প্রয়োজন ছিল না) এবং এই উইন্ডোটি প্রায় সমস্ত কীবোর্ড এবং মাউস ইনপুটটি "দখল" করে রাখতে হবে (যা আমার ব্যবহারের জন্য ঠিক ছিল তবে পারে বিরক্তিকর বা অন্য পরিস্থিতিতে অকার্যকর হতে পারে)। আমার সন্দেহ হয় যে এটি অত্যধিক দক্ষতা এবং এটির জন্য উপযুক্ত নয় যতক্ষণ না সম্পূর্ণ বহনযোগ্যতা আবশ্যক - অন্যথায় প্রস্তাবিত সমাধানগুলির মধ্যে একটি ব্যবহার করে দেখুন।

যাইহোক, এটি আপনাকে কী টিপবে এবং ইভেন্টগুলি আলাদাভাবে প্রকাশ করবে, যদি আপনি এর মধ্যে থাকেন।


1

এখানে এমন একটি সংস্করণ রয়েছে যা সিস্টেমে শেল আউট না করে (ম্যাকোস 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 );
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.