Question Send key combination with Lua [SOLVED]

dgatsoulis

ele2png user
Donator
Joined
Dec 2, 2009
Messages
1,924
Reaction score
339
Points
98
Location
Sparta
I am writing an ascent autopilot for the XR2 in Lua, and I need a way to send key combinations to the Ravenstar. I tried v:send_bufferedkey, but it takes only one input (keycode).
I attempted using nested while loops but I only got one key pressed, not both at the same time:

Code:
goal = 0
while goal < 1 do
  control_key = v:send_bufferedkey(OAPI_KEY.LCONTROL)
   while control_key ~= nil do
    --control_key = v:send_bufferedkey(OAPI_KEY.LCONTROL)
    a_key = v:send_bufferedkey(OAPI_KEY.A)
    if a_key ~= nil then
        control_key = nil
        goal = 1
    end
   end
   if goal > 0 then end
end

My next attempt was to send the key combo from a vb script:
Code:
-- Define the VBScript code
local vbscript = [[
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.SendKeys "^a"
Set WshShell = Nothing
]]

-- Create a temporary VBScript file
local vbscriptFileName = os.tmpname() .. ".vbs"
local vbscriptFile = io.open(vbscriptFileName, "w")
vbscriptFile:write(vbscript)
vbscriptFile:close()

-- Execute the VBScript
os.execute("cscript " .. vbscriptFileName)

-- Delete the temporary VBScript file
os.remove(vbscriptFileName)

Again, same result. The script runs, but the keys are not pressed at the same time. (In a landed Ravenstar, I get the "Hover doors are closed" message, showing that it received the A key, not the CTRL-A combo).

In the OrbiterSDK, SendBufferedKey takes 3 arguments:
int VESSEL::SendBufferedKey ( DWORD key, bool down = true, char * kstate = 0 )
In Lua, it takes only one:
res = v:send_bufferedkey(keycode)
Sends a keycode message to the vessel.
In the interpreter, the send_bufferedkey method is implemented like this:
C++:
int Interpreter::v_send_bufferedkey (lua_State *L)
{
    static char *funcname = "send_bufferedkey";
    AssertMtdMinPrmCount(L, 2, funcname);
    VESSEL *v = lua_tovessel_safe(L, 1, funcname);
    int key = luamtd_tointeger_safe (L, 2, funcname);
    int res = v->SendBufferedKey (key);
    lua_pushnumber (L, res);
    return 1;
}

How can I change it to also take the kstate argument?
Thanks in advance.
 
Last edited:

dgatsoulis

ele2png user
Donator
Joined
Dec 2, 2009
Messages
1,924
Reaction score
339
Points
98
Location
Sparta
Ok, I found a solution that is a bit convoluted, but gets the job done:
C++:
int Interpreter::v_send_ctrlbufferedkey(lua_State *L)
{
    static char *funcname = "send_ctrlbufferedkey";
    AssertMtdMinPrmCount(L, 2, funcname);
    VESSEL *v = lua_tovessel_safe(L, 1, funcname);
    int key = luamtd_tointeger_safe(L, 2, funcname);
    char kstate[256];
    ZeroMemory(kstate, sizeof(kstate));
    kstate[key] = 0x80;
    kstate[OAPI_KEY_LCONTROL] = 0x80;
    int res = v->SendBufferedKey(key, true, kstate);
    lua_pushnumber(L, res);
    return 1;
}
int Interpreter::v_send_shiftbufferedkey(lua_State *L)
{
    static char *funcname = "send_shiftbufferedkey";
    AssertMtdMinPrmCount(L, 2, funcname);
    VESSEL *v = lua_tovessel_safe(L, 1, funcname);
    int key = luamtd_tointeger_safe(L, 2, funcname);
    char kstate[256];
    ZeroMemory(kstate, sizeof(kstate));
    kstate[key] = 0x80;
    kstate[OAPI_KEY_LSHIFT] = 0x80;
    int res = v->SendBufferedKey(key, true, kstate);
    lua_pushnumber(L, res);
    return 1;
}
int Interpreter::v_send_altbufferedkey(lua_State *L)
{
    static char *funcname = "send_altbufferedkey";
    AssertMtdMinPrmCount(L, 2, funcname);
    VESSEL *v = lua_tovessel_safe(L, 1, funcname);
    int key = luamtd_tointeger_safe(L, 2, funcname);
    char kstate[256];
    ZeroMemory(kstate, sizeof(kstate));
    kstate[key] = 0x80;
    kstate[OAPI_KEY_LALT] = 0x80;
    int res = v->SendBufferedKey(key, true, kstate);
    lua_pushnumber(L, res);
    return 1;
}

I added 3 more sendbuffered methods, to account for the CTRL, ALT and SHIFT keys. I know, it's not pretty, but they allow me to send key combinations to a vessel.

I was under the false impression, that I would be able to also control the (left) MFDs with those, by sending the v_send_shiftbufferedkey command, but it doesn't work.

I also added a send_input_key command, that can also take modifiers as an argument, but when it comes to sending a command to an open MFD, it doesn't work either.
C++:
void PressKey(WORD key)
{
    INPUT input;
    input.type = INPUT_KEYBOARD;
    input.ki.wVk = key;
    input.ki.dwFlags = 0; // Press the key
    SendInput(1, &input, sizeof(INPUT));
}

void ReleaseKey(WORD key)
{
    INPUT input;
    input.type = INPUT_KEYBOARD;
    input.ki.wVk = key;
    input.ki.dwFlags = KEYEVENTF_KEYUP; // Release the key
    SendInput(1, &input, sizeof(INPUT));
}
int Interpreter::send_input_key(lua_State* L)
{
    //static char* funcname = "send_input_key";
    //AssertMtdMinPrmCount(L, 1, funcname);

    int modifier = lua_tointeger(L, 1);
    int key = lua_tointeger(L, 2);

    // Press modifier
    PressKey(modifier);
    Sleep(10);
    // Press key while modifier is held
    PressKey(key);

    // Release key and then release modifier
    ReleaseKey(key);
    ReleaseKey(modifier);

    return 0; // No need to return a value to Lua
}

It can send keys, (modified or unmodified) to Orbiter, but it cannot control the MFDs.
Does any one know if it can be done ? How can I send a key to an open MFD ?

----------------EDIT--------------------
Can't believe that I didn't find it earlier. int oapiSendMFDKey ( int mfd, DWORD key ) Sends a keystroke to an MFD.
Not sure if it's implemented in Lua, but if it isn't, it's not that hard to add.
Question solved.
 
Last edited:
Top