mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-07-13 23:58:11 -07:00
js updates
by Willy-JL , oldip
This commit is contained in:
@@ -26,6 +26,12 @@ if (badusb.isConnected()) {
|
||||
badusb.println("Flipper Name: " + flipper.getName());
|
||||
badusb.println("Battery level: " + to_string(flipper.getBatteryCharge()) + "%");
|
||||
|
||||
// Alt+Numpad method works only on Windows!!!
|
||||
badusb.altPrintln("This was printed with Alt+Numpad method!");
|
||||
|
||||
// There's also badusb.print() and badusb.altPrint()
|
||||
// which don't add the return at the end
|
||||
|
||||
notify.success();
|
||||
} else {
|
||||
print("USB not connected");
|
||||
|
||||
@@ -4,16 +4,20 @@ keyboard.setHeader("Example Text Input");
|
||||
|
||||
// Default text is optional
|
||||
let text = keyboard.text(100, "Default text", true);
|
||||
// Returns undefined when pressing back
|
||||
print("Got text:", text);
|
||||
|
||||
keyboard.setHeader("Example Byte Input");
|
||||
|
||||
// Default data is optional
|
||||
let data = keyboard.byte(6, Uint8Array([1, 2, 3, 4, 5, 6]));
|
||||
data = Uint8Array(data);
|
||||
let result = "0x";
|
||||
for (let i = 0; i < data.byteLength; i++) {
|
||||
if (data[i] < 0x10) result += "0";
|
||||
result += to_hex_string(data[i]);
|
||||
let result = keyboard.byte(6, Uint8Array([1, 2, 3, 4, 5, 6]));
|
||||
// Returns undefined when pressing back
|
||||
if (result !== undefined) {
|
||||
let data = Uint8Array(result);
|
||||
result = "0x";
|
||||
for (let i = 0; i < data.byteLength; i++) {
|
||||
if (data[i] < 0x10) result += "0";
|
||||
result += to_hex_string(data[i]);
|
||||
}
|
||||
}
|
||||
print("Got data:", result);
|
||||
@@ -0,0 +1,19 @@
|
||||
let sampleText = "Hello, World!";
|
||||
|
||||
let lengthOfText = "Length of text: " + to_string(sampleText.length);
|
||||
print(lengthOfText);
|
||||
|
||||
let start = 7;
|
||||
let end = 12;
|
||||
let substringResult = sampleText.slice(start, end);
|
||||
print(substringResult);
|
||||
|
||||
let searchStr = "World";
|
||||
let result2 = to_string(sampleText.indexOf(searchStr));
|
||||
print(result2);
|
||||
|
||||
let upperCaseText = "Text in upper case: " + to_upper_case(sampleText);
|
||||
print(upperCaseText);
|
||||
|
||||
let lowerCaseText = "Text in lower case: " + to_lower_case(sampleText);
|
||||
print(lowerCaseText);
|
||||
@@ -7,5 +7,5 @@ submenu.addItem("Item 3", 2);
|
||||
submenu.setHeader("Select an option:");
|
||||
|
||||
let result = submenu.show();
|
||||
|
||||
// Returns undefined when pressing back
|
||||
print("Result:", result);
|
||||
|
||||
@@ -195,7 +195,7 @@ static void js_require(struct mjs* mjs) {
|
||||
}
|
||||
|
||||
static void js_global_to_string(struct mjs* mjs) {
|
||||
double num = mjs_get_int(mjs, mjs_arg(mjs, 0));
|
||||
double num = mjs_get_double(mjs, mjs_arg(mjs, 0));
|
||||
char tmp_str[] = "-2147483648";
|
||||
itoa(num, tmp_str, 10);
|
||||
mjs_val_t ret = mjs_mk_string(mjs, tmp_str, ~0, true);
|
||||
@@ -210,6 +210,88 @@ static void js_global_to_hex_string(struct mjs* mjs) {
|
||||
mjs_return(mjs, ret);
|
||||
}
|
||||
|
||||
static void js_parse_int(struct mjs* mjs) {
|
||||
mjs_val_t arg = mjs_arg(mjs, 0);
|
||||
if(!mjs_is_string(arg)) {
|
||||
mjs_return(mjs, mjs_mk_number(mjs, 0));
|
||||
return;
|
||||
}
|
||||
size_t str_len = 0;
|
||||
const char* str = mjs_get_string(mjs, &arg, &str_len);
|
||||
if((str_len == 0) || (str == NULL)) {
|
||||
mjs_return(mjs, mjs_mk_number(mjs, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t num = 0;
|
||||
int32_t sign = 1;
|
||||
size_t i = 0;
|
||||
|
||||
if(str[0] == '-') {
|
||||
sign = -1;
|
||||
i = 1;
|
||||
} else if(str[0] == '+') {
|
||||
i = 1;
|
||||
}
|
||||
|
||||
for(; i < str_len; i++) {
|
||||
if(str[i] >= '0' && str[i] <= '9') {
|
||||
num = num * 10 + (str[i] - '0');
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
num *= sign;
|
||||
|
||||
mjs_return(mjs, mjs_mk_number(mjs, num));
|
||||
}
|
||||
|
||||
static void js_to_upper_case(struct mjs* mjs) {
|
||||
mjs_val_t arg0 = mjs_arg(mjs, 0);
|
||||
|
||||
size_t str_len;
|
||||
const char* str = NULL;
|
||||
if(mjs_is_string(arg0)) {
|
||||
str = mjs_get_string(mjs, &arg0, &str_len);
|
||||
}
|
||||
if(!str) {
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
char* upperStr = strdup(str);
|
||||
for(size_t i = 0; i < str_len; i++) {
|
||||
upperStr[i] = toupper(upperStr[i]);
|
||||
}
|
||||
|
||||
mjs_val_t resultStr = mjs_mk_string(mjs, upperStr, ~0, true);
|
||||
free(upperStr);
|
||||
mjs_return(mjs, resultStr);
|
||||
}
|
||||
|
||||
static void js_to_lower_case(struct mjs* mjs) {
|
||||
mjs_val_t arg0 = mjs_arg(mjs, 0);
|
||||
|
||||
size_t str_len;
|
||||
const char* str = NULL;
|
||||
if(mjs_is_string(arg0)) {
|
||||
str = mjs_get_string(mjs, &arg0, &str_len);
|
||||
}
|
||||
if(!str) {
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
|
||||
char* lowerStr = strdup(str);
|
||||
for(size_t i = 0; i < str_len; i++) {
|
||||
lowerStr[i] = tolower(lowerStr[i]);
|
||||
}
|
||||
|
||||
mjs_val_t resultStr = mjs_mk_string(mjs, lowerStr, ~0, true);
|
||||
free(lowerStr);
|
||||
mjs_return(mjs, resultStr);
|
||||
}
|
||||
|
||||
#ifdef JS_DEBUG
|
||||
static void js_dump_write_callback(void* ctx, const char* format, ...) {
|
||||
File* file = ctx;
|
||||
@@ -243,6 +325,9 @@ static int32_t js_thread(void* arg) {
|
||||
mjs_set(mjs, global, "to_hex_string", ~0, MJS_MK_FN(js_global_to_hex_string));
|
||||
mjs_set(mjs, global, "ffi_address", ~0, MJS_MK_FN(js_ffi_address));
|
||||
mjs_set(mjs, global, "require", ~0, MJS_MK_FN(js_require));
|
||||
mjs_set(mjs, global, "parse_int", ~0, MJS_MK_FN(js_parse_int));
|
||||
mjs_set(mjs, global, "to_upper_case", ~0, MJS_MK_FN(js_to_upper_case));
|
||||
mjs_set(mjs, global, "to_lower_case", ~0, MJS_MK_FN(js_to_lower_case));
|
||||
|
||||
mjs_val_t console_obj = mjs_mk_object(mjs);
|
||||
mjs_set(mjs, console_obj, "log", ~0, MJS_MK_FN(js_console_log));
|
||||
|
||||
@@ -52,6 +52,17 @@ static const struct {
|
||||
{"F10", HID_KEYBOARD_F10},
|
||||
{"F11", HID_KEYBOARD_F11},
|
||||
{"F12", HID_KEYBOARD_F12},
|
||||
|
||||
{"NUM0", HID_KEYPAD_0},
|
||||
{"NUM1", HID_KEYPAD_1},
|
||||
{"NUM2", HID_KEYPAD_2},
|
||||
{"NUM3", HID_KEYPAD_3},
|
||||
{"NUM4", HID_KEYPAD_4},
|
||||
{"NUM5", HID_KEYPAD_5},
|
||||
{"NUM6", HID_KEYPAD_6},
|
||||
{"NUM7", HID_KEYPAD_7},
|
||||
{"NUM8", HID_KEYPAD_8},
|
||||
{"NUM9", HID_KEYPAD_9},
|
||||
};
|
||||
|
||||
static void js_badusb_quit_free(JsBadusbInst* badusb) {
|
||||
@@ -130,12 +141,8 @@ static void js_badusb_setup(struct mjs* mjs) {
|
||||
|
||||
badusb->usb_if_prev = furi_hal_usb_get_config();
|
||||
|
||||
if(!furi_hal_usb_set_config(&usb_hid, badusb->hid_cfg)) {
|
||||
mjs_prepend_errorf(mjs, MJS_INTERNAL_ERROR, "USB is locked, close companion app first");
|
||||
badusb->usb_if_prev = NULL;
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
furi_hal_usb_unlock();
|
||||
furi_hal_usb_set_config(&usb_hid, badusb->hid_cfg);
|
||||
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
@@ -318,7 +325,35 @@ static void js_badusb_release(struct mjs* mjs) {
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
|
||||
static void badusb_print(struct mjs* mjs, bool ln) {
|
||||
// Make sure NUMLOCK is enabled for altchar
|
||||
static void ducky_numlock_on() {
|
||||
if((furi_hal_hid_get_led_state() & HID_KB_LED_NUM) == 0) {
|
||||
furi_hal_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK);
|
||||
furi_hal_hid_kb_release(HID_KEYBOARD_LOCK_NUM_LOCK);
|
||||
}
|
||||
}
|
||||
|
||||
// Simulate pressing a character using ALT+Numpad ASCII code
|
||||
static void ducky_altchar(const char* ascii_code) {
|
||||
// Hold the ALT key
|
||||
furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT);
|
||||
|
||||
// Press the corresponding numpad key for each digit of the ASCII code
|
||||
for(size_t i = 0; ascii_code[i] != '\0'; i++) {
|
||||
char digitChar[5] = {'N', 'U', 'M', ascii_code[i], '\0'}; // Construct the numpad key name
|
||||
uint16_t numpad_keycode = get_keycode_by_name(digitChar, strlen(digitChar));
|
||||
if(numpad_keycode == HID_KEYBOARD_NONE) {
|
||||
continue; // Skip if keycode not found
|
||||
}
|
||||
furi_hal_hid_kb_press(numpad_keycode);
|
||||
furi_hal_hid_kb_release(numpad_keycode);
|
||||
}
|
||||
|
||||
// Release the ALT key
|
||||
furi_hal_hid_kb_release(KEY_MOD_LEFT_ALT);
|
||||
}
|
||||
|
||||
static void badusb_print(struct mjs* mjs, bool ln, bool alt) {
|
||||
mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0);
|
||||
JsBadusbInst* badusb = mjs_get_ptr(mjs, obj_inst);
|
||||
furi_assert(badusb);
|
||||
@@ -364,10 +399,20 @@ static void badusb_print(struct mjs* mjs, bool ln) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(alt) {
|
||||
ducky_numlock_on();
|
||||
}
|
||||
for(size_t i = 0; i < text_len; i++) {
|
||||
uint16_t keycode = HID_ASCII_TO_KEY(text_str[i]);
|
||||
furi_hal_hid_kb_press(keycode);
|
||||
furi_hal_hid_kb_release(keycode);
|
||||
if(alt) {
|
||||
// Convert character to ascii numeric value
|
||||
char ascii_str[4];
|
||||
snprintf(ascii_str, sizeof(ascii_str), "%u", (uint8_t)text_str[i]);
|
||||
ducky_altchar(ascii_str);
|
||||
} else {
|
||||
uint16_t keycode = HID_ASCII_TO_KEY(text_str[i]);
|
||||
furi_hal_hid_kb_press(keycode);
|
||||
furi_hal_hid_kb_release(keycode);
|
||||
}
|
||||
if(delay_val > 0) {
|
||||
bool need_exit = js_delay_with_flags(mjs, delay_val);
|
||||
if(need_exit) {
|
||||
@@ -385,11 +430,19 @@ static void badusb_print(struct mjs* mjs, bool ln) {
|
||||
}
|
||||
|
||||
static void js_badusb_print(struct mjs* mjs) {
|
||||
badusb_print(mjs, false);
|
||||
badusb_print(mjs, false, false);
|
||||
}
|
||||
|
||||
static void js_badusb_println(struct mjs* mjs) {
|
||||
badusb_print(mjs, true);
|
||||
badusb_print(mjs, true, false);
|
||||
}
|
||||
|
||||
static void js_badusb_alt_print(struct mjs* mjs) {
|
||||
badusb_print(mjs, false, true);
|
||||
}
|
||||
|
||||
static void js_badusb_alt_println(struct mjs* mjs) {
|
||||
badusb_print(mjs, true, true);
|
||||
}
|
||||
|
||||
static void* js_badusb_create(struct mjs* mjs, mjs_val_t* object) {
|
||||
@@ -404,6 +457,8 @@ static void* js_badusb_create(struct mjs* mjs, mjs_val_t* object) {
|
||||
mjs_set(mjs, badusb_obj, "release", ~0, MJS_MK_FN(js_badusb_release));
|
||||
mjs_set(mjs, badusb_obj, "print", ~0, MJS_MK_FN(js_badusb_print));
|
||||
mjs_set(mjs, badusb_obj, "println", ~0, MJS_MK_FN(js_badusb_println));
|
||||
mjs_set(mjs, badusb_obj, "altPrint", ~0, MJS_MK_FN(js_badusb_alt_print));
|
||||
mjs_set(mjs, badusb_obj, "altPrintln", ~0, MJS_MK_FN(js_badusb_alt_println));
|
||||
*object = badusb_obj;
|
||||
return badusb;
|
||||
}
|
||||
|
||||
@@ -43,16 +43,6 @@ static bool check_arg_count(struct mjs* mjs, size_t count) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool get_int_arg(struct mjs* mjs, size_t index, uint8_t* value, bool error) {
|
||||
mjs_val_t int_obj = mjs_arg(mjs, index);
|
||||
if(!mjs_is_number(int_obj)) {
|
||||
if(error) ret_bad_args(mjs, "Argument must be a number");
|
||||
return false;
|
||||
}
|
||||
*value = mjs_get_int(mjs, int_obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void js_blebeacon_is_active(struct mjs* mjs) {
|
||||
JsBlebeaconInst* blebeacon = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 0)) return;
|
||||
@@ -83,15 +73,24 @@ static void js_blebeacon_set_config(struct mjs* mjs) {
|
||||
}
|
||||
|
||||
uint8_t power = GapAdvPowerLevel_0dBm;
|
||||
get_int_arg(mjs, 1, &power, false);
|
||||
mjs_val_t power_arg = mjs_arg(mjs, 1);
|
||||
if(mjs_is_number(power_arg)) {
|
||||
power = mjs_get_int32(mjs, power_arg);
|
||||
}
|
||||
power = CLAMP(power, GapAdvPowerLevel_6dBm, GapAdvPowerLevel_Neg40dBm);
|
||||
|
||||
uint8_t intv_min = 50;
|
||||
get_int_arg(mjs, 2, &intv_min, false);
|
||||
mjs_val_t intv_min_arg = mjs_arg(mjs, 2);
|
||||
if(mjs_is_number(intv_min_arg)) {
|
||||
intv_min = mjs_get_int32(mjs, intv_min_arg);
|
||||
}
|
||||
intv_min = MAX(intv_min, 20);
|
||||
|
||||
uint8_t intv_max = 150;
|
||||
get_int_arg(mjs, 3, &intv_max, false);
|
||||
mjs_val_t intv_max_arg = mjs_arg(mjs, 3);
|
||||
if(mjs_is_number(intv_max_arg)) {
|
||||
intv_max = mjs_get_int32(mjs, intv_max_arg);
|
||||
}
|
||||
intv_max = MAX(intv_max, intv_min);
|
||||
|
||||
GapExtraBeaconConfig config = {
|
||||
|
||||
@@ -6,48 +6,18 @@
|
||||
#define membersof(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
typedef struct {
|
||||
char* data;
|
||||
TextInput* text_input;
|
||||
ByteInput* byte_input;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
uint8_t* byteinput;
|
||||
char* header;
|
||||
bool accepted;
|
||||
} JsKeyboardInst;
|
||||
|
||||
typedef enum {
|
||||
JsKeyboardViewTextInput,
|
||||
JsKeyboardViewByteInput,
|
||||
} JsKeyboardView;
|
||||
|
||||
static void ret_bad_args(struct mjs* mjs, const char* error) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "%s", error);
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
|
||||
static bool get_str_arg(struct mjs* mjs, size_t index, const char** value, bool error) {
|
||||
mjs_val_t str_obj = mjs_arg(mjs, index);
|
||||
if(!mjs_is_string(str_obj)) {
|
||||
if(error) ret_bad_args(mjs, "Argument must be a string");
|
||||
return false;
|
||||
}
|
||||
size_t str_len = 0;
|
||||
*value = mjs_get_string(mjs, &str_obj, &str_len);
|
||||
if((str_len == 0) || (*value == NULL)) {
|
||||
if(error) ret_bad_args(mjs, "Bad string argument");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool get_int_arg(struct mjs* mjs, size_t index, size_t* value, bool error) {
|
||||
mjs_val_t int_obj = mjs_arg(mjs, index);
|
||||
if(!mjs_is_number(int_obj)) {
|
||||
if(error) ret_bad_args(mjs, "Argument must be a number");
|
||||
return false;
|
||||
}
|
||||
*value = mjs_get_int(mjs, int_obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JsKeyboardInst* get_this_ctx(struct mjs* mjs) {
|
||||
mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0);
|
||||
JsKeyboardInst* storage = mjs_get_ptr(mjs, obj_inst);
|
||||
@@ -55,24 +25,33 @@ static JsKeyboardInst* get_this_ctx(struct mjs* mjs) {
|
||||
return storage;
|
||||
}
|
||||
|
||||
void text_input_callback(void* context) {
|
||||
static void keyboard_callback(void* context) {
|
||||
JsKeyboardInst* keyboard = (JsKeyboardInst*)context;
|
||||
keyboard->accepted = true;
|
||||
view_dispatcher_stop(keyboard->view_dispatcher);
|
||||
}
|
||||
|
||||
void byte_input_callback(void* context) {
|
||||
static bool keyboard_exit(void* context) {
|
||||
JsKeyboardInst* keyboard = (JsKeyboardInst*)context;
|
||||
keyboard->accepted = false;
|
||||
view_dispatcher_stop(keyboard->view_dispatcher);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void js_keyboard_set_header(struct mjs* mjs) {
|
||||
JsKeyboardInst* keyboard = get_this_ctx(mjs);
|
||||
|
||||
const char* header;
|
||||
if(!get_str_arg(mjs, 0, &header, true)) return;
|
||||
mjs_val_t header_arg = mjs_arg(mjs, 0);
|
||||
const char* header = mjs_get_string(mjs, &header_arg, NULL);
|
||||
if(!header) {
|
||||
ret_bad_args(mjs, "Header must be a string");
|
||||
return;
|
||||
}
|
||||
|
||||
text_input_set_header_text(keyboard->text_input, header);
|
||||
byte_input_set_header_text(keyboard->byte_input, header);
|
||||
if(keyboard->header) {
|
||||
free(keyboard->header);
|
||||
}
|
||||
keyboard->header = strdup(header);
|
||||
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
@@ -80,40 +59,70 @@ static void js_keyboard_set_header(struct mjs* mjs) {
|
||||
static void js_keyboard_text(struct mjs* mjs) {
|
||||
JsKeyboardInst* keyboard = get_this_ctx(mjs);
|
||||
|
||||
size_t input_length;
|
||||
if(!get_int_arg(mjs, 0, &input_length, true)) return;
|
||||
mjs_val_t input_length_arg = mjs_arg(mjs, 0);
|
||||
if(!mjs_is_number(input_length_arg)) {
|
||||
ret_bad_args(mjs, "Input length must be a number");
|
||||
return;
|
||||
}
|
||||
int32_t input_length = mjs_get_int32(mjs, input_length_arg);
|
||||
char* buffer = malloc(input_length);
|
||||
|
||||
const char* default_text = "";
|
||||
mjs_val_t default_text_arg = mjs_arg(mjs, 1);
|
||||
const char* default_text = mjs_get_string(mjs, &default_text_arg, NULL);
|
||||
bool clear_default = false;
|
||||
if(get_str_arg(mjs, 1, &default_text, false)) {
|
||||
if(default_text) {
|
||||
strlcpy(buffer, default_text, input_length);
|
||||
mjs_val_t bool_obj = mjs_arg(mjs, 2);
|
||||
clear_default = mjs_get_bool(mjs, bool_obj);
|
||||
}
|
||||
|
||||
view_dispatcher_attach_to_gui(
|
||||
keyboard->view_dispatcher, furi_record_open(RECORD_GUI), ViewDispatcherTypeFullscreen);
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
if(keyboard->header) {
|
||||
text_input_set_header_text(keyboard->text_input, keyboard->header);
|
||||
}
|
||||
text_input_set_result_callback(
|
||||
keyboard->text_input, text_input_callback, keyboard, buffer, input_length, clear_default);
|
||||
keyboard->text_input, keyboard_callback, keyboard, buffer, input_length, clear_default);
|
||||
|
||||
view_dispatcher_switch_to_view(keyboard->view_dispatcher, JsKeyboardViewTextInput);
|
||||
text_input_set_minimum_length(keyboard->text_input, 0);
|
||||
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
keyboard->view_dispatcher = view_dispatcher_alloc();
|
||||
view_dispatcher_enable_queue(keyboard->view_dispatcher);
|
||||
view_dispatcher_add_view(
|
||||
keyboard->view_dispatcher, 0, text_input_get_view(keyboard->text_input));
|
||||
view_dispatcher_set_event_callback_context(keyboard->view_dispatcher, keyboard);
|
||||
view_dispatcher_set_navigation_event_callback(keyboard->view_dispatcher, keyboard_exit);
|
||||
view_dispatcher_attach_to_gui(keyboard->view_dispatcher, gui, ViewDispatcherTypeFullscreen);
|
||||
view_dispatcher_switch_to_view(keyboard->view_dispatcher, 0);
|
||||
|
||||
view_dispatcher_run(keyboard->view_dispatcher);
|
||||
|
||||
text_input_reset(keyboard->text_input);
|
||||
view_dispatcher_remove_view(keyboard->view_dispatcher, 0);
|
||||
view_dispatcher_free(keyboard->view_dispatcher);
|
||||
keyboard->view_dispatcher = NULL;
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
mjs_return(mjs, mjs_mk_string(mjs, buffer, ~0, true));
|
||||
text_input_reset(keyboard->text_input);
|
||||
if(keyboard->header) {
|
||||
free(keyboard->header);
|
||||
keyboard->header = NULL;
|
||||
}
|
||||
if(keyboard->accepted) {
|
||||
mjs_return(mjs, mjs_mk_string(mjs, buffer, ~0, true));
|
||||
} else {
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
static void js_keyboard_byte(struct mjs* mjs) {
|
||||
JsKeyboardInst* keyboard = get_this_ctx(mjs);
|
||||
|
||||
size_t input_length;
|
||||
if(!get_int_arg(mjs, 0, &input_length, true)) return;
|
||||
mjs_val_t input_length_arg = mjs_arg(mjs, 0);
|
||||
if(!mjs_is_number(input_length_arg)) {
|
||||
ret_bad_args(mjs, "Input length must be a number");
|
||||
return;
|
||||
}
|
||||
int32_t input_length = mjs_get_int32(mjs, input_length_arg);
|
||||
uint8_t* buffer = malloc(input_length);
|
||||
|
||||
mjs_val_t default_data_arg = mjs_arg(mjs, 1);
|
||||
@@ -126,21 +135,40 @@ static void js_keyboard_byte(struct mjs* mjs) {
|
||||
memcpy(buffer, (uint8_t*)default_data, MIN((size_t)input_length, default_data_len));
|
||||
}
|
||||
|
||||
view_dispatcher_attach_to_gui(
|
||||
keyboard->view_dispatcher, furi_record_open(RECORD_GUI), ViewDispatcherTypeFullscreen);
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
if(keyboard->header) {
|
||||
byte_input_set_header_text(keyboard->byte_input, keyboard->header);
|
||||
}
|
||||
byte_input_set_result_callback(
|
||||
keyboard->byte_input, byte_input_callback, NULL, keyboard, buffer, input_length);
|
||||
keyboard->byte_input, keyboard_callback, NULL, keyboard, buffer, input_length);
|
||||
|
||||
view_dispatcher_switch_to_view(keyboard->view_dispatcher, JsKeyboardViewByteInput);
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
keyboard->view_dispatcher = view_dispatcher_alloc();
|
||||
view_dispatcher_enable_queue(keyboard->view_dispatcher);
|
||||
view_dispatcher_add_view(
|
||||
keyboard->view_dispatcher, 0, byte_input_get_view(keyboard->byte_input));
|
||||
view_dispatcher_set_event_callback_context(keyboard->view_dispatcher, keyboard);
|
||||
view_dispatcher_set_navigation_event_callback(keyboard->view_dispatcher, keyboard_exit);
|
||||
view_dispatcher_attach_to_gui(keyboard->view_dispatcher, gui, ViewDispatcherTypeFullscreen);
|
||||
view_dispatcher_switch_to_view(keyboard->view_dispatcher, 0);
|
||||
|
||||
view_dispatcher_run(keyboard->view_dispatcher);
|
||||
|
||||
view_dispatcher_remove_view(keyboard->view_dispatcher, 0);
|
||||
view_dispatcher_free(keyboard->view_dispatcher);
|
||||
keyboard->view_dispatcher = NULL;
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
if(keyboard->header) {
|
||||
free(keyboard->header);
|
||||
keyboard->header = NULL;
|
||||
}
|
||||
byte_input_set_result_callback(keyboard->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||
byte_input_set_header_text(keyboard->byte_input, "");
|
||||
|
||||
mjs_return(mjs, mjs_mk_array_buf(mjs, (char*)buffer, input_length));
|
||||
if(keyboard->accepted) {
|
||||
mjs_return(mjs, mjs_mk_array_buf(mjs, (char*)buffer, input_length));
|
||||
} else {
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
@@ -153,28 +181,14 @@ static void* js_keyboard_create(struct mjs* mjs, mjs_val_t* object) {
|
||||
mjs_set(mjs, keyboard_obj, "byte", ~0, MJS_MK_FN(js_keyboard_byte));
|
||||
keyboard->byte_input = byte_input_alloc();
|
||||
keyboard->text_input = text_input_alloc();
|
||||
keyboard->view_dispatcher = view_dispatcher_alloc();
|
||||
view_dispatcher_enable_queue(keyboard->view_dispatcher);
|
||||
view_dispatcher_add_view(
|
||||
keyboard->view_dispatcher,
|
||||
JsKeyboardViewTextInput,
|
||||
text_input_get_view(keyboard->text_input));
|
||||
view_dispatcher_add_view(
|
||||
keyboard->view_dispatcher,
|
||||
JsKeyboardViewByteInput,
|
||||
byte_input_get_view(keyboard->byte_input));
|
||||
*object = keyboard_obj;
|
||||
return keyboard;
|
||||
}
|
||||
|
||||
static void js_keyboard_destroy(void* inst) {
|
||||
JsKeyboardInst* keyboard = inst;
|
||||
view_dispatcher_remove_view(keyboard->view_dispatcher, JsKeyboardViewByteInput);
|
||||
byte_input_free(keyboard->byte_input);
|
||||
view_dispatcher_remove_view(keyboard->view_dispatcher, JsKeyboardViewTextInput);
|
||||
text_input_free(keyboard->text_input);
|
||||
view_dispatcher_free(keyboard->view_dispatcher);
|
||||
free(keyboard->data);
|
||||
free(keyboard);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,17 +41,6 @@ static FuriHalSubGhzPreset js_subghz_get_preset_name(const char* preset_name) {
|
||||
return preset;
|
||||
}
|
||||
|
||||
static int32_t get_int_arg(struct mjs* mjs, size_t index, int32_t* value) {
|
||||
mjs_val_t int_obj = mjs_arg(mjs, index);
|
||||
if(!mjs_is_number(int_obj)) {
|
||||
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Argument must be a number");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return false;
|
||||
}
|
||||
*value = mjs_get_int(mjs, int_obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void js_subghz_set_rx(struct mjs* mjs) {
|
||||
mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0);
|
||||
JsSubghzInst* js_subghz = mjs_get_ptr(mjs, obj_inst);
|
||||
@@ -137,8 +126,13 @@ static void js_subghz_set_frequency(struct mjs* mjs) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t frequency;
|
||||
if(!get_int_arg(mjs, 0, &frequency)) return;
|
||||
mjs_val_t frequency_arg = mjs_arg(mjs, 0);
|
||||
if(!mjs_is_number(frequency_arg)) {
|
||||
mjs_prepend_errorf(mjs, MJS_INTERNAL_ERROR, "Frequency must be a number");
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
return;
|
||||
}
|
||||
int32_t frequency = mjs_get_int32(mjs, frequency_arg);
|
||||
|
||||
if(!subghz_devices_is_frequency_valid(js_subghz->radio_device, frequency)) {
|
||||
mjs_prepend_errorf(mjs, MJS_INTERNAL_ERROR, "Invalid frequency");
|
||||
|
||||
@@ -7,12 +7,9 @@ typedef struct {
|
||||
Submenu* submenu;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
uint32_t result;
|
||||
bool accepted;
|
||||
} JsSubmenuInst;
|
||||
|
||||
typedef enum {
|
||||
JsSubmenuViewSubmenu,
|
||||
} JsSubmenuView;
|
||||
|
||||
static JsSubmenuInst* get_this_ctx(struct mjs* mjs) {
|
||||
mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0);
|
||||
JsSubmenuInst* storage = mjs_get_ptr(mjs, obj_inst);
|
||||
@@ -34,47 +31,38 @@ static bool check_arg_count(struct mjs* mjs, size_t count) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool get_str_arg(struct mjs* mjs, size_t index, const char** value) {
|
||||
mjs_val_t str_obj = mjs_arg(mjs, index);
|
||||
if(!mjs_is_string(str_obj)) {
|
||||
ret_bad_args(mjs, "Argument must be a string");
|
||||
return false;
|
||||
}
|
||||
size_t str_len = 0;
|
||||
*value = mjs_get_string(mjs, &str_obj, &str_len);
|
||||
if((str_len == 0) || (*value == NULL)) {
|
||||
ret_bad_args(mjs, "Bad string argument");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int32_t get_int_arg(struct mjs* mjs, size_t index, int32_t* value) {
|
||||
mjs_val_t int_obj = mjs_arg(mjs, index);
|
||||
if(!mjs_is_number(int_obj)) {
|
||||
ret_bad_args(mjs, "Argument must be a number");
|
||||
return false;
|
||||
}
|
||||
*value = mjs_get_int32(mjs, int_obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void submenu_callback(void* context, uint32_t id) {
|
||||
UNUSED(id);
|
||||
JsSubmenuInst* submenu = context;
|
||||
submenu->result = id;
|
||||
submenu->accepted = true;
|
||||
view_dispatcher_stop(submenu->view_dispatcher);
|
||||
}
|
||||
|
||||
static bool submenu_exit(void* context) {
|
||||
JsSubmenuInst* submenu = context;
|
||||
submenu->result = 0;
|
||||
submenu->accepted = false;
|
||||
view_dispatcher_stop(submenu->view_dispatcher);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void js_submenu_add_item(struct mjs* mjs) {
|
||||
JsSubmenuInst* submenu = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 2)) return;
|
||||
|
||||
const char* label;
|
||||
if(!get_str_arg(mjs, 0, &label)) return;
|
||||
mjs_val_t label_arg = mjs_arg(mjs, 0);
|
||||
const char* label = mjs_get_string(mjs, &label_arg, NULL);
|
||||
if(!label) {
|
||||
ret_bad_args(mjs, "Label must be a string");
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t id;
|
||||
if(!get_int_arg(mjs, 1, &id)) return;
|
||||
mjs_val_t id_arg = mjs_arg(mjs, 1);
|
||||
if(!mjs_is_number(id_arg)) {
|
||||
ret_bad_args(mjs, "Id must be a number");
|
||||
return;
|
||||
}
|
||||
int32_t id = mjs_get_int32(mjs, id_arg);
|
||||
|
||||
submenu_add_item(submenu->submenu, label, id, submenu_callback, submenu);
|
||||
|
||||
@@ -85,8 +73,12 @@ static void js_submenu_set_header(struct mjs* mjs) {
|
||||
JsSubmenuInst* submenu = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 1)) return;
|
||||
|
||||
const char* header;
|
||||
if(!get_str_arg(mjs, 0, &header)) return;
|
||||
mjs_val_t header_arg = mjs_arg(mjs, 0);
|
||||
const char* header = mjs_get_string(mjs, &header_arg, NULL);
|
||||
if(!header) {
|
||||
ret_bad_args(mjs, "Header must be a string");
|
||||
return;
|
||||
}
|
||||
|
||||
submenu_set_header(submenu->submenu, header);
|
||||
|
||||
@@ -96,19 +88,29 @@ static void js_submenu_set_header(struct mjs* mjs) {
|
||||
static void js_submenu_show(struct mjs* mjs) {
|
||||
JsSubmenuInst* submenu = get_this_ctx(mjs);
|
||||
if(!check_arg_count(mjs, 0)) return;
|
||||
submenu->result = 0;
|
||||
|
||||
view_dispatcher_attach_to_gui(
|
||||
submenu->view_dispatcher, furi_record_open(RECORD_GUI), ViewDispatcherTypeFullscreen);
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
view_dispatcher_switch_to_view(submenu->view_dispatcher, JsSubmenuViewSubmenu);
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
submenu->view_dispatcher = view_dispatcher_alloc();
|
||||
view_dispatcher_enable_queue(submenu->view_dispatcher);
|
||||
view_dispatcher_add_view(submenu->view_dispatcher, 0, submenu_get_view(submenu->submenu));
|
||||
view_dispatcher_set_event_callback_context(submenu->view_dispatcher, submenu);
|
||||
view_dispatcher_set_navigation_event_callback(submenu->view_dispatcher, submenu_exit);
|
||||
view_dispatcher_attach_to_gui(submenu->view_dispatcher, gui, ViewDispatcherTypeFullscreen);
|
||||
view_dispatcher_switch_to_view(submenu->view_dispatcher, 0);
|
||||
|
||||
view_dispatcher_run(submenu->view_dispatcher);
|
||||
|
||||
submenu_reset(submenu->submenu);
|
||||
view_dispatcher_remove_view(submenu->view_dispatcher, 0);
|
||||
view_dispatcher_free(submenu->view_dispatcher);
|
||||
submenu->view_dispatcher = NULL;
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
mjs_return(mjs, mjs_mk_number(mjs, submenu->result));
|
||||
submenu_reset(submenu->submenu);
|
||||
if(submenu->accepted) {
|
||||
mjs_return(mjs, mjs_mk_number(mjs, submenu->result));
|
||||
} else {
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
}
|
||||
|
||||
static void* js_submenu_create(struct mjs* mjs, mjs_val_t* object) {
|
||||
@@ -119,19 +121,13 @@ static void* js_submenu_create(struct mjs* mjs, mjs_val_t* object) {
|
||||
mjs_set(mjs, submenu_obj, "setHeader", ~0, MJS_MK_FN(js_submenu_set_header));
|
||||
mjs_set(mjs, submenu_obj, "show", ~0, MJS_MK_FN(js_submenu_show));
|
||||
submenu->submenu = submenu_alloc();
|
||||
submenu->view_dispatcher = view_dispatcher_alloc();
|
||||
view_dispatcher_enable_queue(submenu->view_dispatcher);
|
||||
view_dispatcher_add_view(
|
||||
submenu->view_dispatcher, JsSubmenuViewSubmenu, submenu_get_view(submenu->submenu));
|
||||
*object = submenu_obj;
|
||||
return submenu;
|
||||
}
|
||||
|
||||
static void js_submenu_destroy(void* inst) {
|
||||
JsSubmenuInst* submenu = inst;
|
||||
view_dispatcher_remove_view(submenu->view_dispatcher, JsSubmenuViewSubmenu);
|
||||
submenu_free(submenu->submenu);
|
||||
view_dispatcher_free(submenu->view_dispatcher);
|
||||
free(submenu);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user