LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Windows Keyboard Entry

Is there a way we can detect keyboard strokes from LabVIEW through a dynamic event?

The idea is to trigger an event whenever the user hits "LWIN + F" for example.

The keyboard strokes can be anywhere in windows, it could be on another application, not only on the LabVIEW application or controls.

0 Kudos
Message 1 of 21
(783 Views)

I think Initialize Keyboard/Acquire Input Data should be helpful for you:

 

Screenshot 2024-10-10 06.59.33.png

0 Kudos
Message 2 of 21
(744 Views)

How do I register this as a user event?

This is what I have so far but it doesn't work.

 

Sable_0-1728539339722.png

 

0 Kudos
Message 3 of 21
(727 Views)

@Sable wrote:

How do I register this as a user event?


You can't do it directly. You have to run a polling loop to monitor the keyboard state and you can generate a user event whenever that array changes. This loop can be in a subVI, but then you also need a way to stop it.

 

 

Edit: this refers specifically to these VIs. Windows does have hooks for keyboard events, but I don't think you can write the code to intercept those directly in LV, at least not as a system-wide hook.


___________________
Try to take over the world!
0 Kudos
Message 4 of 21
(719 Views)

@tst wrote:

Edit: this refers specifically to these VIs. Windows does have hooks for keyboard events, but I don't think you can write the code to intercept those directly in LV, at least not as a system-wide hook.


One could but that requires external C code in a DLL. It could be a feature in the underlaying lvinput.dll but that DLL is old, and quite likely nobody at NI feels any temptation to touch the source code for that with a 10 foot pole. And if someone does feel like digging in there he would not be allowed to spend any time on that. Such a feature costs a lot of time, to get acquainted with the ancient code in it, to understand the exact troubles involved, to modify the code, add VI wrappers, test, crash, test, crash and test again. And finally update the whole documentation about these VIs. This easily can turn out to be a several man month project and for what? To let a few users avoid having to create a poll loop in their application! Any product manager will shoot down this idea immediately unless there is a very significant commercial gain to be had. Anybody thinks there will be even one single additional LabVIEW user because of that?

Rolf Kalbermatter
My Blog
0 Kudos
Message 5 of 21
(710 Views)

@rolfk wrote:

@tst wrote:

Edit: this refers specifically to these VIs. Windows does have hooks for keyboard events, but I don't think you can write the code to intercept those directly in LV, at least not as a system-wide hook.


One could but that requires external C code in a DLL. ...


Well ,the "hardcore" way may looks like this (very quick and very dirty):

The C code for DLL:

Spoiler
//==============================================================================
//
// Title:		DLLHook
// Purpose:		Traverse Hot Keys to LabVIEW App via User Event.
//
// Created on:	10.10.2024 by AD.
// https://stackoverflow.com/questions/29734263/creating-global-keyboard-hook
//==============================================================================

#include <windows.h>
#include <stdio.h>
#include <utility.h>
#include "DLLHook.h"

HHOOK hKeyboardHook;
LVUserEventRef *lvEvent;
HANDLE hThread;
DWORD dwThread;

__declspec(dllexport) LRESULT CALLBACK KeyboardEvent (int nCode, WPARAM wParam, LPARAM lParam)
{
	DWORD LWIN_key = 0;
	DWORD RWIN_key = 0;
	int hotkey = -1;

    if  ((nCode == HC_ACTION) && ((wParam == WM_SYSKEYDOWN) || (wParam == WM_KEYDOWN))) {
		KBDLLHOOKSTRUCT hooked_key = *((KBDLLHOOKSTRUCT*)lParam);
    	DWORD dwMsg = 1;
		dwMsg += hooked_key.scanCode << 16;
		dwMsg += hooked_key.flags << 24;
		char lpszKeyName[1024] = {0};

        GetKeyNameText(dwMsg, (lpszKeyName + 1), 0xFF) + 1;
        int key = hooked_key.vkCode;
 		LWIN_key = GetAsyncKeyState(VK_LWIN);
 		RWIN_key = GetAsyncKeyState(VK_RWIN);
		
 		// Uncomment to see all key presses in DebugView:
		// char buf[256];
        // sprintf(buf, "Keycode = %c\n", key); OutputDebugStringA(buf);

        if (LWIN_key !=0 && (key == 'f' || key == 'F') ) {
			hotkey = 0; LWIN_key = 0;
        }
			
        if (RWIN_key !=0 && (key == 'f' || key == 'F') ) {
			hotkey = 1; RWIN_key = 0;
        }
		if (hotkey >= 0 && lvEvent) PostLVUserEvent(*lvEvent, (void *)&hotkey); //Fire LV Event

    }
    return CallNextHookEx(hKeyboardHook, nCode,wParam,lParam);
}

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

DWORD WINAPI my_HotKey(LPVOID lpParm)
{
    HINSTANCE hInstance = GetModuleHandle(NULL);
    if (!hInstance) hInstance = LoadLibrary ((LPCSTR) lpParm); 
    if (!hInstance) return 1;

    hKeyboardHook = SetWindowsHookEx (WH_KEYBOARD_LL, (HOOKPROC)KeyboardEvent, hInstance, 0);
    MessageLoop();
    UnhookWindowsHookEx(hKeyboardHook);
    return 0;
}

//==============================================================================
// Exported function
//
int RegisterHook(LVUserEventRef *LVevent)
{
	lvEvent = LVevent;
	return 0;
}

//==============================================================================
// DLL main entry-point functions
//
int __stdcall DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
	switch (fdwReason) {
		case DLL_PROCESS_ATTACH:
			if (InitCVIRTE (hinstDLL, 0, 0) == 0)
				return 0; /* out of memory */
			if (!hThread) hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)my_HotKey, NULL, 0, &dwThread);
			OutputDebugStringA("Hook attached");
			break;
		case DLL_PROCESS_DETACH:
			PostQuitMessage(0);
			if (hThread){
				TerminateThread(hThread, 0);
				CloseHandle(hThread);
				hThread = 0;
			}
			CloseCVIRTE ();
			OutputDebugStringA("Hook detached");
			break;
	}
	return 1;
}

Block Diagram:

 

hook_snippet.png

and works, also when focus not on LabVIEW's Front Panel:

hook.gif

But I'll not take any responsibilities for crashes or "side effects", use on own risk (I did this exercise long long time ago in the past, but unable to found 100% working solution).

Full source in the attachment, the DLL was built with latest NI CVI (could be easily ported to MSVC), the LabVIEW code downgraded to 2018, tested with x64 (2024Q3), should work in theory also with 32-bit (but wasn't tested).

0 Kudos
Message 6 of 21
(690 Views)

This looks promising...do you mind to downgrade the LabVIEW code to 2013?

0 Kudos
Message 7 of 21
(672 Views)

@Sable wrote:

This looks promising...do you mind to downgrade the LabVIEW code to 2013?


Here saved for LabVIEW 2013:

 

0 Kudos
Message 8 of 21
(658 Views)

Do you know what does this error mean?

 

Sable_0-1728561584624.png

 

0 Kudos
Message 9 of 21
(594 Views)

@Sable wrote:

Do you know what does this error mean?

 

Sable_0-1728561584624.png

 


Try to download and install latest CVI Run-Time 2020:


LabWindows/CVI Runtime Download

 

If this will not help, then I can recompile DLL using Visual Studio 2022 instead of NI CVI 2020.

0 Kudos
Message 10 of 21
(585 Views)