I have 2 scripts, each are in a different lua_State.
I am trying to be able to get a variable from one state and use it in the other.
My code below works for single variables and unidirectional arrays. Could I get some guidance on also making it work for multidimensional arrays?
void getValues(lua_State* L1, lua_State* L2, int& returns)
{
if (lua_isuserdata(L1, -1))
{
LuaElement* e = Luna<LuaElement>::to_object(L1, -1);
if (e != NULL)
{
Luna<LuaElement>::push_object(L2, e);
}
}
else if (lua_isstring(L1, -1))
{
lua_pushstring(L2, lua_tostring(L1, -1));
}
else if (lua_isnumber(L1, -1))
lua_pushnumber(L2, lua_tonumber(L1, -1));
else if (lua_isboolean(L1, -1))
lua_pushboolean(L2, lua_toboolean(L1, -1));
else if (lua_istable(L1, -1))
{
lua_pushnil(L1);
lua_newtable(L2);
while (lua_next(L1, -2))
{
getValues(L1, L2, returns);
lua_rawseti(L2,-2,returns-1);
lua_pop(L1, 1);
}
// lua_rawseti(L2,-2,returns); // this needs work
}
returns++;
}
Unfortunately I'm having a tough time getting the recursion right for this to work for multidimensional arrays.
Solved.
For anyone this might be useful:
void getValues(lua_State* L1, lua_State* L2, int ind)
{
if (lua_type(L1, -1) == LUA_TTABLE)
{
lua_newtable(L2);
lua_pushnil(L1);
ind = 0;
while (lua_next(L1, -2))
{
// push the key
if (lua_type(L1, -2) == LUA_TSTRING)
lua_pushstring(L2, lua_tostring(L1, -2));
else if (lua_type(L1, -2) == LUA_TNUMBER)
lua_pushnumber(L2, lua_tonumber(L1, -2));
else
lua_pushnumber(L2, ind);
getValues(L1, L2, ind++);
lua_pop(L1, 1);
lua_settable(L2, -3);
}
}
else if (lua_type(L1, -1) == LUA_TSTRING)
{
lua_pushstring(L2, lua_tostring(L1, -1));
}
else if (lua_type(L1, -1) == LUA_TNUMBER)
{
lua_pushnumber(L2, lua_tonumber(L1, -1));
}
else if (lua_type(L1, -1) == LUA_TBOOLEAN)
{
lua_pushboolean(L2, lua_toboolean(L1, -1));
}
else if (lua_type(L1, -1) == LUA_TUSERDATA)
{
// replace with your own user data. This is mine
LuaElement* e = Luna<LuaElement>::to_object(L1, -1);
if (e != NULL)
{
Luna<LuaElement>::push_object(L2, e);
}
}
}
Warning: L1 and L2 must be different states.
You can try lua_tinker::table:
Related
My program makes simple movements with the mouse, I use c++, it works through the console, I would like to pause on the ''0x32, 0x33, 0x34'' key and make it work again on the ''0x31'' key
if (GetAsyncKeyState(MOUSEEVENTF_MOVE) < 0) {
if (!is_mouse_down) {
is_mouse_down = true;
if (gun != nullptr)
gun_index = 0;
}
if (gun != nullptr && gun_index != gun->len) {
mouse_event(MOUSEEVENTF_MOVE, long(gun->pattner[gun_index][0] * K), long(gun->pattner[gun_index][1] * K), 0, 0);
++gun_index;
Sleep(gun_delay);
continue;
}
}
else
is_mouse_down = false;
Sleep(150);
}
return 0;
}
Ok, so as in the title I am trying to make a custom shortcut keyboard with esp32 with Arduino ide and keep running into errors so if someone could fix it all for me that would be appreciated.
one of these errors is: no return statement in function returning non-void [-Werror=return-type]
Code:
#include <BleKeyboard.h>
BleKeyboard bleKeyboard;
const int buttonPin[] = {36, 39, 34, 35, 32, 33};
int pinCount = 6;
int potPin = 2;
int prevPotState = -1;
int potState = -1;
int potTolerance = 1;
long potDebounceDelay = 20;
int buttonState[] = {1, 1, 1, 1, 1, 1};
int prevButtonState[] = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH};
long startedPressing[] = {0, 0, 0, 0, 0, 0};
boolean longPressing[] = {false, false, false, false, false, false};
long lastDebounceTime[] = {0, 0, 0, 0, 0, 0, 0}; // 1 more for the pot
long debounceDelay = 0;
boolean testHardware = false;
int keyComb(char key1 = 0, char key2 = 0, char key3 = 0, char key4 = 0) {
if (key1 != 0) {
bleKeyboard.press(key1);
}
if (key2 != 0) {
bleKeyboard.press(key2);
}
if (key3 != 0) {
bleKeyboard.press(key3);
}
if (key4 != 0) {
bleKeyboard.press(key4);
}
delay(100);
bleKeyboard.releaseAll();
}
int sendLine(char const * line) {
bleKeyboard.print(line);
delay(750);
keyComb(KEY_RETURN);
}
// Output actions. Probably the only part that you need to change
int outputAction(int currentButton, int typeOfPress = 0) {
// typeOfPress 1: on push; 2: on release; 3: on long press; 4: on lingering press.
// actions on release, on long press and lingering press include the action press. Action lingering press cancels action release and long press.
if (testHardware) {
bleKeyboard.print(currentButton + 1);
if (typeOfPress == 1) {
bleKeyboard.print(" pressed ");
}
if (typeOfPress == 2) {
bleKeyboard.print(" released ");
}
if (typeOfPress == 3) {
bleKeyboard.print(" long ");
}
if (typeOfPress == 4) {
bleKeyboard.print(" lingering ");
}
bleKeyboard.print(millis());
bleKeyboard.print("Pressed: ");
bleKeyboard.print(lastDebounceTime[currentButton]);
keyComb(KEY_RETURN);
} else {
if (currentButton + 1 == 1) {
if (typeOfPress == 1) {
keyComb(KEY_LEFT_CTRL, KEY_LEFT_ALT, KEY_LEFT_SHIFT, 'M');
}
if (typeOfPress == 3) {
keyComb(KEY_LEFT_CTRL, KEY_LEFT_ALT, KEY_LEFT_SHIFT, 'S');
}
}
if (currentButton + 1 == 2) {
if (typeOfPress == 1) {
keyComb(KEY_LEFT_CTRL, KEY_LEFT_ALT, KEY_LEFT_SHIFT, 'P');
}
}
if (currentButton + 1 == 3) {
if (typeOfPress == 1) {
keyComb(KEY_LEFT_CTRL, KEY_LEFT_ALT, KEY_LEFT_SHIFT, 'M');
}
}
if (currentButton + 1 == 4) {
if (typeOfPress == 2) {
keyComb(KEY_LEFT_CTRL, KEY_LEFT_ALT, KEY_LEFT_SHIFT, 'L');
}
}
if (currentButton + 1 == 5) {
if (typeOfPress == 1) {
keyComb(KEY_LEFT_CTRL, KEY_LEFT_ALT, KEY_LEFT_SHIFT, 'K');
}
}
if (currentButton + 1 == 6) {
if (typeOfPress == 1) {
keyComb(KEY_LEFT_CTRL, KEY_LEFT_ALT, KEY_LEFT_SHIFT, 'N');
}
}
}
}
void setup() {
Serial.begin(115200);
for (int thisPin = pinCount - 1; thisPin >= 0; thisPin--) {
pinMode(buttonPin[thisPin], INPUT);
analogWrite(buttonPin[thisPin], HIGH); // In some versions use INPUT_PULLUP to use the built-in pull up resistor
}
bleKeyboard.begin();
}
void loop() {
for (int thisPin = pinCount - 1; thisPin >= 0; thisPin--) {
buttonState[thisPin] = analogRead(buttonPin[thisPin]);
// HIGH = state 1 <- button not pressed
// LOW = state 0 <- button pressed
// On longer press
if ((startedPressing[thisPin] == 0) || ((millis() - startedPressing[thisPin]) <= 1200)) {
// Debouncing not working properly with current hardware
//if (((buttonState[thisPin] != prevButtonState[thisPin])) && ((millis() - lastDebounceTime[thisPin]) > debounceDelay)) {
if ((buttonState[thisPin] != prevButtonState[thisPin])) {
if (buttonState[thisPin] == 0) {
// Standard press action
startedPressing[thisPin] = millis();
outputAction(thisPin, 1);
} else {
if (!longPressing[thisPin]) {
if ((millis() - startedPressing[thisPin]) < 500) {
// On release (to avoid standard action if is incompatible with Long or Longer action)
outputAction(thisPin, 2);
} else {
// Long action (+standard action already sent)
outputAction(thisPin, 3);
}
}
startedPressing[thisPin] = 0;
longPressing[thisPin] = false;
}
lastDebounceTime[thisPin] = millis();
}
} else {
outputAction(thisPin, 4);
longPressing[thisPin] = true;
startedPressing[thisPin] = 0;
}
prevButtonState[thisPin] = buttonState[thisPin];
}
// The pot
int thisPin = pinCount; // To consider it the last one in the lastDebounceTime array
potState = (int) (analogRead(potPin) / 6);
if (prevPotState == -1) {
prevPotState = potState;
}
if (((potState > prevPotState + potTolerance) || (potState < prevPotState - potTolerance))
&& ((millis() - lastDebounceTime[thisPin]) > potDebounceDelay)
) {
if (potState > prevPotState) {
keyComb(KEY_UP_ARROW);
} else {
keyComb(KEY_DOWN_ARROW);
}
lastDebounceTime[thisPin] = millis();
prevPotState = potState;
}
}
!!!FILLER!!!
hehehuheuheuheuhuehdkl;lbkljdfklbfklvjnbgkljnjbgvnjkvjbkvfnvkljklbjk
From the declaration of your function, you declare the function can return an integer in the code. But you don't return an integer.
For your example,
int sendLine(char const * line) {
bleKeyboard.print(line);
delay(750);
keyComb(KEY_RETURN);
}
You don't return an integer in the function sendLine.
Another function you declared to have the same issue too.
I'm working on a program that creates a Lua 5.1 environment in an SDL window written with a mix of C and C++. I've set up an event system that queues SDL events so that Lua can pop events off the queue. One of the events is sent when a printable character is typed. When the event is detected it pushes the string into a new lua_State, queues it in an std::queue, and once it's pulled the values in the lua_State get copied into the main coroutine state, where they're then returned by coroutine.yield. But when I compare the string with a constant on the Lua side (ex: ev[2] == "q"), the comparison results in false. If I copy the value to a new string and compare that (ex: "" .. ev[2] == "q"), the comparison results in true.
I've tried using multiple ways of pushing the string (since SDL provides a UTF-8 string instead of an ASCII character), including:
lua_pushstring(L, e.text.text)
to insert the entire string
lua_pushlstring(L, e.text.text, 1)
to insert the first character
char tmp[2]; tmp[0] = e.text.text[0]; tmp[1] = 0; lua_pushstring(L, tmp)
to copy the string and insert that
but none of these fixed the issue.
Here's the basic structure in my C++ code:
const char * termGetEvent(lua_State *L) {
SDL_Event e;
if (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT) return "die";
else if (e.type == SDL_KEYDOWN && keymap.find(e.key.keysym.scancode) != keymap.end()) {
lua_pushinteger(L, keymap.at(e.key.keysym.scancode));
lua_pushboolean(L, false);
return "key";
} else if (e.type == SDL_KEYUP && keymap.find(e.key.keysym.scancode) != keymap.end()) {
lua_pushinteger(L, keymap.at(e.key.keysym.scancode));
return "key_up";
} else if (e.type == SDL_TEXTINPUT) { // this is the section producing errors
char tmp[2];
tmp[0] = e.text.text[0];
tmp[1] = 0;
lua_pushstring(L, tmp);
return "char";
} else if (e.type == SDL_MOUSEBUTTONDOWN) {
lua_pushinteger(L, buttonConvert(e.button.button));
lua_pushinteger(L, convertX(e.button.x));
lua_pushinteger(L, convertY(e.button.y));
return "mouse_click";
} else if (e.type == SDL_MOUSEBUTTONUP) {
lua_pushinteger(L, buttonConvert(e.button.button));
lua_pushinteger(L, convertX(e.button.x));
lua_pushinteger(L, convertY(e.button.y));
return "mouse_up";
} else if (e.type == SDL_MOUSEWHEEL) {
int x = 0, y = 0;
term->getMouse(&x, &y);
lua_pushinteger(L, e.button.y);
lua_pushinteger(L, convertX(x));
lua_pushinteger(L, convertY(y));
return "mouse_scroll";
} else if (e.type == SDL_MOUSEMOTION && e.motion.state) {
lua_pushinteger(L, buttonConvert2(e.motion.state));
lua_pushinteger(L, convertX(e.motion.x));
lua_pushinteger(L, convertY(e.motion.y));
return "mouse_drag";
} else if (e.type == SDL_WINDOWEVENT && e.window.event == SDL_WINDOWEVENT_RESIZED) {
term->resize();
}
}
return NULL;
}
std::queue<std::pair<const char *, lua_State*> > eventQueue;
int getNextEvent(lua_State *L, const char * filter) {
std::pair<const char *, lua_State*> ev;
do {
while (eventQueue.size() == 0) {
lua_State *param = luaL_newstate();
if (!lua_checkstack(param, 4)) printf("Could not allocate event\n");
const char * name = termGetEvent(param);
if (name != NULL) {
if (strcmp(name, "die") == 0) running = 0;
eventQueue.push(std::make_pair(name, param));
} else if (param) {
lua_pushnil(param);
lua_close(param);
param = NULL;
}
}
ev = eventQueue.front();
eventQueue.pop();
} while (strlen(filter) > 0 && strcmp(std::get<0>(ev), filter) != 0);
// Copy the next event in
lua_State *param = std::get<1>(ev);
int count = lua_gettop(param);
if (!lua_checkstack(L, count + 1)) printf("Could not allocate\n");
lua_pushstring(L, std::get<0>(ev));
lua_xmove(param, L, count);
//lua_close(param);
return count + 1;
}
lua_State *L;
int main() {
int status, result, i;
double sum;
lua_State *coro;
start:
/*
* All Lua contexts are held in this structure. We work with it almost
* all the time.
*/
L = luaL_newstate();
coro = lua_newthread(L);
luaL_openlibs(coro); /* Load Lua libraries */
termInit(); // initializes SDL
/* Load the file containing the script we are going to run */
status = luaL_loadfile(coro, bios_path);
if (status) {
/* If something went wrong, error message is at the top of */
/* the stack */
fprintf(stderr, "Couldn't load file: %s\n", lua_tostring(L, -1));
exit(1);
}
tid = createThread(&termRenderLoop); // stops when running != 1
/* Ask Lua to run our little script */
status = LUA_YIELD;
int narg = 0;
while (status == LUA_YIELD && running == 1) {
status = lua_resume(coro, narg);
if (status == LUA_YIELD) {
if (lua_isstring(coro, -1)) narg = getNextEvent(coro, lua_tostring(coro, -1));
else narg = getNextEvent(coro, "");
} else if (status != 0) {
running = 0;
joinThread(tid);
//usleep(5000000);
termClose();
printf("%s\n", lua_tostring(coro, -1));
lua_close(L);
exit(1);
}
}
joinThread(tid);
termClose();
lua_close(L); /* Cya, Lua */
if (running == 2) {
//usleep(1000000);
goto start;
}
return 0;
}
Here's the Lua script I'm using to test:
while true do
local ev = {coroutine.yield()}
print(table.unpack(ev)) -- provided by previous scripts
if ev[1] == "char" then
print("\"" .. ev[2] .. "\"") -- prints "q" if 'q' was pressed
assert(ev[2] == "q") -- false, even if 'q' was pressed
assert(string.len(ev[2]) == 1) -- true
assert(#ev[2] == 1) -- true
assert(string.len(string.sub(ev[2], 2, 2)) == 0) -- true
assert(string.sub(ev[2], 1, 1) == ev[2]) -- false
assert("" .. ev[2] == "q") -- true if 'q' was pressed
end
if ev[1] == "char" and string.sub(ev[2], 1, 1) == "q" then break end
end
I expect all of the asserts in the script to result in true (assuming 'q' was pressed), but some of them result in false. I had to adjust the statement with the break in it to use only the first character. Why is the string not being compared correctly?
EDIT: I'm not trying to compare the strings on the C++ side, but on the Lua side. I handle string comparisons properly in the C code (strcmp).
After following Egor Skriptunoff's suggestion to replace luaL_newstate with lua_newthread, as well as replacing the lua_close calls with lua_pop, I was able to fix the problem. This post on the lua-users mailing list says you can't close a new thread:
Graham Wakefield wrote:
Hi,
I'm having some hard to understand behavior; I create new threads using lua_newthread, and lua_resume them periodically from C++. However, I may wish to at some point terminate a thread before it has completed; I tried calling lua_close() on the thread's lua_State,
You can't call lua_close() on a thread; only on the main state.
which ended up causing a segmentation fault. Since I was getting excessive memory use otherwise, I ended up replacing lua_close with lua_pop because the state is pushed onto the main stack. After applying these fixes I no longer got any segfaults and the memory usage stays constant.
I have this code:
void setup() {
Serial.begin(9600);
while (!Serial){}
Serial.println("Connected");
Serial.println("L");
Serial.println("R");
Serial.println("B");
Serial.println("S");
Serial.println("T");
}
void loop() {
evalComms(Serial.readStringUntil("0"));
}
void evalComms(String recv){
if (recv == "L"){
Serial.println("ok L " + String(Serial.parseInt()));
} else if (recv == "R"){
Serial.println("ok R " + String(Serial.parseInt()));
} else if (recv == "B") {
Serial.println("ok B " + String(Serial.parseInt()));
} else if (recv == "S") {
Serial.println("ok S");
} else if (recv == "T"){
Serial.println("ok T");
} else if (recv != ""){
Serial.println("Comm error. Read: " + recv);
}
}
Expected I/O scenario:
IN: L020
OUT: ok L 20
Actual I/O scenario:
IN: L020
OUT: Comm error. Read: L020
What am I doing wrong?
Try:
Serial.readStringUntil('0') since as per docs it accepts a char
Else I'd suggest to change the terminate character to say \n ( ENTER ) ,
then on serial : "L\n20" will give you correct output.
void loop()
{
if(Serial.available() > 0)
{
evalComms( Serial.readStringUntil('\n') );
}
}
edit:
As I commented before, my problem is I can't create a table in C which uses strings as keys. I made a quick test program which demonstrates the problem I'm having:
Here is the C++ part of it:
#include <lua.hpp>
#include <String.h>
BString
LuaTypeToString(lua_State *L, int index, int type)
{
BString out;
switch (type)
{
case LUA_TSTRING:
{
out << "'" << lua_tostring(L, index) << "'";
break;
}
case LUA_TBOOLEAN:
{
out << (lua_toboolean(L, index) ? "true" : "false");
break;
}
case LUA_TNUMBER:
{
out << (float)lua_tonumber(L, index);
break;
}
default:
{
out << lua_typename(L, type);
break;
}
}
return out;
}
void
DumpLuaTable(lua_State *L, int tableIndex)
{
lua_pushnil(L);
printf("\t{ ");
while (lua_next(L, tableIndex) != 0)
{
BString keyString = lua_tostring(L, -2);
BString valueString;
int type = lua_type(L, -1);
if (type == LUA_TTABLE)
DumpLuaTable(L, lua_gettop(L));
else
valueString = LuaTypeToString(L, -1, type);
printf("%s=%s,",
keyString.String(),
valueString.String());
lua_pop(L, 1);
if (lua_isnumber(L, -1))
{
lua_pop(L, 1);
break;
}
}
printf(" }");
}
void
DumpLuaStack(lua_State *L)
{
printf("DumpLuaStack:\n");
int top = lua_gettop(L);
for (int i = 1; i <= top; i++)
{
int type = lua_type(L, i);
if (type == LUA_TTABLE)
DumpLuaTable(L, i);
else
printf("\t%s ", LuaTypeToString(L, i, type).String());
}
printf("\n");
}
static
int
ReturnTable(lua_State *L)
{
lua_newtable(L);
lua_pushnumber(L, 3.14);
lua_pushstring(L, "1");
lua_settable(L, -3);
DumpLuaStack(L);
return 1;
}
int
main(void)
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_pushcfunction(L, ReturnTable);
lua_setglobal(L, "ReturnTable");
int status = luaL_dofile(L, "luatest.lua");
if (status)
printf("Status = %d: %s\n", status, lua_tostring(L, -1));
lua_close(L);
return status;
}
And the Lua part of it:
function DumpTable(table)
print("LuaDumpTable")
local out = "\t"
if #table > 0 then
for i, v in ipairs(table) do
out = out .. i .. "=" .. v .. " "
end
print(out)
else
print("\tEmpty table")
end
end
value = ReturnTable()
if (type(value) == "table") then
DumpTable(value)
else
print(type(value))
end
The code as it is works without problem -- the Lua script prints out what you would expect. Change the line which pushes 3.14 to the stack to, say, lua_pushstring(L, "foo"); and all I get is an empty table on the Lua side. Any ideas what I'm doing wrong here?
You're checking the table incorrectly in Lua:
if #table > 0 then
The #table is just telling you that the first unused integer in the table is 0. When you have a string inserted into the table, it doesn't increment the count since it's not part of a continuous array, and you also can't process it with ipairs. Just switch to using pairs and you should see foo:
function DumpTable(table)
print("LuaDumpTable")
local out = "\t"
for i, v in pairs(table) do
out = out .. i .. "=" .. v .. " "
end
print(out)
end
Older note, left as an fyi:
I doubt this would cause the issue, but for API's being called from Lua, you typically want to pop the input off of the stack. So after the lua_tonumber call:
int32 value = lua_tonumber(L, 1);
lua_pop(L, 1);
rgb_color c = ui_color((color_which)value);