mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 12:42:30 +04:00
InputSettings complete. Added VibroTouchLevel
This commit is contained in:
@@ -67,6 +67,7 @@ Small applications providing configuration for basic firmware and its services.
|
|||||||
- `power_settings_app` - Basic power options
|
- `power_settings_app` - Basic power options
|
||||||
- `storage_settings` - Storage settings app
|
- `storage_settings` - Storage settings app
|
||||||
- `system` - System settings
|
- `system` - System settings
|
||||||
|
- `input_settings_app` - Basic input options
|
||||||
|
|
||||||
|
|
||||||
## system
|
## system
|
||||||
|
|||||||
@@ -7,4 +7,5 @@ App(
|
|||||||
stack_size=1 * 1024,
|
stack_size=1 * 1024,
|
||||||
order=80,
|
order=80,
|
||||||
sdk_headers=["input.h"],
|
sdk_headers=["input.h"],
|
||||||
|
provides=["input_settings"],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
#define INPUT_LONG_PRESS_COUNTS 2
|
#define INPUT_LONG_PRESS_COUNTS 2
|
||||||
#define INPUT_THREAD_FLAG_ISR 0x00000001
|
#define INPUT_THREAD_FLAG_ISR 0x00000001
|
||||||
|
|
||||||
|
#define TAG "Input"
|
||||||
|
|
||||||
/** Input pin state */
|
/** Input pin state */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const InputPin* pin;
|
const InputPin* pin;
|
||||||
@@ -80,28 +82,77 @@ const char* input_get_type_name(InputType type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// static void input_storage_callback(const void* message, void* context) {
|
||||||
|
// furi_assert(context);
|
||||||
|
// InputSettings* settings = context;
|
||||||
|
// const StorageEvent* event = message;
|
||||||
|
// UNUSED (settings);
|
||||||
|
// if(event->type == StorageEventTypeCardMount) {
|
||||||
|
// // furi_hal_vibro_on(true);
|
||||||
|
// // furi_delay_tick (100);
|
||||||
|
// // furi_hal_vibro_on(false);
|
||||||
|
// // furi_delay_tick (100);
|
||||||
|
// // furi_hal_vibro_on(true);
|
||||||
|
// // furi_delay_tick (100);
|
||||||
|
// // furi_hal_vibro_on(false);
|
||||||
|
// // furi_delay_tick (100);
|
||||||
|
// // furi_hal_vibro_on(true);
|
||||||
|
// // furi_delay_tick (100);
|
||||||
|
// // furi_hal_vibro_on(false);
|
||||||
|
// //input_settings_load(settings);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // load inital settings from file for power service
|
||||||
|
// static void input_init_settings(InputSettings* settings) {
|
||||||
|
// Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
|
// furi_pubsub_subscribe(storage_get_pubsub(storage), input_storage_callback, settings);
|
||||||
|
|
||||||
|
// if(storage_sd_status(storage) != FSE_OK) {
|
||||||
|
// FURI_LOG_D(TAG, "SD Card not ready, skipping settings");
|
||||||
|
// //set default value
|
||||||
|
// settings->vibro_touch_level=0;
|
||||||
|
// //furi_record_close(RECORD_STORAGE);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// furi_hal_vibro_on(true);
|
||||||
|
// furi_delay_tick (100);
|
||||||
|
// furi_hal_vibro_on(false);
|
||||||
|
// furi_delay_tick (100);
|
||||||
|
// furi_hal_vibro_on(true);
|
||||||
|
// furi_delay_tick (100);
|
||||||
|
// furi_hal_vibro_on(false);
|
||||||
|
|
||||||
|
// input_settings_load(settings);
|
||||||
|
// furi_record_close(RECORD_STORAGE);
|
||||||
|
// }
|
||||||
|
|
||||||
// allocate memory for input_settings structure
|
// allocate memory for input_settings structure
|
||||||
static InputSettings* input_settings_alloc (void) {
|
static InputSettings* input_settings_alloc (void) {
|
||||||
InputSettings* input_settings = malloc(sizeof(InputSettings));
|
InputSettings* settings = malloc(sizeof(InputSettings));
|
||||||
return input_settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
//free memory from input_settings structure
|
//free memory from input_settings structure
|
||||||
void input_settings_free (InputSettings* input_settings) {
|
void input_settings_free (InputSettings* settings) {
|
||||||
free (input_settings);
|
free (settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t input_srv(void* p) {
|
int32_t input_srv(void* p) {
|
||||||
UNUSED(p);
|
UNUSED(p);
|
||||||
|
|
||||||
//define object input_settings and take memory for him
|
|
||||||
InputSettings* input_settings = input_settings_alloc();
|
|
||||||
|
|
||||||
const FuriThreadId thread_id = furi_thread_get_current_id();
|
const FuriThreadId thread_id = furi_thread_get_current_id();
|
||||||
FuriPubSub* event_pubsub = furi_pubsub_alloc();
|
FuriPubSub* event_pubsub = furi_pubsub_alloc();
|
||||||
uint32_t counter = 1;
|
uint32_t counter = 1;
|
||||||
furi_record_create(RECORD_INPUT_EVENTS, event_pubsub);
|
furi_record_create(RECORD_INPUT_EVENTS, event_pubsub);
|
||||||
|
|
||||||
|
//define object input_settings, take memory load (or init) settings and create record for access to settings structure outside
|
||||||
|
InputSettings* settings = input_settings_alloc();
|
||||||
|
furi_record_create(RECORD_INPUT_SETTINGS, settings);
|
||||||
|
input_settings_load(settings);
|
||||||
|
|
||||||
#ifdef INPUT_DEBUG
|
#ifdef INPUT_DEBUG
|
||||||
furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeOutputPushPull);
|
furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeOutputPushPull);
|
||||||
#endif
|
#endif
|
||||||
@@ -164,9 +215,10 @@ int32_t input_srv(void* p) {
|
|||||||
// Send Press/Release event
|
// Send Press/Release event
|
||||||
event.type = pin_states[i].state ? InputTypePress : InputTypeRelease;
|
event.type = pin_states[i].state ? InputTypePress : InputTypeRelease;
|
||||||
furi_pubsub_publish(event_pubsub, &event);
|
furi_pubsub_publish(event_pubsub, &event);
|
||||||
if (input_settings->vibro_touch_level) {
|
// do vibro if user setup vibro touch level in Settings-Input.
|
||||||
|
if (settings->vibro_touch_level) {
|
||||||
furi_hal_vibro_on(true);
|
furi_hal_vibro_on(true);
|
||||||
furi_delay_tick (30);
|
furi_delay_tick (settings->vibro_touch_level);
|
||||||
furi_hal_vibro_on(false);
|
furi_hal_vibro_on(false);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -185,7 +237,6 @@ int32_t input_srv(void* p) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we come here and ready exit from service (whats going on ??!!) then best practice is free memory
|
|
||||||
input_settings_free(input_settings);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,15 @@
|
|||||||
|
|
||||||
#include <furi_hal_resources.h>
|
#include <furi_hal_resources.h>
|
||||||
#include "input_settings.h"
|
#include "input_settings.h"
|
||||||
|
#include <storage/storage.h>
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define RECORD_INPUT_EVENTS "input_events"
|
#define RECORD_INPUT_EVENTS "input_events"
|
||||||
|
#define RECORD_INPUT_SETTINGS "input_settings"
|
||||||
#define INPUT_SEQUENCE_SOURCE_HARDWARE (0u)
|
#define INPUT_SEQUENCE_SOURCE_HARDWARE (0u)
|
||||||
#define INPUT_SEQUENCE_SOURCE_SOFTWARE (1u)
|
#define INPUT_SEQUENCE_SOURCE_SOFTWARE (1u)
|
||||||
|
|
||||||
@@ -41,13 +44,6 @@ typedef struct {
|
|||||||
InputType type;
|
InputType type;
|
||||||
} InputEvent;
|
} InputEvent;
|
||||||
|
|
||||||
//for next step input structure globalization;
|
|
||||||
//typedef struct Input {
|
|
||||||
//InputSettings* settings;
|
|
||||||
//InputType* type;
|
|
||||||
//InputEvent* event;
|
|
||||||
//} Input;
|
|
||||||
|
|
||||||
/** Get human readable input key name
|
/** Get human readable input key name
|
||||||
* @param key - InputKey
|
* @param key - InputKey
|
||||||
* @return string
|
* @return string
|
||||||
|
|||||||
@@ -21,18 +21,21 @@ void input_settings_load(InputSettings* settings) {
|
|||||||
|
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
|
//a useless cycle do-while, may will be used in future with anoter condition
|
||||||
do {
|
do {
|
||||||
|
// take version from settings file metadata, if cant then break and fill settings with 0 and save to settings file;
|
||||||
uint8_t version;
|
uint8_t version;
|
||||||
if(!saved_struct_get_metadata(INPUT_SETTINGS_PATH, NULL, &version, NULL)) break;
|
if(!saved_struct_get_metadata(INPUT_SETTINGS_PATH, NULL, &version, NULL)) break;
|
||||||
|
|
||||||
if(version == INPUT_SETTINGS_VER) { // if config actual version - load it directly
|
// if config actual version - load it directly
|
||||||
|
if(version == INPUT_SETTINGS_VER) {
|
||||||
success = saved_struct_load(
|
success = saved_struct_load(
|
||||||
INPUT_SETTINGS_PATH,
|
INPUT_SETTINGS_PATH,
|
||||||
settings,
|
settings,
|
||||||
sizeof(InputSettings),
|
sizeof(InputSettings),
|
||||||
INPUT_SETTINGS_MAGIC,
|
INPUT_SETTINGS_MAGIC,
|
||||||
INPUT_SETTINGS_VER);
|
INPUT_SETTINGS_VER);
|
||||||
|
// if config previous version - load it and inicialize new settings
|
||||||
} else if(
|
} else if(
|
||||||
version ==
|
version ==
|
||||||
INPUT_SETTINGS_VER_0) { // if config previous version - load it and manual set new settings to inital value
|
INPUT_SETTINGS_VER_0) { // if config previous version - load it and manual set new settings to inital value
|
||||||
@@ -51,9 +54,10 @@ void input_settings_load(InputSettings* settings) {
|
|||||||
|
|
||||||
free(settings_v0);
|
free(settings_v0);
|
||||||
}
|
}
|
||||||
|
// in case of another config version we exit from useless cycle to next step
|
||||||
} while(false);
|
} while(false);
|
||||||
|
|
||||||
|
// fill settings with 0 and save to settings file;
|
||||||
if(!success) {
|
if(!success) {
|
||||||
FURI_LOG_W(TAG, "Failed to load file, using defaults");
|
FURI_LOG_W(TAG, "Failed to load file, using defaults");
|
||||||
memset(settings, 0, sizeof(InputSettings));
|
memset(settings, 0, sizeof(InputSettings));
|
||||||
@@ -71,6 +75,12 @@ void input_settings_save(const InputSettings* settings) {
|
|||||||
INPUT_SETTINGS_MAGIC,
|
INPUT_SETTINGS_MAGIC,
|
||||||
INPUT_SETTINGS_VER);
|
INPUT_SETTINGS_VER);
|
||||||
|
|
||||||
|
// debug log
|
||||||
|
// FURI_LOG_D(TAG,"SAVE");
|
||||||
|
// char buffer[12] = {};
|
||||||
|
// snprintf(buffer, sizeof(buffer), "%d",settings->vibro_touch_level);
|
||||||
|
// FURI_LOG_D(TAG,buffer);
|
||||||
|
|
||||||
if(!success) {
|
if(!success) {
|
||||||
FURI_LOG_E(TAG, "Failed to save file");
|
FURI_LOG_E(TAG, "Failed to save file");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -615,7 +615,7 @@ static Power* power_alloc(void) {
|
|||||||
free(settings);
|
free(settings);
|
||||||
|
|
||||||
// auto_poweroff
|
// auto_poweroff
|
||||||
//---define subscription to loader events message (info about started apps) and defina callback for this
|
//---define subscription to loader events message (info about started apps) and define callback for this
|
||||||
Loader* loader = furi_record_open(RECORD_LOADER);
|
Loader* loader = furi_record_open(RECORD_LOADER);
|
||||||
furi_pubsub_subscribe(loader_get_pubsub(loader), power_loader_callback, power);
|
furi_pubsub_subscribe(loader_get_pubsub(loader), power_loader_callback, power);
|
||||||
power->input_events_pubsub = furi_record_open(RECORD_INPUT_EVENTS);
|
power->input_events_pubsub = furi_record_open(RECORD_INPUT_EVENTS);
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include "input_settings_app.h"
|
|
||||||
|
|
||||||
#define VIBRO_TOUCH_LEVEL_COUNT 10
|
|
||||||
// vibro touch human readable levels
|
|
||||||
const char* const vibro_touch_level_text[VIBRO_TOUCH_LEVEL_COUNT] = {
|
|
||||||
"OFF",
|
|
||||||
"1",
|
|
||||||
"2",
|
|
||||||
"3",
|
|
||||||
"4",
|
|
||||||
"5",
|
|
||||||
"6",
|
|
||||||
"7",
|
|
||||||
"8",
|
|
||||||
"9",
|
|
||||||
};
|
|
||||||
// vibro touch levels tick valies delay
|
|
||||||
const uint32_t vibro_touch_level_value[VIBRO_TOUCH_LEVEL_COUNT] =
|
|
||||||
{0,13,16,19,21,24,27,30,33,36};
|
|
||||||
|
|
||||||
input_settings_start_vibro_touch_level_changed (){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
InputSettingsApp* input_settings_alloc (void) {
|
|
||||||
InputSettingsApp* app = malloc(sizeof(InputSettingsApp));
|
|
||||||
|
|
||||||
app->gui = furi_record_open (RECORD_GUI);
|
|
||||||
app->view_dispatcher = view_dispatcher_alloc ();
|
|
||||||
|
|
||||||
VariableItem* item;
|
|
||||||
app->var_item_list = variable_item_list_alloc();
|
|
||||||
|
|
||||||
item = variable_item_list_add(
|
|
||||||
variable_item_list,
|
|
||||||
"Vibro touch level",
|
|
||||||
VIBRO_TOUCH_LEVEL_COUNT,
|
|
||||||
input_settings_start_vibro_touch_level_changed,
|
|
||||||
app);
|
|
||||||
|
|
||||||
value_index = value_index_uint32(
|
|
||||||
app->settings.vibro_touch_level, vibro_touch_level_value, VIBRO_TOUCH_LEVEL_COUNT);
|
|
||||||
variable_item_set_current_value_index(item, value_index);
|
|
||||||
variable_item_set_current_value_text(item, vibro_touch_level_text[value_index]);
|
|
||||||
|
|
||||||
|
|
||||||
return app;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Enter point
|
|
||||||
int32_t input_settings_app (void* p) {
|
|
||||||
UNUSED (p);
|
|
||||||
|
|
||||||
//take memory
|
|
||||||
InputSettingsApp* app = input_settings_alloc ();
|
|
||||||
|
|
||||||
//start view_dispatcher
|
|
||||||
view_dispatcher_run(app->view_dispatcher);
|
|
||||||
|
|
||||||
//free memory
|
|
||||||
Input_settings_free (app);
|
|
||||||
|
|
||||||
//exit with 0 code
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
App(
|
App(
|
||||||
appid="input_settings",
|
appid="input_settings",
|
||||||
name="Input",
|
name="Input",
|
||||||
apptype=FlipperAppType,SETTINGS,
|
apptype=FlipperAppType.SETTINGS,
|
||||||
entry_point="input_settings_app",
|
entry_point="input_settings_app",
|
||||||
requires=["gui"],
|
requires=["input"],
|
||||||
stack_size=1 * 1024,
|
stack_size=1 * 1024,
|
||||||
order=100,
|
order=100,
|
||||||
)
|
)
|
||||||
103
applications/settings/input_settings_app/input_settings_app.c
Normal file
103
applications/settings/input_settings_app/input_settings_app.c
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include "input_settings_app.h"
|
||||||
|
|
||||||
|
#define TAG "InputSettingsApp"
|
||||||
|
|
||||||
|
#define VIBRO_TOUCH_LEVEL_COUNT 10
|
||||||
|
// vibro touch human readable levels
|
||||||
|
const char* const vibro_touch_level_text[VIBRO_TOUCH_LEVEL_COUNT] = {
|
||||||
|
"OFF","1","2","3","4","5","6","7","8","9",};
|
||||||
|
// vibro touch levels tick valies delay
|
||||||
|
const uint32_t vibro_touch_level_value[VIBRO_TOUCH_LEVEL_COUNT] =
|
||||||
|
{0,13,16,19,21,24,27,30,33,36};
|
||||||
|
|
||||||
|
static void input_settings_vibro_touch_level_changed (VariableItem* item) {
|
||||||
|
uint8_t index = variable_item_get_current_value_index(item);
|
||||||
|
variable_item_set_current_value_text(item, vibro_touch_level_text[index]);
|
||||||
|
|
||||||
|
//change settings to selected
|
||||||
|
InputSettingsApp* app = variable_item_get_context(item);
|
||||||
|
app->settings->vibro_touch_level = vibro_touch_level_value[index];
|
||||||
|
|
||||||
|
// use RECORD for acces to input service instance and set settings
|
||||||
|
InputSettings* service_settings = furi_record_open (RECORD_INPUT_SETTINGS);
|
||||||
|
service_settings->vibro_touch_level = vibro_touch_level_value[index];
|
||||||
|
furi_record_close (RECORD_INPUT_SETTINGS);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t input_settings_app_exit(void* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
return VIEW_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputSettingsApp* input_settings_app_alloc (void) {
|
||||||
|
InputSettingsApp* app = malloc(sizeof(InputSettingsApp));
|
||||||
|
//app->inputservice = furi_record_open(RECORD_INPUT_EVENTS);
|
||||||
|
|
||||||
|
app->gui = furi_record_open (RECORD_GUI);
|
||||||
|
|
||||||
|
app->settings = malloc(sizeof(InputSettings));
|
||||||
|
input_settings_load (app->settings);
|
||||||
|
|
||||||
|
app->variable_item_list = variable_item_list_alloc();
|
||||||
|
View* view = variable_item_list_get_view(app->variable_item_list);
|
||||||
|
view_set_previous_callback(view, input_settings_app_exit);
|
||||||
|
|
||||||
|
VariableItem* item;
|
||||||
|
uint8_t value_index;
|
||||||
|
|
||||||
|
item = variable_item_list_add(
|
||||||
|
app->variable_item_list,"VibroTouchLevel",VIBRO_TOUCH_LEVEL_COUNT,input_settings_vibro_touch_level_changed,app);
|
||||||
|
|
||||||
|
value_index = value_index_uint32(
|
||||||
|
app->settings->vibro_touch_level, vibro_touch_level_value, VIBRO_TOUCH_LEVEL_COUNT);
|
||||||
|
variable_item_set_current_value_index(item, value_index);
|
||||||
|
variable_item_set_current_value_text(item, vibro_touch_level_text[value_index]);
|
||||||
|
|
||||||
|
// create and setup view and view dispatcher
|
||||||
|
app->view_dispatcher = view_dispatcher_alloc ();
|
||||||
|
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
|
||||||
|
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||||
|
view_dispatcher_add_view(app->view_dispatcher,InputSettingsViewVariableItemList,view);
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, InputSettingsViewVariableItemList);
|
||||||
|
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
void input_settings_app_free (InputSettingsApp* app){
|
||||||
|
furi_assert(app);
|
||||||
|
|
||||||
|
// Variable item list
|
||||||
|
view_dispatcher_remove_view(app->view_dispatcher, InputSettingsViewVariableItemList);
|
||||||
|
variable_item_list_free(app->variable_item_list);
|
||||||
|
|
||||||
|
// View dispatcher
|
||||||
|
view_dispatcher_free(app->view_dispatcher);
|
||||||
|
|
||||||
|
// Records
|
||||||
|
furi_record_close(RECORD_GUI);
|
||||||
|
//furi_record_close(RECORD_INPUT_EVENTS);
|
||||||
|
free (app->settings);
|
||||||
|
free(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enter point
|
||||||
|
int32_t input_settings_app (void* p) {
|
||||||
|
UNUSED (p);
|
||||||
|
InputSettingsApp* app = input_settings_app_alloc ();
|
||||||
|
|
||||||
|
view_dispatcher_run(app->view_dispatcher);
|
||||||
|
|
||||||
|
// // debug code
|
||||||
|
// FURI_LOG_D(TAG,"Vibro Touch level before save");
|
||||||
|
// char buffer[12] = {};
|
||||||
|
// snprintf(buffer, sizeof(buffer), "%d",app->settings->vibro_touch_level);
|
||||||
|
// FURI_LOG_D(TAG,buffer);
|
||||||
|
|
||||||
|
//save current settings;
|
||||||
|
input_settings_save(app->settings);
|
||||||
|
|
||||||
|
input_settings_app_free (app);
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
@@ -6,15 +6,19 @@
|
|||||||
#include <gui/view.h>
|
#include <gui/view.h>
|
||||||
#include <gui/view_dispatcher.h>
|
#include <gui/view_dispatcher.h>
|
||||||
#include <gui/modules/variable_item_list.h>
|
#include <gui/modules/variable_item_list.h>
|
||||||
#include "input/input_settings.h"
|
#include <input/input.h>
|
||||||
|
#include <lib/toolbox/value_index.h>
|
||||||
|
#include <furi_hal_vibro.h>
|
||||||
|
#include <storage/storage.h>
|
||||||
|
|
||||||
// app stucture
|
|
||||||
|
// input_settings_app stucture
|
||||||
typedef struct {
|
typedef struct {
|
||||||
InputSettings* settings;
|
//InputService* inputservice; //link to input_sevice with they setings and events
|
||||||
Input* input;
|
|
||||||
Gui* gui;
|
Gui* gui;
|
||||||
ViewDispatcher* view_dispatcher;
|
ViewDispatcher* view_dispatcher;
|
||||||
VariableItemList* variable_item_list;
|
VariableItemList* variable_item_list;
|
||||||
|
InputSettings* settings;
|
||||||
} InputSettingsApp;
|
} InputSettingsApp;
|
||||||
|
|
||||||
// list of menu views for view dispatcher
|
// list of menu views for view dispatcher
|
||||||
Reference in New Issue
Block a user