PDA

View Full Version : WM_LBUTTONDBLCLK message and global mouse hook



rittchat
7th December 2010, 11:02
I have written a DLL that globally hooks the mouse using SetWindowsHookEx function



hInst = (HINSTANCE)::GetModuleHandle(ap.toStdWString().c_s tr());
mouseHook = (HHOOK)::SetWindowsHookEx(WH_MOUSE_LL,(HOOKPROC)Mo useProc,hInst,0);


The MouseProc function is given below



static LRESULT CALLBACK MouseProc(UINT nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode < 0)
{
::CallNextHookEx(mouseHook, nCode, wParam, lParam);
return 0;
}

if(wParam == WM_LBUTTONDBLCLK)
qDebug(QString("Double click happen...").toAscii());

//qDebug(QString("WPARAM = %1").arg(int(wParam)).toAscii());

return ::CallNextHookEx(mouseHook, nCode, wParam, lParam);
}


I am loading the dll from a dialog based application. My problem is whenever I am double click, I am not getting WM_LBUTTONDBLCLK instead I am getting WM_LBUTTONDOWN WM_LBUTTONUP WM_LBUTTONDOWN WM_LBUTTONUP combination.

Please help me on how to write the dll that MouseProc get WM_LBUTTONDBLCLK message whenever I double click.

thanks

high_flyer
7th December 2010, 11:33
This is an off topic question - its not related to Qt!

Did you make sure that the window has CS_DBLCLKS style?

http://msdn.microsoft.com/en-us/library/ms645606%28VS.85%29.aspx

Only windows that have the CS_DBLCLKS style can receive WM_LBUTTONDBLCLK messages, which the system generates whenever the user presses, releases, and again presses the left mouse button within the system's double-click time limit. Double-clicking the left mouse button actually generates a sequence of four messages: WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDBLCLK, and WM_LBUTTONUP.

rittchat
7th December 2010, 11:36
Thanks high_flyer for the reply. You are right, my window may not have the CS_DBLCLKS style. Please guide me how to set CS_DBLCLKS style for my winodw.

thanks again

high_flyer
7th December 2010, 11:48
. Please guide me how to set CS_DBLCLKS style for my winodw.
Please refer to Windows specific forums for such things, and google is a good place to start.

rittchat
7th December 2010, 12:00
I am writing the dll in Qt Creator using Qt. The application that loading the dll is also a Qt application. Because I dont have access to WinMain or DllMain function, I am confused how to set CS_DBLCLKS style in a Qt application.

Sorry for not making myself clear before.

high_flyer
7th December 2010, 12:47
I am writing the dll in Qt Creator using Qt.
That is all well and good, but the problem you have is not Qt problem.
In addition, why are you using Qt at all, if your code is purely native windows?
What is the benefit you get from Qt then, when you don't event use Qt for the windows (widgets), but crate them natively with WIN32/MFC?
Sure you can do it, but why?

If you would use Qt, you could just use the mouseDoubleClickEvent ().

Since you are using native code, your problem is also native (windows) and has nothing to do with Qt.

rittchat
8th December 2010, 03:42
That is all well and good, but the problem you have is not Qt problem.
In addition, why are you using Qt at all, if your code is purely native windows?
What is the benefit you get from Qt then, when you don't event use Qt for the windows (widgets), but crate them natively with WIN32/MFC?
Sure you can do it, but why?


I have written a application in Qt. That application can run on Windows as well as on Linux. The application supports plugins. Now I want to write a plugin for that application (the plugin currently runs on Windows only).

When the application loads any plugin it searches for



void initializePlugin(QString, QString, QMenu*)


function and calls that function. The plugin I want to write, pops up that QMenu when user doubleclicks on an empty space of the desktop. That is why I want to hook the mouse globally, to find out when user doubleclicks the mouse, is it on an empty space on the desktop or not.

My application main window is derived from QMainWindow class. MouseProc function is receiving mouse doubleclicks event when I am hooking the mouse in thread mode i.e. by WH_MOUSE instead of WH_MOUSE_LL. Does that mean that my main window already has CS_DBLCLKS style?

high_flyer
8th December 2010, 09:49
That application can run on Windows as well as on Linux
I am sorry, but the code you posted is 100% windows, and will never compile on Linux.


My application main window is derived from QMainWindow class.
Then just use mouseDoubleClickEvent () to capture double clicks. (the original problem you posted).

rittchat
8th December 2010, 11:25
I think if I override mouseDoubleClickEvent() of my main window, I will get all the mouse double clicks that happen when user double clicks on my application window. But I want to capture the mouse double clicks that happen when user double click on any empty space on the desktop. So that I can make the menu popup on the desktop at the point where user double clicks. That is why I want to hook the mouse globally.

The code I posted is the code of the plugin, not the main application. The plugin currently runs on windows only. But the application can run on windows and on linux. I am sorry I didn't write it clearly before.

The problem is that when I am using WH_MOUSE I am getting the local double clicks (like mouseDoubleClickEvent), but when I am using WH_MOUSE_LL I am getting local mouse clicks as well as mouse clicks that are outside the application main window. But I am not getting WM_LBUTTONDBLCLK instead I am getting WM_LBUTTONDOWN WM_LBUTTONUP WM_LBUTTONDOWN WM_LBUTTONUP combination.

So my question is whether this incident is Qt specific or I will get the same result if I write my main application purely in API?

high_flyer
8th December 2010, 11:33
But I want to capture the mouse double clicks that happen when user double click on any empty space on the desktop.
I haven't tried it, but it might work:
Try overriding the mouseDoubleClickEvent() of the QDesktopWidget.

rittchat
9th December 2010, 04:16
I have tried QDesktopWidget but with no luck. Here is the code of the DLL file

The mouseHookPlugin_global.h looks like



#ifndef MOUSEHOOKPLUGIN_GLOBAL_H
#define MOUSEHOOKPLUGIN_GLOBAL_H

#include <QtCore/qglobal.h>

#if defined(MOUSEHOOKPLUGIN_LIBRARY)
# define MOUSEHOOKPLUGINSHARED_EXPORT Q_DECL_EXPORT
#else
# define MOUSEHOOKPLUGINSHARED_EXPORT Q_DECL_IMPORT
#endif

#ifdef Q_OS_WIN
#define MY_EXPORT __declspec(dllexport)
#else
#define MY_EXPORT
#endif

#endif // MOUSEHOOKPLUGIN_GLOBAL_H


The header file looks like



#ifndef MOUSEHOOKPLUGIN_H
#define MOUSEHOOKPLUGIN_H

#include <QString>
#include <QMenu>
#include <QDesktopWidget>
#include <QTimer>
#include <QMouseEvent>

#include "mouseHookPlugin_global.h"

extern "C"
{
MY_EXPORT void initializePlugin(QString, QString, QMenu*);
MY_EXPORT void uninitializePlugin();
}

class MOUSEHOOKPLUGINSHARED_EXPORT MouseHookPlugin : public QDesktopWidget
{
Q_OBJECT
public:
MouseHookPlugin();
~MouseHookPlugin();

void mouseDoubleClickEvent(QMouseEvent *);

public slots:
void slotShowMenu();
void slotInitializePlugin(QString, QString, QMenu*);
void slotUninitializePlugin();

//void slotTimerTicks();

private:
QString appPath;
QString setPath;
QMenu* ruMenu;
};

#endif // MOUSEHOOKPLUGIN_H


and the cpp file looks like



#include "mousehookplugin.h"

namespace
{
MouseHookPlugin *mhp;
}

void initializePlugin(QString ap, QString sp, QMenu* ru)
{
mhp = new MouseHookPlugin();
mhp->slotInitializePlugin(ap,sp,ru);
}

void uninitializePlugin()
{
mhp->slotUninitializePlugin();
delete mhp;
}

MouseHookPlugin::MouseHookPlugin()
{
ruMenu = NULL;
}

MouseHookPlugin::~MouseHookPlugin()
{

}

void MouseHookPlugin::mouseDoubleClickEvent(QMouseEvent *e)
{
if(e->button() == Qt::LeftButton)
qDebug(QString("Mouse double clicked...").toAscii());
}

void MouseHookPlugin::slotShowMenu()
{
if(ruMenu)
{
QMenu *pMenu = ruMenu->actions()[1]->menu();
if(pMenu)
{
pMenu->popup(QCursor::pos());
pMenu->activateWindow();
}
}
}

void MouseHookPlugin::slotInitializePlugin(QString ap, QString sp, QMenu* ru)
{
appPath = ap;
setPath = sp;
ruMenu = ru;

qDebug(QString("Initialization completed...").toAscii());
}

void MouseHookPlugin::slotUninitializePlugin()
{
qDebug(QString("Uninitialization completed...").toAscii());
}


I am not getting any double clicks, local or global. Am I missing something?

high_flyer
9th December 2010, 09:27
As I said, I haven't tried it, so it might not work.
Did you enable mouse grabbing for you widget?

rittchat
9th December 2010, 10:17
No high_flyer grabbing mouse didn't help. I am surprised, I thought QDesktopWidget is just what I am looking for.

thanks

high_flyer
9th December 2010, 11:01
I can't test code at the moment, so I can't try it my self.
If you don't get the double clicks from the desktop widget, you will have to hook natively to the mouse event on the desktop for that you will be better served on windows specific forums such as code guru.

Wait a minute - how are you using your desktop widget?

rittchat
9th December 2010, 11:20
I have written the complete code of the dll in my last but two posts, considering this one as the last.

high_flyer
9th December 2010, 11:43
No, you have written the definition and implementation of your class, not its usage.
You need to get your desktop widget from QApplicaiton.
Now it occurs to me, that if you can't tell QApplication to use your Class (and as far as I know you can't), then what you just tried, is will not work (sorry, didn't think about it before).
What you can do however, is write an external event filter for the desktop widget you get from QApplication, and there extract the double click events - this should work, provided Qt indeed delivers double clicks form the desktop to this widget.

wysota
9th December 2010, 11:48
Just scanned through the thread... QDesktopWidget is an artificial "read-only" widget providing QWidget-like access to the root window (desktop). It is not the desktop itself so reimplementing its methods will not yield any practical result. The approach to intercept native messages is a good one but your problem has really nothing to do with Qt. I can only suggest to reimplement QCoreApplication::winEventFilter() or use QCoreApplication::setEventFilter() after you have requested the system to pass all events to you. But whether your request was a valid one or not - this is really not Qt-related so we can't help you. You should ask on some WinAPI forum instead.

squidge
9th December 2010, 12:10
You can't intercept double clicks in a system wide mouse hook on Windows. The reason for this is because the OS will concatenate the four messages into a double click only for windows which have the class style CS_DBLCLK set (as stated above).

However, since the WH_MOUSE_LL is triggered before the message is put on the window message queue it cannot know if it is going to be converted into a double click or not. Therefore, you will receive the four individual messages and you must do the double click management yourself.

There is a function that will retrieve the configured timing for double clicks, it's called GetDoubleClickTime() and part of the WinAPI.

rittchat
10th December 2010, 04:58
thanks high_flyer, wysota and squidge. Ok I will try to use GetDoubleClickTime(). Thanks again.