Question Trying to implement keypress detection in Lua. [SOLVED]

dgatsoulis

ele2png user
Donator
Joined
Dec 2, 2009
Messages
1,924
Reaction score
340
Points
98
Location
Sparta
I am trying to implement keypress detection in lua.
I am creating a function in a dll with GetAsyncKeyState and I am accessing the function with package.loadlib.

keystate.dll
C++:
#include <Windows.h>

extern "C" __declspec(dllexport) bool IsKeyPressed(int virtualKeyCode)
{
    return (GetAsyncKeyState(virtualKeyCode) & 0x8000) != 0;
}
lua script:
Code:
func = package.loadlib("keystate.dll", "IsKeyPressed")
if func then
    msg1 = ("DLL loaded successfully")
   
else
   msg1 =("Error loading DLL")
end


goals = 0
while goals < 1 do
 keyPressed = func(0x41) -- 0x41 is the virtual key code for the 'A' key
 if keyPressed then
        msg =("A key is pressed")
    else
        msg =("A key is not pressed")
 end
 note:set_text(msg1.." "..msg)
 proc.skip()
 if goals > 0 then end
end

whether the A key is pressed or not, the response I am getting is: "DLL loaded successfully A key is not pressed".

Can anyone tell me why this isn't working?
Any help is much appreciated.
 
Last edited:

martins

Orbiter Founder
Orbiter Founder
Joined
Mar 31, 2008
Messages
2,448
Reaction score
462
Points
83
Website
orbit.medphys.ucl.ac.uk
I think the problem is that the function you pass in the second parameter of package.loadlib is meant to be a initialisation routine for the library you define, rather than a custom function to be called in the script. It has a required form of "int init(lua_State*).

This should work:

keystate.dll:
C++:
#include <windows.h>

extern "C" {
#include "Lua\lua.h"
#include "Lua\lualib.h"
#include "Lua\lauxlib.h"
}

int my_key_pressed(lua_State * L)
{
    int virtualKeyCode = lua_tointeger(L, 1);
    lua_pushboolean(L, GetAsyncKeyState(virtualKeyCode) & 0x8000 ? 1 : 0);
    return 1;
}

extern "C" __declspec(dllexport) int init(lua_State * L)
{
    static const struct luaL_Reg testlib[] = {
        {"mykeypressed", my_key_pressed},
        {NULL, NULL}
    };
    luaL_register(L, "testlib", testlib);
    return 1;
}
Script:
Code:
keylib = package.loadlib("keystate.dll", "init");
if keylib then
    msg1 = "DLL loaded successfully"
else
    msg1 = "Error loading DLL"
end

keylib()

note = oapi.create_annotation()
note:set_pos (0.25,0.15,0.9,0.95)
note:set_colour ({r=1,g=0.6,b=0.2})

goals = 0
while goals < 1 do
 keyPressed = testlib.mykeypressed(0x41) -- 0x41 is the virtual key code for the 'A' key
 if keyPressed then
        msg =("A key is pressed")
    else
        msg =("A key is not pressed")
 end
 note:set_text(msg1.." "..msg)
 proc.skip()
 if goals > 0 then end
end
It registers the key checking function as a library function. The function itself pulls the requested virtual key code from the lua stack (where it was left from the input argument), and pushes the result back to the stack (where it is available as a return value).
Note that the script, after loading the library, has to call the initialisation routine ("keylib()"), so that the registration is actually performed.

Something that confused the hell out of me when I was trying to find a solution was the fact that the name of the library you register in the initialisation routine (here: "testlib") must not be the same as the name of the library you assign to the return value of the package.loadlib call (here: "keylib"). Otherwise you overwrite the library you just created in the global namespace, and all its methods mysteriously disappear.
 

martins

Orbiter Founder
Orbiter Founder
Joined
Mar 31, 2008
Messages
2,448
Reaction score
462
Points
83
Website
orbit.medphys.ucl.ac.uk
Actually, it turns out that you can abuse the initialisation routine to give you the answer directly, which simplifies the code a bit.

keystate.dll:

C++:
#include <windows.h>

extern "C" {
#include "Lua\lua.h"
}

extern "C" __declspec(dllexport) int my_key_pressed(lua_State * L)
{
    int virtualKeyCode = lua_tointeger(L, 1);
    lua_pushboolean(L, GetAsyncKeyState(virtualKeyCode) & 0x8000 ? 1 : 0);
    return 1;
}
Script:
Code:
keypress = package.loadlib("keystate.dll", "my_key_pressed");
if keypress then
    msg1 = "DLL loaded successfully"
else
    msg1 = "Error loading DLL"
end


note = oapi.create_annotation()
note:set_pos (0.25,0.15,0.9,0.95)
note:set_colour ({r=1,g=0.6,b=0.2})

goals = 0
while goals < 1 do
 keyPressed = keypress(0x41) -- 0x41 is the virtual key code for the 'A' key
 if keyPressed then
        msg =("A key is pressed")
    else
        msg =("A key is not pressed")
 end
 note:set_text(msg1.." "..msg)
 proc.skip()
 if goals > 0 then end
end
 

dgatsoulis

ele2png user
Donator
Joined
Dec 2, 2009
Messages
1,924
Reaction score
340
Points
98
Location
Sparta
Thank you so much Martin! I will try it as soon as I get back home later today.
 

dgatsoulis

ele2png user
Donator
Joined
Dec 2, 2009
Messages
1,924
Reaction score
340
Points
98
Location
Sparta
I have attached on this post a compiled "keypress.dll". You can unzip the file in your Orbiter root directory and you can access it from a Lua script by
Code:
keypress = package.loadlib("keystate.dll", "my_key_pressed");
You can unload it by
Code:
keypress = nil

This will cause the Lua garbage collector to eventually collect the memory used by the DLL and unload it from memory.

Here is an example of a function that detects when the "A" key has been pressed and toggles a variable (keyA_var) from 0 to 1.
Code:
keyA_var = 0
timeSinceKeyPress_A = 0

function A_key()
    local keyPressed_A = keypress(65)
    if keyPressed_A then
        timeSinceKeyPress_A = timeSinceKeyPress_A + oapi.get_sysstep()
        if timeSinceKeyPress_A >= 0.1 then
            timeSinceKeyPress_A = 0
            if keyA_var == 0 then
                keyA_var = 1
            else
                keyA_var = 0
            end
        end
    else
        timeSinceKeyPress_A = 0
    end
end

When the A key is pressed (for 0.1 seconds) the keyA_var will go from 0 to 1. Press it again and it will go back to 0. You can also do combined keys:
This one toggles the Ctrl_E_var (0 - 1) when you press Ctrl + E for 0.1 seconds.

Code:
Ctrl_E_var = 0
timeSinceKeyPress_Ctrl_E = 0

function Ctrl_E_key()
    local keyPressed_Ctrl = keypress(17)
    local keyPressed_E = keypress(69)
    if keyPressed_Ctrl and keyPressed_E then
        timeSinceKeyPress_Ctrl_E = timeSinceKeyPress_Ctrl_E + oapi.get_sysstep()
        if timeSinceKeyPress_Ctrl_E >= 0.1 then
            timeSinceKeyPress_Ctrl_E = 0
            if Ctrl_E_var == 0 then
                Ctrl_E_var = 1
            else
                Ctrl_E_var = 0
            end
        end
    else
        timeSinceKeyPress_Ctrl_E = 0
    end
end

Below is a list of some of the most common virtual key codes for standard Windows keyboard keys:
Code:
"Backspace": 8
"Tab": 9
"Enter": 13
"Shift": 16
"Ctrl": 17
"Alt": 18
"Caps Lock": 20
"Escape": 27
"Spacebar": 32
"Page Up": 33
"Page Down": 34
"End": 35
"Home": 36
"Left Arrow": 37
"Up Arrow": 38
"Right Arrow": 39
"Down Arrow": 40
"Insert": 45
"Delete": 46
"0": 48
"1": 49
"2": 50
"3": 51
"4": 52
"5": 53
"6": 54
"7": 55
"8": 56
"9": 57
"A": 65
"B": 66
"C": 67
"D": 68
"E": 69
"F": 70
"G": 71
"H": 72
"I": 73
"J": 74
"K": 75
"L": 76
"M": 77
"N": 78
"O": 79
"P": 80
"Q": 81
"R": 82
"S": 83
"T": 84
"U": 85
"V": 86
"W": 87
"X": 88
"Y": 89
"Z": 90
"F1": 112
"F2": 113
"F3": 114
"F4": 115
"F5": 116
"F6": 117
"F7": 118
"F8": 119
"F9": 120
"F10": 121
"F11": 122
"F12": 123

This is not an exhaustive list, but it includes many of the standard keyboard keys that you might need to detect. You can find the full list of virtual key codes in the Windows API documentation.

Once again a big thanks to Martin for implementing this..
 

Attachments

  • keystate.zip
    4.9 KB · Views: 23

Thunder Chicken

Fine Threads since 2008
Donator
Joined
Mar 22, 2008
Messages
4,327
Reaction score
3,248
Points
138
Location
Massachusetts
@dgatsoulis @martins There is an interest in porting this method into OpenOrbiter:


I'm assuming from this thread that this code was written by dgatsoulis with assistance from Martin. If so, would you be willing to permit this code to be compiled against OpenOrbiter? It would make the small and loud group of Lua proponents very happy if you did. :)
 

dgatsoulis

ele2png user
Donator
Joined
Dec 2, 2009
Messages
1,924
Reaction score
340
Points
98
Location
Sparta
@dgatsoulis @martins There is an interest in porting this method into OpenOrbiter:


I'm assuming from this thread that this code was written by dgatsoulis with assistance from Martin. If so, would you be willing to permit this code to be compiled against OpenOrbiter? It would make the small and loud group of Lua proponents very happy if you did. :)
It was a shot in the dark from me after many unsuccessful attempts to get keypress detection in Lua. It was actually Martin that provided the correct working code. For my small part in this, I am absolutely fine for it to be used in OpenOrbiter.
 

Thunder Chicken

Fine Threads since 2008
Donator
Joined
Mar 22, 2008
Messages
4,327
Reaction score
3,248
Points
138
Location
Massachusetts
It was a shot in the dark from me after many unsuccessful attempts to get keypress detection in Lua. It was actually Martin that provided the correct working code. For my small part in this, I am absolutely fine for it to be used in OpenOrbiter.
Thanks. It's unclear where it sits with regard to the OpenOrbiter license so it was best to ask. It isn't a part of the code base.
 
Top