2 Fragen zu GetAsyncKeyState und rint

  • C++

Es gibt 14 Antworten in diesem Thema. Der letzte Beitrag () ist von Elanda.

    2 Fragen zu GetAsyncKeyState und rint

    Hi all,

    ich hätte zwei Fragen und wäre erfreut, wenn ihr sie mir beantworten könntet.
    Vorab: Ich baue gerade das Grundgerüst zu einem Schrittmotorprojekt. Ich möchte als Erstes, dass die Logik steht. Daher will ich am Anfang alles richtig machen.

    Die erste hierzu. Mit der ESC-Taste soll das Programm beendet werden. Ich muss leider ein sleep einbauen, weil er sonst nicht kapiert, dass ich gerade ESC drücke -.- Habt ihr einen Gegenvorschlag? Ich muss dazu sagen, dass ich, was Keys in C++ angeht, nicht wirklich gut bin.

    C-Quellcode

    1. while (aktiv)
    2. {
    3. Motor1.Richtung();
    4. Motor1.Eingabe();
    5. Motor1.verfahren(Motor1.Schritte);
    6. Motor1.Bewertung(Motor1.Bewert);
    7. std::this_thread::sleep_for(std::chrono::milliseconds(3000));
    8. for (int k = 0; k < 1; k++)
    9. {
    10. Key[k] = (0x8000 & GetAsyncKeyState((unsigned char)("\x1B"[k]))) != 0;
    11. }
    12. if (Key[0] == true)
    13. {
    14. aktiv = false;
    15. }
    16. }


    Zweite Frage

    C-Quellcode

    1. Schritte = (int)rint(dFahrstrecke / d_mm_pro_Umdrehungen * d_Schritte_pro_Umdrehung);

    Schritte = $\frac{Strecke [mm]}{mm\_pro\_U [\frac{mm}{U}]}$ * $\frac{Schritte}{U}$

    Ich will runden und dann zu int casten. Gibt es eine Funktion, die direkt einen Integer zurückgibt (inkl runden)?
    Auf rint bin ich hier gestoßen.

    Liebe Grüße
    Bartosz

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „EaranMaleasi“ ()

    Keine C-Style casts in C++!
    Verwende einfach static_cast in deinem Fall.

    Des Weiteren, die STL verfügt über massen an Utilities und so auch über round, ceil und floor. Versuche so gut wie möglich immer die STL Versionen über denen der C Ausführungen zu verwenden.
    Wichtig, da diese für C++ Kompilierer spezifisch implementiert werden und daher auch größere Optimisationschancen bieten.

    Auch interessant finde ich die 1x-Iterationsschleife,ist das wirklich notwendig? (an diesem Punkt möchte ich mich für diese Frage entschuldigen falls der Zweck aufgrund von Skalierbarkeit besteht)

    So nun zu deinem anderen Problem.
    Vorweg noch, ich habe kein Windows daher kenne ich mich mit der Windows API so gar nicht aus, dennoch gibt es genügend Microsoft docs auf die ich meine Hypothesen stützen kann, daher versuche ich nur so viel zu sagen wie ich selbst verstanden habe.

    Das erste was mir auffällt ist

    C-Quellcode

    1. GetAsyncKeyState((unsigned char)("\x1B"[k]))

    könnte aufgerufen werdem bevor oder nachdem du eine Taste gedrückt hast, daher auch nicht garantiert das es in dem Moment in dem du es aufrufst auch den gewünschten Wert zurückgibt (so verstehe ich zumindest die MSDN Beschreibung). Ich empfehle dir, versuche den Thread mit einem signal-handler zu Verwalten.

    Sobald ein key gedrückt wird, wird ein boolescher Wert umgestellt. (pass auf das es ein volatile-bool ist, sonst könnte MSVC den while check wegoptimieren)

    Edit: Habe auf Google gerade ein paar Dinge über keyboard hooks gelesen, das könnte das richtige für dich sein.
    ----------------------------------------------------------------------------------------------------------------------

    Hier könnte meine Signatur stehen, aber die ist mir abfußen gekommen.

    ----------------------------------------------------------------------------------------------------------------------
    @Bartosz Warum muss das C++ sein?
    Fals die elementare Steuerung in C++ vorliegt, mach Dir daraus eine native DLL und arbeite mit .NET.
    Falls das SerialPort oder USB ist, mach alles in .NET.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Verwende einfach static_cast in deinem Fall. ... Des Weiteren, die STL verfügt über massen an Utilities und so auch über round
    Verbessert :)

    C-Quellcode

    1. Schritte = static_cast<int>(round(dFahrstrecke / d_mm_pro_Umdrehungen * d_Schritte_pro_Umdrehung));



    Auch interessant finde ich die 1x-Iterationsschleife,ist das wirklich notwendig?
    Ja, vorher (in einem anderen Projekt) sah das so aus, bis ich die anderen 5 rausgeschmissen hab:

    C-Quellcode

    1. bool Key[6] = { false, false, false, false, false, false };
    2. for (int k = 0; k < 6; k++)
    3. { //↑ ↓ ← → RShift ESC
    4. Key[k] = (0x8000 & GetAsyncKeyState((unsigned char)("\x26\x28\x25\x27\xA1\x1B"[k]))) != 0;
    5. }

    Die For-Schleife kann natürlich raus. Mit deinem Vorschlag und mit @Takafusas Virtual-Key-Code vereinfacht sich mein Code zu

    C-Quellcode

    1. bool Key = false;
    2. volatile bool aktiv = true;
    3. while (aktiv)
    4. {
    5. Motor1.Richtung();
    6. Motor1.Eingabe();
    7. Motor1.verfahren(Motor1.Schritte);
    8. Motor1.Bewertung(Motor1.Bewert);
    9. std::this_thread::sleep_for(std::chrono::milliseconds(3000));
    10. Key = (0x8000 & GetAsyncKeyState((VK_ESCAPE))) != 0;
    11. if (Key == true)
    12. {
    13. aktiv = false;
    14. }
    15. }

    Ich brauche aber immer noch das sleep →"Ich empfehle dir, versuche den Thread mit einem signal-handler zu Verwalten." Ist wahrscheinlich die Lösung, aber sorry Ich weiß nicht, was du meinst.

    Ist das eine Konsolenanwendung?
    Ja, zumindest für dieses Grundgerüst. Wird ein langes Projekt.

    Warum muss das C++ sein?
    Hi @RodFromGermany, Weil ich das bereits in .NET kann. Ich wollte mich an C++ versuchen.



    Melde mich heute Nachmittag wieder.
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.
    @Bartosz 3 Sekunden warten und dann Esc abfragen ist suboptimal, weil Du losgelassen haben kannst, bevor die 3 Sekunden vorbei sind.
    Mach Dir ne 30er Schleife über 100 ms, da solltest Du die Taste sicher erkennen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Bartosz schrieb:

    Ja, zumindest für dieses Grundgerüst. Wird ein langes Projekt.


    Dann mach gleich mit Windows.

    Im Anhang ist ein Source, kannst du gut als Grundlage nehmen. So mach ich das mit dem UserInput, ist Framebasiert aufgebaut.
    Füge alle Dateien zu einem leeren C++ Projekt hinzu, in den Projekt-Eigenschaften unter Linker/System das SubSystem auf Windows (/SUBSYSTEM:WINDOWS) stellen.
    Dateien
    • SimpleWindow.zip

      (9,06 kB, 80 mal heruntergeladen, zuletzt: )

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Takafusa“ ()

    @RodFromGermany Danke für den Tipp, aber das scheint nicht viel zu bringen.

    ich habe jetzt

    C-Quellcode

    1. volatile bool aktiv = true;
    2. while (aktiv)
    3. {
    4. Motor1.Richtung();
    5. Motor1.Eingabe();
    6. Motor1.verfahren(Motor1.Schritte);
    7. Motor1.Bewertung(Motor1.Bewert);
    8. aktiv = Verlangsamung();
    9. }

    mit der Funktion

    C-Quellcode

    1. bool Verlangsamung()
    2. {
    3. bool Key_is_pressed = false;
    4. volatile bool aktiv = true;
    5. for (int i = 0; i < 20; i++)
    6. {
    7. std::this_thread::sleep_for(std::chrono::milliseconds(95));
    8. }
    9. Key_is_pressed = (0x8000 & GetAsyncKeyState(VK_ESCAPE)) != 0;
    10. if (Key_is_pressed)
    11. {
    12. aktiv = false;
    13. }
    14. return aktiv;
    15. }


    Wenn ich ESC zu kurz drücke, nimmt er die Taste nicht an...vb-paradise.de/index.php/User/28071-Takafusa/


    Es sind übrigens 20*95ms, da das laut Haltepunkten knapp 2,5 sec sind

    @Takafusa Danke, probiere ich gleich mal aus
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.
    @Bartosz Du musst GetAsyncKeyState() in der for-Schleife abfragen:

    C-Quellcode

    1. bool Verlangsamung()
    2. {
    3. bool Key_is_pressed = false;
    4. volatile bool aktiv = true;
    5. for (int i = 0; i < 20; i++)
    6. {
    7. std::this_thread::sleep_for(std::chrono::milliseconds(95));
    8. Key_is_pressed = (0x8000 & GetAsyncKeyState(VK_ESCAPE)) != 0;
    9. if (Key_is_pressed)
    10. {
    11. aktiv = false;
    12. }
    13. }
    14. return aktiv;
    15. }

    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „RodFromGermany“ ()

    Ach verdammt stimmt -.-
    Danke

    =========================
    gerade getestet, läuft :thumbsup:
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Bartosz“ ()

    Ich finde polling hier dennoch überflüssig.
    So wie @Takafusa bereits angemerkt hat, WndProc, solltest du es mal mit Keyboard hooks versuchen. (wenn dies die richtige Bezeichnung dafür war)

    Abgesehen davon, jedes mal wenn Thread sleep verwendet wird, bringt das Jesus zum weinen.
    Es gibt fast immer eine Alternative um sleep zu vermeiden, hauptsächlich um Kontextwechsel und Prioritätsumkehrung vorzubeugen. (auch wenn du damit jetzt keine Probleme haben wirst, in zukünftigen Projekten kann das sehr schnell zum Kryptonit für effiziente Anwendungen werden)

    Neben all dem:

    C-Quellcode

    1. volatile bool aktiv = true;

    Das volatile macht hier absolut keinen Sinn.
    An beiden Stellen nicht!

    Der Kompilierer sollte in der Lage sein die Nebeneffekte zu identifizieren also wird er es auch nicht wegoptimieren.
    Er weiß das Verlangsamen es möglicherweise irgendwann verändern könnte, daher wird aktiv auch nicht mit true ersetzt werden.

    Und mal ganz abgesehen von dem while-check, ist aktiv auch noch anderweitig in Verwendung oder nur für diese eine Stelle?
    Denn wenn nicht, könntest du auch einfach ein break zum terminieren verwenden. (was natürlich nur dann funktioniert wenn du weiter pollst, wenn du es mit hooks machst ist dies hinfällig)

    Edit: fast vergessen

    C-Quellcode

    1. static_cast<int>(round(dFahrstrecke

    round ist C und nicht C++
    Du hast std:: vergessen, aber ist ja in deinem Fall eh egal, nur mein OCD mal wieder. :D
    ----------------------------------------------------------------------------------------------------------------------

    Hier könnte meine Signatur stehen, aber die ist mir abfußen gekommen.

    ----------------------------------------------------------------------------------------------------------------------

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Elanda“ ()

    Das volatile macht hier absolut keinen Sinn.
    Ok, ist raus! Was meintest du heute Morgen dann hiermit?

    Sobald ein key gedrückt wird, wird ein boolescher Wert umgestellt. (pass auf das es ein volatile-bool ist, sonst könnte MSVC den while check wegoptimieren)



    Und mal ganz abgesehen von dem while-check, ist aktiv auch noch anderweitig in Verwendung oder nur für diese eine Stelle?
    Denn wenn nicht, könntest du auch einfach ein break zum terminieren verwenden.
    Nur hier für diesen Zweck. Break ist drin ^^
    Du hast std:: vergessen
    Stimmt, ist drin.
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.

    Bartosz schrieb:

    Ok, ist raus! Was meintest du heute Morgen dann hiermit?

    Vergiss was ich da meinte, ich dachte das wenn du die Variable extern umstellen müsstest setzt du es volatile damit der Compiler weiß: Aha, jemand den ich nicht kenne, sehe und verstehe könnte diese Variable verändern, also lieber Finger weg.

    Da wäre dann aber sowieso noch das Konkurrenz Problem in Kraft getreten, also wäre atomic<bool> für diesen Einsatz sowieso die einzige Plausible Möglichkeit gewesen.
    Da du aber sowieso auf das pollen und nicht signaling setzt ist das eh egal.

    Du modifizierst das Terminierstatement Thread-Lokal, mach dir darüber also keine Sorgen. ^^
    ----------------------------------------------------------------------------------------------------------------------

    Hier könnte meine Signatur stehen, aber die ist mir abfußen gekommen.

    ----------------------------------------------------------------------------------------------------------------------

    Elanda schrieb:

    Ich finde polling hier dennoch überflüssig.
    Probiere es aus.
    GetAsyncKeyState() gibt den aktuell vorgefundenen Zustand zurück.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich sagte überflüssig nicht unmöglich.
    Außerdem hat Linux kein GetAsyncKeyState xD

    Abgesehen davon ist es am Ende des Tages sowieso Wurst, da @Bartosz's Anwendungen keine Anspruchsvollen Aufgaben auszuführen hat.
    Allerdings ist es in meinem Kopf schon so eingebrannt das ich auch einfache Anwendungen skalierbar mache, nur damit ich mich vorbereiten kann auf Eventualitäten in ferner Zukunft.

    Deshalb wäre Event-basiert hier meiner Meinung nach ein Vorteil, nicht nur weil unnötiges, ständiges Abfragen verhindert wird sondern auch eben weil man so ein neues System lernen kann.
    Und ja es stimmt, im Kern ist auch ein Eventbasiertes System durch polling aufgebaut, dennoch wird dies alles intern und möglichst effizient gehändelt. (obwohl bei Windows bin ich mir da manchmal nicht so sicher, no offense)

    Das wichtigste ist das man sich nicht auf Thread sleep verlassen muss :p
    ----------------------------------------------------------------------------------------------------------------------

    Hier könnte meine Signatur stehen, aber die ist mir abfußen gekommen.

    ----------------------------------------------------------------------------------------------------------------------