كيف يمكنني التقاط ضغطة مفتاح فورًا في نظام التشغيل Linux؟[ينسخ]

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

  •  13-12-2019
  •  | 
  •  

سؤال

التكرار المحتمل:
ما هو المعادل لـ getch() & getche() في Linux؟

أنا مبتدئ في برمجة لينكس.:-)

أنا فقط أتساءل عما إذا كان برنامجي (باستخدام ج اللغة) يمكنه التقاط كل ضغطة مفتاح على الفور في Linux، ثم تحديد ما إذا كنت تريد تكرارها أم لا وكيفية عرضها، تمامًا مثل telnet.

على سبيل المثال، إذا قام المستخدم بضرب "A"، أريد أن يعرض البرنامج "B"، وإذا كتب "B"، فإن "C" مطلوب، وما إلى ذلك.

يبدو مضحكا وغير مجدية.أنا فقط أشعر بالفضول حيال ذلك.

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

المحلول

في الأساس، يعتمد الأمر بشكل كبير على كيفية تعريفك على الفور.

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

في الكود الزائف.

 echo(off);
 while (capturing && charIsAvailable()) {
   c = readOneChar();
   if (c == '\n') {
     capturing = false;
   }
   printf("%c", c++);
 }
 echo(on);

هناك عدد من الأنظمة التي تتواصل لالتقاط الضغط على المفتاح.

  1. لوحة المفاتيح
  2. (ربما) حافلة USB
  3. معالج مقاطعة وحدة المعالجة المركزية
  4. نظام التشغيل
  5. عملية خادم النافذة X
  6. "النافذة" X التي تحتوي على التركيز.

تتم الخطوة الأخيرة باستخدام برنامج يقوم بتشغيل حلقة مستمرة تلتقط الأحداث من خادم X وتعالجها.إذا كنت ترغب في توسيع هذا البرنامج بطرق معينة (الحصول على طول الوقت الذي تم فيه الضغط على المفتاح)، فأنت بحاجة إلى إخبار البرامج الأخرى أنك تريد أحداث لوحة المفاتيح "الأولية"، مما يعني أنك لن تتلقى حقًا "مطبوخًا" بالكامل " الشخصيات.ونتيجة لذلك، سيتعين عليك تتبع المفاتيح التي يتم رفعها لأعلى ولأسفل، ومدة ذلك، والتعامل مع جميع سلوكيات المفاتيح التعريفية الفردية في برنامجك (هذا ليس "a" ولكنه "A" لأن يحول هو أسفل، الخ).

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

الآن بعد أن أصبحت لديك فكرة عن بيئتك، دعنا نعيد النظر في الكود الفعلي المطلوب لمنع إخراج الأحرف.

// define a terminal configuration data structure
struct termios term;

// copy the stdin terminal configuration into term
tcgetattr( fileno(stdin), &term );

// turn off Canonical processing in term
term.c_lflag &= ~ICANON;

// turn off screen echo in term
term.c_lflag &= ~ECHO;

// set the terminal configuration for stdin according to term, now
tcsetattr( fileno(stdin), TCSANOW, &term);


(fetch characters here, use printf to show whatever you like)

// turn on Canonical processing in term
term.c_lflag |= ICANON;

// turn on screen echo in term
term.c_lflag |= ECHO;

// set the terminal configuration for stdin according to term, now
tcsetattr( fileno(stdin), TCSANOW, &term);

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

نصائح أخرى

إدوين باك قدمت إجابة عظيمة.هنا بديل آخر يستخدم ncurses مما يجعل مثل هذه الأشياء أكثر سهولة قليلاً ويتم دعمها في كل توزيعات Linux ومتغيرات Unix الأخرى تقريبًا.

#include <ncurses.h>

int main(int argc, char *argv[])
{
    int ch,c;
    initscr();
    cbreak();
    noecho();

    while( ch != 'q')
    {
        switch( c = getch() )
        {
            case 'a':
                ch = 'b';
            break;

            case 'b':
                ch = 'c';
            break;

            case 'c':
                ch = 'd';
            break;

            default:
                ch = c;                 
            break;
        }
        printw("%c",ch);
    }
    endwin();
    return(0);
}

قم بالتجميع باستخدام كود gcc code.c -o -lncurses

وهنا بعض الروابط الداعمة:

ncurses noecho وغيرها - صفحة الرجل
كيفية برمجة ncurses

يمكن العثور على هذا الرمز على الإنترنت وهو موجود kermi3 من سي بورد

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

int mygetch(void)
{
    struct termios oldt,newt;
    int ch;
    tcgetattr( STDIN_FILENO, &oldt );
    newt = oldt;
    newt.c_lflag &= ~( ICANON | ECHO );
    tcsetattr( STDIN_FILENO, TCSANOW, &newt );
    ch = getchar();
    tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
    return ch;
}

يحرر: بالطبع إذا كنت ترغب في الحصول على الحرف نفسه وليس تغيير قيمة ascii إلى char بدلاً من int

قد يكون الأمر مبالغًا فيه ولكن يمكنك استخدام مكتبات الألعاب مثل com.sdl لتحقيق ذلك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top