Mouse event singleton Question.
-
Hi i'm trying to do with singleton one program to show mouse events. But i want sometimes stop this hook so i need use this sentence:
UnhookWindowsHookEx(mouseHook);
But i'm little lost and i dont know how to add to my code;
Code.h file:
#ifndef MOUSELOGGER_H #define MOUSELOGGER_H #include <QObject> #include <windows.h> class MouseLogger : public QObject { Q_OBJECT Q_DISABLE_COPY(MouseLogger) public: static MouseLogger &instance(); explicit MouseLogger(QObject *parent = nullptr); virtual ~MouseLogger(){} // Static method that will act as a callback-function static LRESULT CALLBACK mouseProc(int Code, WPARAM wParam, LPARAM lParam); signals: // The signal, which will report the occurrence of an event void mouseEvent(); public slots: private: // hook handler HHOOK mouseHook; }; #endif // MOUSELOGGER_H
Code.cpp:
#include "mouselogger.h" #include <QDebug> MouseLogger &MouseLogger::instance() { static MouseLogger _instance; return _instance; } MouseLogger::MouseLogger(QObject *parent) : QObject(parent) { HINSTANCE hInstance = GetModuleHandle(NULL); // Set hook mouseHook = SetWindowsHookEx(WH_MOUSE_LL, mouseProc, hInstance, 0); // Check hook is correctly if (mouseHook == NULL) { qWarning() << "Mouse Hook failed"; } } LRESULT CALLBACK MouseLogger::mouseProc(int Code, WPARAM wParam, LPARAM lParam) { Q_UNUSED(Code) // Having an event hook, we nned to cast argument lParam // to the structure of the mouse is the hook. MOUSEHOOKSTRUCT * pMouseStruct = (MOUSEHOOKSTRUCT *)lParam; // Next, we check to see what kind of event occurred, // if the structure is not a pointer to nullptr if(pMouseStruct != nullptr) { switch (wParam) { case WM_MOUSEMOVE: qDebug() << "WM_MOUSEMOVE"; break; case WM_LBUTTONDOWN: qDebug() << "WM_LBUTTONDOWN"; break; case WM_LBUTTONUP: qDebug() << "WM_LBUTTONUP"; break; case WM_RBUTTONDOWN: qDebug() << "WM_RBUTTONDOWN"; break; case WM_RBUTTONUP: qDebug() << "WM_RBUTTONUP"; break; case WM_MBUTTONDOWN: qDebug() << "WM_MBUTTONDOWN"; break; case WM_MBUTTONUP: qDebug() << "WM_MBUTTONUP"; break; case WM_MOUSEWHEEL: qDebug() << "WM_MOUSEWHEEL"; break; default: break; } emit instance().mouseEvent(); } // After that you need to return back to the chain hook event handlers return CallNextHookEx(NULL, Code, wParam, lParam); }
Main function where i want to deactivate this hook:
#include <QCoreApplication> #include <QDebug> #include "mouselogger.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QObject::connect(&MouseLogger::instance(), &MouseLogger::mouseEvent, [](){ qDebug() << "Mouse Event"; }); return a.exec(); }
-
hi
you should/could make a function of our class
like stoplogging()and there call
UnhookWindowsHookEx(mouseHook);so in main , you can say
MouseLogger::instance().stoplogging();
-
hi
you should/could make a function of our class
like stoplogging()and there call
UnhookWindowsHookEx(mouseHook);so in main , you can say
MouseLogger::instance().stoplogging();
-
hi
you should/could make a function of our class
like stoplogging()and there call
UnhookWindowsHookEx(mouseHook);so in main , you can say
MouseLogger::instance().stoplogging();
@mrjj Ok worked but i have some questions why sometimes it's useful use static method? What is the utility? If for example i want to include one signal and slot i need to do the same?
It's useful to use qobject when and why.
thx overall i use in databases and events games. -
@Jeronimo
No need to make it static as you call via an instance.
You use static function to be able to call them WITHOUT an instance.Signals and slots have notning to do with static use.
Example:
Say we have class Printer and it has a name() function.
If NOT static we must do
Printer myp; // instance
myp.name();if we make it static, its a not needed
you can say
Printer::name(); // to call it with no instance.Qt Example is
QFileDialog::getOpenFileName(this,
tr("Open Image"), "/home/jana", tr("Image Files (*.png *.jpg *.bmp)"));here we use a static getOpenFileName without an instance of QFileDialog
So static is good for utility functions but should NOT be used a lot.
-
@mrjj Ok worked but i have some questions why sometimes it's useful use static method? What is the utility? If for example i want to include one signal and slot i need to do the same?
It's useful to use qobject when and why.
thx overall i use in databases and events games.@Jeronimo
Oh, the reason for
static LRESULT CALLBACK mouseProc(int Code, WPARAM wParam, LPARAM lParam);
is static here is that Windows cannot get an instance of an Object to call so it has to be plain function or
a static function for it to call it back.So the reason for static here , is that the callback CANNOT live as normal function in a class and be called from outside
from code that cannot know class types. (from your app) -
@Jeronimo
Oh, the reason for
static LRESULT CALLBACK mouseProc(int Code, WPARAM wParam, LPARAM lParam);
is static here is that Windows cannot get an instance of an Object to call so it has to be plain function or
a static function for it to call it back.So the reason for static here , is that the callback CANNOT live as normal function in a class and be called from outside
from code that cannot know class types. (from your app) -
@mrjj Ok thx one little question if i connect the instance with qobject::connect is necessary or not?¿ because it's very using too sorry to late .
@Jeronimo said in Mouse event singleton Question.:
i connect the instance with qobject::connect is necessary or not?
Its not necessary for the call back ?
but if you want MouseLogger to emit signal , then yes you must use the Instance to connect.
Connect need a real object and cannot use static member functions. -
@Jeronimo said in Mouse event singleton Question.:
i connect the instance with qobject::connect is necessary or not?
Its not necessary for the call back ?
but if you want MouseLogger to emit signal , then yes you must use the Instance to connect.
Connect need a real object and cannot use static member functions.@mrjj But if for example i want to use signals and slots:
connect(MouseLogger::Instance(),SIGNAL(testSignal()), this,SLOT(testSlot()));I can include this code to my program to use different signal and slots? but i' dont know how.
When you say this:
Signals and slots have notning to do with static use.So i dont need to use static functions for this.
-
@mrjj But if for example i want to use signals and slots:
connect(MouseLogger::Instance(),SIGNAL(testSignal()), this,SLOT(testSlot()));I can include this code to my program to use different signal and slots? but i' dont know how.
When you say this:
Signals and slots have notning to do with static use.So i dont need to use static functions for this.
@Jeronimo
Yes that would be the way, but one note
connect(MouseLogger::Instance(),SIGNAL(testSignal()), this,SLOT(testSlot()));When you are in main, there is no this pointer. That have to be inside a class, say mainwindow.
So you would have to use the new syntax and a lambda as you already did with
QObject::connect(&MouseLogger::instance(), &MouseLogger::mouseEvent,
{
qDebug() << "Mouse Event";
});The
[]()
makes it the lamba thing and then you dont need another instance of a class for the THIS part.
Remember what we say is
connect( some instance, that signal, to this other/same instance, to this slot (function)But the c+11 feature called lambda makes it possible to create function RIGHT there so to speak
and can be used in main - to add slots that can respond (in main) to your Logger.A common design is called Producers / Consumers and it would not be a bad design
if anyone using the Logger would be another class ( and not main) as
it's very flexible as you can then just swap the Consumer (main) with some other
consumer and do other stuff. Or have mutiple consumers to same Producer (logger).
This is vastly simplified version of the design. so take it as "overall" concept.
https://dzone.com/articles/producer-consumer-patternFinal note is:
Always/please do
qDebug << "con1:" << connect(xxx);
when using the SLOT() , SIGNAL() version and check it says "true" in Application output.
Its very helpful and takes the guessing away :) -
@Jeronimo
Yes that would be the way, but one note
connect(MouseLogger::Instance(),SIGNAL(testSignal()), this,SLOT(testSlot()));When you are in main, there is no this pointer. That have to be inside a class, say mainwindow.
So you would have to use the new syntax and a lambda as you already did with
QObject::connect(&MouseLogger::instance(), &MouseLogger::mouseEvent,
{
qDebug() << "Mouse Event";
});The
[]()
makes it the lamba thing and then you dont need another instance of a class for the THIS part.
Remember what we say is
connect( some instance, that signal, to this other/same instance, to this slot (function)But the c+11 feature called lambda makes it possible to create function RIGHT there so to speak
and can be used in main - to add slots that can respond (in main) to your Logger.A common design is called Producers / Consumers and it would not be a bad design
if anyone using the Logger would be another class ( and not main) as
it's very flexible as you can then just swap the Consumer (main) with some other
consumer and do other stuff. Or have mutiple consumers to same Producer (logger).
This is vastly simplified version of the design. so take it as "overall" concept.
https://dzone.com/articles/producer-consumer-patternFinal note is:
Always/please do
qDebug << "con1:" << connect(xxx);
when using the SLOT() , SIGNAL() version and check it says "true" in Application output.
Its very helpful and takes the guessing away :)