MOUSE_WHEELED
-
@zeropage sagte in MOUSE_WHEELED:
Ja, ich will da nicht gleich so kompliziert einsteigen.
Du sollst a minimales kompilierbares beispiel liefern. Wie lange bist Du jetzt hier im Forum??
-
Oh sorry! Auch wegen der Verspätung.
Ich dachte, man kann sich in den Code so rein denken. Aber ich schau mal, was ich da machen kann. Immerhin müsste ich ja eine ganz neue Funktion schreiben, weil so wie die Methode oben steht, geht ja nur mit zugehöriger Klasse. Aber ich schau mal.
-
Bist Du sauer auf mich, weil wir vor 150 Jahren mal aneinander geraten sind?
-
@zeropage sagte in MOUSE_WHEELED:
Oh sorry! Auch wegen der Verspätung.
Ich dachte, man kann sich in den Code so rein denken. Aber ich schau mal, was ich da machen kann. Immerhin müsste ich ja eine ganz neue Funktion schreiben, weil so wie die Methode oben steht, geht ja nur mit zugehöriger Klasse. Aber ich schau mal.
Es geht auch darum, das einfach in live mal sehen zu können und vlt selbst mal zwei, drei Sachen probieren zu können ohne selbst all zu viel Arbeit da rein zu investieren.
Verschachtelte
switch
case
if
for
Konstrukte machen es auch nicht wirklich "einfach" sich irgendwo rein zu denken.Ich möchte aber, das das Mausrad auf 0 gesetzt wird, wenn es nicht mehr bedient wird.
Was heißt denn nicht mehr bedient? 0.1 Sekunden nicht weiter gedreht, oder 0.2 s nicht weiter gedreht? Mein Mausrad hier hat so Zwischenstufen, wenn ich langsam drehe bleibe ich da immer "kurz" stehen. Ist das dann "nicht mehr bedient"? Vielleicht gibt es, für das, was du vorhast, ein besseres Kriterium?
-
In meiner Variable
mouse.wheelData
wird tatsächlich nur hoch und runtergezählt, wenn man das Mausrad auch dreht. Wenn es still steht wird auch nicht gezählt, währendmouse.wheelState
immer und ständig != 0 ist. (bzw in diesem Fall erst bei Mausklick auf 0 gestzte wird)Dieses switch_case Ding wird von der API so vorgegeben. zB hier:
Reading Input Buffer Events
Und da steht ausdrücklichMOUSE_WHEELED 0x0004 The vertical mouse wheel was moved.
If the high word of the dwButtonState member contains a positive value, the wheel was rotated forward, away from the user.
Otherwise, the wheel was rotated backward, toward the user.Ich musste dieses Beispiel etwas umschreiben, damit es bei mir (VS22, c++20) kompiliert:
#include <windows.h> #include <iostream> #include <string> HANDLE hStdin; DWORD fdwSaveOldMode; void ErrorExit(const std::string& lpszMessage) { std::cout << stderr << lpszMessage; // Restore input mode on exit. SetConsoleMode(hStdin, fdwSaveOldMode); ExitProcess(0); } void KeyEventProc(KEY_EVENT_RECORD ker) { std::cout << "Key event: "; if (ker.bKeyDown) std::cout << "key pressed\n"; else std::cout << "key released\n"; } void MouseEventProc(MOUSE_EVENT_RECORD mer) { std::cout << "Mouse event: "; switch (mer.dwEventFlags) { case 0: if (mer.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED) { std::cout << "left button press \n"; } else if (mer.dwButtonState == RIGHTMOST_BUTTON_PRESSED) { std::cout << "right button press \n"; } else { std::cout << "button press\n"; } break; case DOUBLE_CLICK: std::cout << "double click\n"; break; case MOUSE_MOVED: std::cout << "mouse moved\n"; break; case MOUSE_WHEELED: if (HIWORD(mer.dwButtonState) > 0) { std::cout << "mouse wheel up\n"; } else { std::cout << "mouse wheel down\n"; } break; default: std::cout << "unknown\n"; break; } } void ResizeEventProc(WINDOW_BUFFER_SIZE_RECORD wbsr) { std::cout << "Resize event\n"; std::cout << "Console screen buffer is " << wbsr.dwSize.X << " columns by " << wbsr.dwSize.Y << " rows\n"; } int main() { DWORD cNumRead, fdwMode; // Get the standard input handle. hStdin = GetStdHandle(STD_INPUT_HANDLE); if (hStdin == INVALID_HANDLE_VALUE) ErrorExit("GetStdHandle"); // Save the current input mode, to be restored on exit. if (!GetConsoleMode(hStdin, &fdwSaveOldMode)) ErrorExit("GetConsoleMode"); // Enable the window and mouse input events. fdwMode = (ENABLE_EXTENDED_FLAGS | ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT); if (!SetConsoleMode(hStdin, fdwMode)) ErrorExit("SetConsoleMode"); INPUT_RECORD irInBuf[128]; // Loop to read and handle the next 100 input events. int counter = 0; while (counter++ <= 100) { // Wait for the events. if (!ReadConsoleInput( hStdin, // input buffer handle irInBuf, // buffer to read into 128, // size of read buffer &cNumRead)) // number of records read ErrorExit("ReadConsoleInput"); // Dispatch the events to the appropriate handler. for (DWORD i = 0; i < cNumRead; i++) { switch (irInBuf[i].EventType) { case KEY_EVENT: // keyboard input KeyEventProc(irInBuf[i].Event.KeyEvent); break; case MOUSE_EVENT: // mouse input MouseEventProc(irInBuf[i].Event.MouseEvent); break; case WINDOW_BUFFER_SIZE_EVENT: // scrn buf. resizing ResizeEventProc(irInBuf[i].Event.WindowBufferSizeEvent); break; case FOCUS_EVENT: // disregard focus events break; case MENU_EVENT: // disregard menu events break; default: ErrorExit("Unknown event type"); } } } // Restore input mode on exit. SetConsoleMode(hStdin, fdwSaveOldMode); return 0; }
Aber dort funktioniert es nicht richtig, ich bekomme nur 'wheel_up' als Rückmeldung, egal wie ich drehe.
-
Erstmal zu
wheel_up
:Das
HIWORD
Makro verschiebt das high word nach rechts setzt die obersten 16 Bit auf 0. Wenn das als Integer interpretiert wird, ist das immer positiv.case MOUSE_WHEELED: { short h = HIWORD(mer.dwButtonState); if (h > 0) { std::cout << "mouse wheel up\n"; } else { std::cout << "mouse wheel down\n"; } break; }
-
@zeropage
Das Drehen des Mouse-Wheel wird nicht als anhaltender Zustand zum PC gemeldet, sondern in "Klicks". (Bei vielen Mäusen sind diese "Klicks" auch deutlich spürbar - aber nicht bei allen.)Also wenn du das Rad z.B. zu dir hin drehst, dann bekommst du PC seitig einfach hin und wieder einen Event mit negativem
HIWORD(dwButtonState)
gemeldet - also pro "Klick" kommt ein solcher Event. Dazwischen kommt nix. Und wenn du aufhörst zu drehen, dann kommt auch nix. Im Prinzip das selbe wie wenn du mehrfach eine Maustaste drückst. Da meldet die Maus ja auch nur jeden Klick einzeln, und es gibt keinen Event wenn du dann irgendwann mal mit Klicken aufhörst. D.h. wenn du mitbekommen willst dass der Benutzer aufgehört hat das Rad zu drehen, dann kannst du nur selbst willkürlich ein Timeout festlegen, nach dessen Ablauf du einfach annimmst dass der Benutzer eben aufgehört hat das Mausrad zu drehen. Einfach experimentell ermitteln was sich deiner Meinung nach passend anfühlt.Umsetzen kannst du das z.B. mittels
SetTimer
. Du kannst bei jedem Mausrad-Event einen Timer starten. Wenn du dabei eine von dir vordefinierte Timer-ID verwendest, dann ersetztSetTimer
automatisch den alten Timer mit der selben ID und startet das Timeout neu. D.h. wenn der Timer Event kommt, dann weisst du dass X Millisekunden seit dem letzten Mausrad-Event vergangen sind. Dann kannst du deinen Mausrad-Zustand auf "steht" setzen und den Timer löschen.
-
Er. Ich sehe gerade du arbeitest mit
ReadConsoleInput
. D.h. du hast vermutlich kein Fenster. In dem Fall wirdSetTimer
wohl nicht funktionieren. D.h. die Timeout-Sache wirst du irgendwie anders lösen müssen. Falls du schon einen "polling loop" mit ausreichender Frequenz hast kannst du z.B. einfach mitzählen.
-
Doch,
SetTimer
funktioniert auch ohne Fenster. In diesem Fall muss mannullptr
für das Fensterhandle und einen Funktionszeiger als letzten Parameter übergeben, dann wird keineWM_TIMER
Nachricht verschickt, sondern direkt die Funktion aufgerufen. Ob man dann die Windows Message Pump perGetMessage
manuell behandeln muss weiss ich allerdings nicht.
-
@DocShoe
Ah, OK.Ob man dann die Windows Message Pump per GetMessage manuell behandeln muss weiss ich allerdings nicht.
Ja, muss man:
When you specify a TimerProc callback function, the default window procedure calls the callback function when it processes WM_TIMER. Therefore, you need to dispatch messages in the calling thread, even when you use TimerProc instead of processing WM_TIMER.
Würde mich wundern wenn das ohne Fenster anders wäre. In dem Fall wird man die
WM_TIMER
vermutlich einfach als "thread message" bekommen. Also alsWM_TIMER
die nicht an ein Fenster gerichtet ist. Und:WM_TIMER
Messages werden auch nicht magisch, asynchron von irgendwem in die Queue gesteckt, sondern ad-hoc vonGetMessage
/PeekMessage
generiert wenn es abgelaufene Timer gibt und nix wichtigeres ansteht.
-
Wobei ich nicht weiss wie man die Kombination aus
ReadConsoleInput
und Message-Loop am besten macht. Es gibt zwar für beide "peek" Funktionen, aber ich kenne keine Funktion mittels der man warten könnte bis es bei einem der beiden etwas zu holen gibt. D.h. man wird wohl trotzdem pollen müssen.Vermutlich könnte man es auch mehr oder weniger elegant mit Threads lösen. Fühlt sich aber irgendwie fast nach Overkill an.
-
Vielen Dank für den Input Muss ich erstmal sortieren...