Hallo, vermutlich wird es mir nicht gelingen in der initialen Frage das Kernproblem zu beschreiben, ich brobiere es dennoch mal ;) Es geht mir darum, dass ich gerne für eine konsolenbasierte Anwwendung beliebige Tastatureingaben in einem dediziertem Threak abfangen und verwerten möchte. (Also nicht blockierend und auch ohne Bestätigung mit Return) Ich habe schon einige Code-Schnipsel gefunden, wie dieses "nicht-blockiernd" funktionieren soll (Win & Unix) und auch einige Teile, wie man kbhit() und getch() unter Linux nachbildet. Jedoch blockieren diese ALLE in meiner Konsole, die in der IDE eingebunden ist. (Veränderbar und nutzt per Default auch nur den System-Std) Daher möchte ich unabhängig von der Programmierung hier erst mal klären, welche Voraussetzungen man überhaupt braucht, damit ALLE Eingaben gefangen werden können und ob dies neben dem "Fokus" auf dem ausführenden Terminal noch andere Kriterien erfüllen muss. Grüße David
Möchtest du nun eine nicht blockierende Eingabe im Terminal, oder soll dein Programm Eingaben aufzeichnen auch wenn dein Progamm nicht den Fokus besitzt?
Adam P. schrieb: > Möchtest du nun eine nicht blockierende Eingabe im Terminal, Ja, den Fokus bekomme ich schon noch geregelt. Walter T. schrieb: > Oder willst Du einfach ein interaktives Programm in der Konsole? Was versteht man hier unter "interaktiv"? Ich glaube ein gutes Beispiel wäre "Snake" oder "Packman". (auch wenn es hier nicht konkret um ein Spiel geht) Ermöglicht werden soll z.B. $ "Start" $ Buffer ausgabe:[ 0, 0, 1, 4, 6]... (Über den Hauptthread) $ Buffer ausgabe:[ 0, 0, 1, 4, 6]... (Über den Hauptthread) $ Buffer ausgabe:[ 0, 0, 1, 4, 6]... (Über den Hauptthread) $ 'a' $ "Sie befinden sich nun in Menue a" $ Buffer ausgabe:[ 0, 0, 1, 4, 6]... (Über den Hauptthread) $ Buffer ausgabe:[ 0, 0, 1, 4, 6]... (Über den Hauptthread) $ 'Pfeiltaste-UP' $ Buffer ausgabe:[ 0, 0, 1, 4, 6]... (Über den Hauptthread) $ "Der globale Wert int x wurde incrementiert und ist nun x = 10" $ Buffer ausgabe:[ 0, 0, 1, 4, 6]... (Über den Hauptthread) $ 'Pfeiltaste-DOWN' $ Buffer ausgabe:[ 0, 0, 1, 4, 6]... (Über den Hauptthread) $ Buffer ausgabe:[ 0, 0, 1, 4, 6]... (Über den Hauptthread) $ "Der globale Wert int x wurde decrementiert und ist nun x = 9" $ Buffer ausgabe:[ 0, 0, 1, 4, 6]... (Über den Hauptthread) $ Buffer ausgabe:[ 0, 2, 1, 4, 6]... (Über den Hauptthread) $ Buffer ausgabe:[ 0, 4, 1, 4, 6]... (Über den Hauptthread) $ Buffer ausgabe:[ 0, 0, 1, 4, 6]... (Über den Hauptthread) $... $... $... Grüße David
D a v i d K. schrieb: > Es geht mir darum, dass ich gerne für eine konsolenbasierte Anwwendung > beliebige Tastatureingaben in einem dediziertem Threak abfangen und > verwerten möchte. (Also nicht blockierend und auch ohne Bestätigung mit > Return) Du möchtest also einen Keylogger programmieren. Sags doch gleich.
D a v i d K. schrieb: > Adam P. schrieb: >> Möchtest du nun eine nicht blockierende Eingabe im Terminal, > Ja, den Fokus bekomme ich schon noch geregelt Bezweifel grad das du die Problematik verstehst... wenn dein Programm den Fokus nicht besitzt, dann musst du "keyboard hooks" verwenden, sprich du musst dich an windows registrieren und ihm mitteilen, dass alle aktionen ebenfalls an dich geleitet werden sollen. Was dein parallele Verarbeitung betrifft: Das sollte doch mit Threads ganz gut funktionieren. - Erstell ein Thread der sich um das Einlesen kümmert und die Daten global zur Verfügung stellt. - In der main() machst eine while() die immer etwas ausgibt oder verarbeitet und dort reagierst du bzw. prüfst ob etwas eingegeben wurde.
Natürlich muss man bei Thread noch den gleichzeitigen Zugriff auf Variablen beachten etc. Aber vllt. ist ja das Beispiel das was du vor hast: Findest zu Windows-Threads hier z.B. ein Tutorial: https://www.spieleprogrammierer.de/27-tutorials/6661-einstieg-in-multithreading-unter-windows/
1 | #include <stdio.h> |
2 | #include <conio.h> |
3 | #include <windows.h> |
4 | #include <time.h> |
5 | |
6 | bool input; |
7 | char ch; |
8 | |
9 | /*******************************************************************************
|
10 | * Nicht schön, dient nur der langsameren Ausgabe in der main()
|
11 | */
|
12 | void delay(int number_of_seconds) |
13 | {
|
14 | // Converting time into milli_seconds
|
15 | int milli_seconds = 1000 * number_of_seconds; |
16 | |
17 | // Stroing start time
|
18 | clock_t start_time = clock(); |
19 | |
20 | // looping till required time is not acheived
|
21 | while (clock() < start_time + milli_seconds); |
22 | }
|
23 | |
24 | /*******************************************************************************
|
25 | * Thread für Eingabe
|
26 | */
|
27 | DWORD WINAPI ThreadProc(LPVOID lpParam) |
28 | {
|
29 | while (1) |
30 | {
|
31 | ch = _getch(); |
32 | |
33 | input = true; |
34 | }
|
35 | |
36 | return 0; |
37 | }
|
38 | |
39 | /*******************************************************************************
|
40 | * Haupt-Thread
|
41 | */
|
42 | int main() |
43 | {
|
44 | DWORD threadId, mainThreadId; |
45 | HANDLE threadHandle; |
46 | bool ende = false; |
47 | |
48 | mainThreadId = GetCurrentThreadId(); |
49 | printf("Ich bin das Hauptprogrammm: ID %d\n", mainThreadId); |
50 | |
51 | threadHandle = CreateThread(NULL, 0, ThreadProc, NULL, 0, &threadId); |
52 | printf("Thread mit der ID=%d erstellt\n", threadId); |
53 | |
54 | printf("\n\n"); |
55 | |
56 | while (!ende) |
57 | {
|
58 | printf("Hauptprogramm\n"); |
59 | |
60 | if (input) |
61 | {
|
62 | input = false; |
63 | printf("\nEingabe: %c\n", ch); |
64 | |
65 | if (ch == 'E') |
66 | {
|
67 | ende = true; |
68 | }
|
69 | }
|
70 | |
71 | /* Damit die Ausgabe nicht 1000x die Sekunde passiert */
|
72 | delay(1); |
73 | }
|
74 | |
75 | CloseHandle(threadHandle); |
76 | |
77 | return 0; |
78 | }
|
Adam P. schrieb: > Natürlich muss man bei Thread noch den gleichzeitigen Zugriff auf > Variablen beachten etc. > > Aber vllt. ist ja das Beispiel das was du vor hast: > { > while (1) > { > ch = _getch(); > > input = true; > } Egal wie ich diesen teil hier umsetze (also hab bestimmt schon 8 verschiedene Implementierungen "reinkopiert" Funktioniert immer nur die Erkennung NACH dem betätigen der Enter-Taste. (Ich weiß kopiere, statt verstehen ist hässlich, aber es geht ja nun mal um grundsätzliche Dinge in meiner IDE) Adam P. schrieb: > D a v i d K. schrieb: >> Adam P. schrieb: >>> Möchtest du nun eine nicht blockierende Eingabe im Terminal, >> Ja, den Fokus bekomme ich schon noch geregelt > > Bezweifel grad das du die Problematik verstehst... Bezweifel ich ja selbst ;)
nur mal so zum Einlesen...: https://www.geeksforgeeks.org/difference-getchar-getch-getc-getche/ Die Frage ist ja eigentlich eine andere: passt die gewählte Programmstruktur auf dass, was implementiert werden soll. Wenn man sich nicht unbedingt mit Threads rumärgern möchte, dann steht halt die Tastatureingabe in einem Endlos-Loop in main und alles, was man während des Wartens auf eine Tastatureingabe nebenbei machen will, packt man z.B. in einen Timerinterrupt.
50c schrieb: > nur mal so zum Einlesen...: > https://www.geeksforgeeks.org/difference-getchar-getch-getc-getche/ Danke, hier noch zwei Bilder, die demonstrieren sollen, dass ich nicht zu blöde bin Code auszuführen ;P
Habe ich das richtig verstanden: Du willst ein einfaches, interaktives Konsolenprogramm schreiben, das sich vom normalen input() dadurch unterscheidet, dass zeichenweise reagiert wird, und nicht erst eine Eingabe komplett abgeschlossen sein muss? Wenn ich das richtig verstanden habe, ist evtl. SDL2 Dein Freund. Da kann man Keyboard-Events relativ einfach abfragen.
:
Bearbeitet durch User
Es gibt verschiedene Terminalemulatoren. Es kann gut sein, dass der in deiner IDE das Feature, was du brauchst, nicht unterstützt, andere hingegen schon. So einen full-featured Terminalemulator schreiben ist ein relativ komplexes Projekt, und es ist gut möglich dass $IDE da nur die offensichtlichsten 3 Dinge eingebaut hat.
:
Bearbeitet durch User
Ich hab den Verdacht, dass das "Terminal" in der IDE sein eigenes Süppchen kocht (ein eigener Zeileneditor (in grün)) und erst bei Return die Zeile an die Anwendung weitergibt. Das Teil kann wahrscheinlich gar kein Single-Char-Input. Starte in dem Teil mal nen Texteditor ... PS: deine getch-Routine sollte auch VMIN und VTIME setzen.
Ja, der interne Terminalemulator von CLion scheint da ein paar Einschränkungen zu haben. So kannst mit CLion einen externen Terminalemulator nutzen (hier gnome-terminal, sollte aber genauso mit einem anderen funktionieren): https://stackoverflow.com/questions/36675012/how-to-execute-a-clion-program-in-gnome-terminal Ich verstehe sowieso nicht, warum Leute in der heutigen Zeit immer noch IDEs benutzen ;-)
D a v i d K. schrieb: > Egal wie ich diesen teil hier umsetze (also hab bestimmt schon 8 > verschiedene Implementierungen "reinkopiert" Funktioniert immer nur die > Erkennung NACH dem betätigen der Enter-Taste. So wie ich es gepostet habe ist es das ganze Programm....nichts heraus kopieren, versuch es so zu kompilieren und zu verstehen. getch() erwartet kein ENTER, deshalb muss der Fehler in deinem Code liegen. Was nutzt du für eine IDE? Ich hab es mit dem Visual Studio 2015 oder 2017 unter Win 10 getestet und brauchte kein ENTER.
:
Bearbeitet durch User
D a v i d K. schrieb: > Egal wie ich diesen teil hier umsetze (also hab bestimmt schon 8 > verschiedene Implementierungen "reinkopiert" Funktioniert immer nur die > Erkennung NACH dem betätigen der Enter-Taste. Das liegt daran, dass Terminals (genau genommen TTYs) unter Unix die eingegebene Zeile normalerweise erst nach Drücken der Enter-Taste absenden, d.h. davor hat Dein Prozeß gar keine Chance die Eingaben zu sehen, egal welche Input-Funktion er verwendet. Um das zu ändern, muss das TTY in den raw-Modus versetzt werden. Auf die Schnelle habe ich dieses Tutorial gefunden, das die Thematik recht ausführlich behandelt: https://viewsourcecode.org/snaptoken/kilo/02.enteringRawMode.html Falls Du es einfacher haben möchtest und Dich der Hintergrund nicht interessiert, kannst Du z.B. die ncurses-Bibliothek verwenden. Da gibt es die Funktionen raw() und noraw(), um zwischen den beiden Modi umzuschalten und auch die getch()-Funktion nach der Du im Eingangspost gefragt hattest.
:
Bearbeitet durch User
Ja gut wenn er grad unter Linux arbeitet, wird mein Code nicht laufen... Mein Bsp. setzt auf den Win-Threads auf, sonst muss er pthread nutzen!
R. M. schrieb: > Das liegt daran, dass Terminals (genau genommen TTYs) unter Unix die > eingegebene Zeile normalerweise erst nach Drücken der Enter-Taste > absenden Da die Dinger ursprünglich an seriellen Schnittstellen angeschlossen waren: Wie sollen die das machen? Wie soll damit z.B. ein Bildschirmeditor funktionieren? vi beispielsweise reagiert auf einzelne Tastendrücke ... Und ein vt100 sendet jeden Tastendruck einzeln, das hat weder einen Zeilenpuffer noch sendet es erst nach der Entertaste. Das Problem hier dürfte sich buffered IO nennen, und liegt nicht im Terminal, sondern ist ein Teil des Betriebssystems. Der lässt sich auch abschalten (sonst würde wie gesagt kein Bildschirmeditor funktionieren). Das sollte mit setvbuf mit dem Modus _IONBF möglich sein.
Adam P. schrieb: > So wie ich es gepostet habe ist es das ganze Programm....nichts heraus > kopieren, versuch es so zu kompilieren und zu verstehen. > > getch() erwartet kein ENTER, deshalb muss der Fehler in deinem Code > liegen. > > > Was nutzt du für eine IDE? > Ich hab es mit dem Visual Studio 2015 oder 2017 unter Win 10 getestet > und brauchte kein ENTER. Ich stelle das hier immer wieder fest (nur du musst jetzt leider mal dran glauben), dass scheinbar lesen nicht so die Stärke einiger "Hilfesteller" ist? Man erwartet vom Fragesteller, dass er im Kontext bleibt aber die Antworten driften immer weiter ab oder wiederholen sogar Annahmen, die man bereits verworfen hat. Wie ich Threads erzeuge weiß ich, ist aber doch ein ganz anderes Thema! (notfalls geht immer ein while(1){} Welche IDE und welches Betriebsystem ich verwende sollte ebenfalls seit dem posten des Screenshots klar sein! An viele andere ein herzlichen Dank! Ich denke ich habe das Problem in etwa verstanden und versuche meine IDE nun umzukonfigurieren. Falls dies nicht klappt, könnt ihr mir noch in einem Satz die Anforderung auf den Punkt bringen, die IDEA (Clion & IntelliJ) in einem Ticket hören wollen würde, wenn ich das als BUG/FEATURE melde? (Bei IntelliJ z.B. merke ich dass die Jungs ihre IDE auch selber verwenden, denn die Usability ist extrem hoch und auch die Updates incl. EAP sehr häufig. Daher besteht eine Chance dass die es wirklich mit einbauen) Grüße David
:
Bearbeitet durch User
Die andere Frage ist halt, ist das wirklich so zentral dass das im Terminalemulator der IDE läuft? Warum nicht einen externen nehmen? Im Endeffekt muss es ja eh dort laufen, und wenn die sich unterschiedlich verhalten ...
:
Bearbeitet durch User
Sven B. schrieb: > Die andere Frage ist halt, ist das wirklich so zentral dass das im > Terminalemulator der IDE läuft? Warum nicht einen externen nehmen? > > Im Endeffekt muss es ja eh dort laufen, und wenn die sich > unterschiedlich verhalten ... ein deutliches JEIN, ich "simuliere" hier Dinge, die eigentlich auf einem AVR ablaufen. Also möchte ich Eingaben wie Knopfdrücken über die Tastatur abhandeln. Beitrag "CMake zwei Compilate bauen lassen" Grüße David
D a v i d K. schrieb: > Hallo, > > vermutlich wird es mir nicht gelingen in der initialen Frage das > Kernproblem zu beschreiben, ich brobiere es dennoch mal ;) > > Es geht mir darum, dass ich gerne für eine konsolenbasierte Anwwendung > beliebige Tastatureingaben in einem dediziertem Threak abfangen und > verwerten möchte. (Also nicht blockierend und auch ohne Bestätigung mit > Return) Nicht blockierend ist schlecht. Das bedeutet, dass dein Thread einen Prozessorkern zu 100% damit auslastet, auf Eingaben zu warten. Ich verstehe auch den Sinn nicht. Wenn du schon einen eigenen Thread dafür hast, warum darf der nicht blockieren? > Ich habe schon einige Code-Schnipsel gefunden, wie dieses > "nicht-blockiernd" funktionieren soll (Win & Unix) und auch einige > Teile, wie man kbhit() und getch() unter Linux nachbildet. Unter Linux kann man man das getch() von ncurses verwenden. https://linux.die.net/man/3/getch
Rolf M. schrieb: > Nicht blockierend ist schlecht. Das bedeutet, dass dein Thread einen > Prozessorkern zu 100% damit auslastet, auf Eingaben zu warten. Das ist jetzt nicht per se richtig. Es könnte auch ein Callback aufgerufen werden wenn ein Ereignis stattfindet.
Und was macht der Thread dann in der Zeit, in der kein Callback aufgerufen wird? Entweder er blockiert, oder er lastet den Kern komplett aus. Anders geht's nicht.
D a v i d K. schrieb: > ein deutliches JEIN, ich "simuliere" hier Dinge, die eigentlich auf > einem AVR ablaufen. Dann würde ich wirklich mal einen Blick auf SDL werfen. Spätestens, wenn Du auch ein Display emulieren willst.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.