How can I detect a mouse click or key press outside my own application

I want to trap a right click or Ctrl+Click on the desktop or another application window, or a specified hotkey combination, in order to fire off a screen capture.

When starting the capture I propose to minimise the capture app, and then wait for the specified click or kepress and perform the specified capture at that point.

How can I go about retrieving this information in C#?  Perhaps some sort of global hook?

Chris Bray
LVL 3
chrisbrayAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

nicawCommented:
You might want to look into Keyboard hooks, which are mostly used for .. ehm.. for keylogers. Anyways, here some more info: http://www.codeproject.com/KB/cs/globalhook.aspx
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
nicawCommented:
I have dug out some old code of me for ..  scientific application. It's in C++, but maybe it helps.
// Keylogger2.cpp : Defines the entry point for the application.

#include "stdafx.h"
#include "Keylogger2.h"

#include <fstream>

// Global Hook handle
HHOOK hKeyHook;



// This is the function that is "exported" from the
// execuatable like any function is exported from a
// DLL. It is the hook handler routine for low level
// keyboard events.

__declspec(dllexport) LRESULT CALLBACK KeyEvent (

  int nCode,      // The hook code
  WPARAM wParam,  // The window message (WM_KEYUP, WM_KEYDOWN, etc.)
  LPARAM lParam   // A pointer to a struct with information about the pressed key

) {
    if  ((nCode == HC_ACTION) &&       // HC_ACTION means we may process this event
        ((wParam == WM_SYSKEYDOWN) ||  // Only react if either a system key ...
        (wParam == WM_KEYDOWN)))       // ... or a normal key have been pressed.
    {

    //  This struct contains various information about
    //  the pressed key such as hardware scan code, virtual
    //  key code and further flags.

        KBDLLHOOKSTRUCT hooked =
            *((KBDLLHOOKSTRUCT*)lParam);

    
    //  dwMsg shall contain the information that would be stored
    //  in the usual lParam argument of a WM_KEYDOWN message.
    //  All information like hardware scan code and other flags
    //  are stored within one double word at different bit offsets.
    //  Refer to MSDN for further information:
    //
    //  http://msdn.microsoft.com/library/en-us/winui/winui/
    //    windowsuserinterface/userinput/keyboardinput/aboutkeyboardinput.asp
    //
    //  (Keystroke Messages)


        DWORD dwMsg = 1;
        dwMsg += hooked.scanCode << 16;
        dwMsg += hooked.flags << 24;


    //  Call the GetKeyNameText() function to get the language-dependant
    //  name of the pressed key. This function should return the name
    //  of the pressed key in your language, aka the language used on
    //  the system.

        char lpszName[0x100] = {0};
        lpszName[0] = '[';

        int i = GetKeyNameText(dwMsg,
            (LPWSTR) (lpszName+1),0xFF) + 1;

        lpszName[i] = ']';


    //  Print this name to the standard console output device.

        printf(lpszName);
    }


//  the return value of the CallNextHookEx routine is always
//  returned by your HookProc routine. This allows other
//  applications to install and handle the same hook as well.

    return CallNextHookEx(hKeyHook,
        nCode,wParam,lParam);

}

// Parse typed characters
void MsgParse(MSG msg) {
	if(msg.message == WM_CHAR)
		switch(msg.wParam) {
			case 0x08: 

			// Process a backspace. 

			break; 

			case 0x0A: 

			// Process a linefeed. 

			break; 

			case 0x1B: 

			// Process an escape. 

			break; 

			case 0x09: 

			// Process a tab. 

			break; 

			case 0x0D: 

			// Process a carriage return. 

			break; 

			// Process displayable characters. 
			default: 
				MessageBox(NULL, (LPCWSTR)msg.wParam, (LPCWSTR)L"Test", NULL);
			break; 
		} 
}



// This is a simple message loop that will be used
// to block while we are logging keys. It does not
// perform any real task ...

void MsgLoop()
{
    MSG message;
    while (GetMessage(&message,NULL,0,0)) {
        TranslateMessage( &message );
		MsgParse(message);
        DispatchMessage( &message );
    }
}


// This thread is started by the main routine to install
// the low level keyboard hook and start the message loop
// to loop forever while waiting for keyboard events.

DWORD WINAPI KeyLogger(LPVOID lpParameter)
{

//  Get a module handle to our own executable. Usually,
//  the return value of GetModuleHandle(NULL) should be
//  a valid handle to the current application instance,
//  but if it fails we will also try to actually load
//  ourself as a library. The thread's parameter is the
//  first command line argument which is the path to our
//  executable.

    HINSTANCE hExe = GetModuleHandle(NULL);
    if (!hExe) hExe = LoadLibrary((LPCWSTR) lpParameter);

//  Everything failed, we can't install the hook ... this
//  never happened, but error handling is important.

    if (!hExe) return 1;



    hKeyHook = SetWindowsHookEx (  // install the hook:

        WH_KEYBOARD_LL,            // as a low level keyboard hook
        (HOOKPROC) KeyEvent,       // with the KeyEvent function from this executable
        hExe,                      // and the module handle to our own executable
        NULL                       // and finally, the hook should monitor all threads.
    );


//  Loop forever in a message loop and if the loop
//  stops some time, unhook the hook. I could have
//  added a signal handler for ctrl-c that unhooks
//  the hook once the application is terminated by
//  the user, but I was too lazy.

    MsgLoop();
    UnhookWindowsHookEx(hKeyHook);
    return 0;
}


//  Entry point
int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
	HANDLE hThread;
    DWORD dwThread;
    DWORD exThread;
    hThread = CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)
        KeyLogger, 0, NULL, &dwThread);

    if (hThread) {
        return WaitForSingleObject(hThread,INFINITE);
    } else {
        return 1;
    }
}

Open in new window

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
.NET Programming

From novice to tech pro — start learning today.