nyx: Add joycon fallback support as a virtual mouse

Cursor Movement: Left Stick
Click: A / ZL / ZR
Back: B
This commit is contained in:
CTCaer
2020-04-30 13:16:30 +03:00
parent 7b715f7be9
commit 1483a61f11
4 changed files with 535 additions and 1 deletions

View File

@@ -29,6 +29,7 @@
#include "../config/ini.h"
#include "../gfx/di.h"
#include "../gfx/gfx.h"
#include "../input/joycon.h"
#include "../input/touch.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
@@ -68,6 +69,26 @@ typedef struct _gui_status_bar_ctx
lv_obj_t *battery_more;
} gui_status_bar_ctx;
typedef struct _jc_lv_driver_t
{
lv_indev_t *indev;
bool centering_done;
u16 cx_max;
u16 cx_min;
u16 cy_max;
u16 cy_min;
s16 pos_x;
s16 pos_y;
s16 pos_last_x;
s16 pos_last_y;
lv_obj_t *cursor;
u32 cursor_timeout;
bool cursor_hidden;
u32 console_timeout;
} jc_lv_driver_t;
static jc_lv_driver_t jc_drv_ctx;
static gui_status_bar_ctx status_bar;
static void _nyx_disp_init()
@@ -212,6 +233,126 @@ static bool _fts_touch_read(lv_indev_data_t *data)
return false; // No buffering so no more data read.
}
static bool _jc_virt_mouse_read(lv_indev_data_t *data)
{
// Poll Joy-Con.
jc_gamepad_rpt_t *jc_pad = joycon_poll();
if (!jc_pad)
{
data->state = LV_INDEV_STATE_REL;
return false;
}
// Take a screenshot if Capture button is pressed.
if (jc_pad->cap)
{
_save_fb_to_bmp();
msleep(1000);
}
// Calibrate left stick.
if (!jc_drv_ctx.centering_done)
{
if (jc_pad->conn_l
&& jc_pad->lstick_x > 0x400 && jc_pad->lstick_y > 0x400
&& jc_pad->lstick_x < 0xC00 && jc_pad->lstick_y < 0xC00)
{
jc_drv_ctx.cx_max = jc_pad->lstick_x + 0x72;
jc_drv_ctx.cx_min = jc_pad->lstick_x - 0x72;
jc_drv_ctx.cy_max = jc_pad->lstick_y + 0x72;
jc_drv_ctx.cy_min = jc_pad->lstick_y - 0x72;
jc_drv_ctx.centering_done = true;
jc_drv_ctx.cursor_timeout = 0;
}
else
{
data->state = LV_INDEV_STATE_REL;
return false;
}
}
// Re-calibrate on disconnection.
if (!jc_pad->conn_l)
jc_drv_ctx.centering_done = 0;
// Set button presses.
if (jc_pad->a || jc_pad->zl || jc_pad->zr)
data->state = LV_INDEV_STATE_PR;
else
data->state = LV_INDEV_STATE_REL;
// Calculate new cursor position.
if (jc_pad->lstick_x <= jc_drv_ctx.cx_max && jc_pad->lstick_x >= jc_drv_ctx.cx_min)
jc_drv_ctx.pos_x += 0;
else if (jc_pad->lstick_x > jc_drv_ctx.cx_max)
jc_drv_ctx.pos_x += ((jc_pad->lstick_x - jc_drv_ctx.cx_max) / 30);
else
jc_drv_ctx.pos_x -= ((jc_drv_ctx.cx_min - jc_pad->lstick_x) / 30);
if (jc_pad->lstick_y <= jc_drv_ctx.cy_max && jc_pad->lstick_y >= jc_drv_ctx.cy_min)
jc_drv_ctx.pos_y += 0;
else if (jc_pad->lstick_y > jc_drv_ctx.cy_max)
jc_drv_ctx.pos_y -= ((jc_pad->lstick_y - jc_drv_ctx.cy_max) / 30);
else
jc_drv_ctx.pos_y += ((jc_drv_ctx.cy_min - jc_pad->lstick_y) / 30);
// Ensure value inside screen limits.
if (jc_drv_ctx.pos_x < 0)
jc_drv_ctx.pos_x = 0;
else if (jc_drv_ctx.pos_x > 1279)
jc_drv_ctx.pos_x = 1279;
if (jc_drv_ctx.pos_y < 0)
jc_drv_ctx.pos_y = 0;
else if (jc_drv_ctx.pos_y > 719)
jc_drv_ctx.pos_y = 719;
// Set cursor position.
data->point.x = jc_drv_ctx.pos_x;
data->point.y = jc_drv_ctx.pos_y;
// Auto hide cursor.
if (jc_drv_ctx.pos_x != jc_drv_ctx.pos_last_x || jc_drv_ctx.pos_y != jc_drv_ctx.pos_last_y)
{
jc_drv_ctx.pos_last_x = jc_drv_ctx.pos_x;
jc_drv_ctx.pos_last_y = jc_drv_ctx.pos_y;
jc_drv_ctx.cursor_hidden = false;
jc_drv_ctx.cursor_timeout = get_tmr_ms();
lv_indev_set_cursor(jc_drv_ctx.indev, jc_drv_ctx.cursor);
// Un hide cursor.
lv_obj_set_opa_scale_enable(jc_drv_ctx.cursor, false);
}
else
{
if (!jc_drv_ctx.cursor_hidden)
{
if (((u32)get_tmr_ms() - jc_drv_ctx.cursor_timeout) > 3000)
{
// Remove cursor and hide it.
lv_indev_set_cursor(jc_drv_ctx.indev, NULL);
lv_obj_set_opa_scale_enable(jc_drv_ctx.cursor, true);
lv_obj_set_opa_scale(jc_drv_ctx.cursor, LV_OPA_TRANSP);
jc_drv_ctx.cursor_hidden = true;
}
}
else
data->state = LV_INDEV_STATE_REL; // Ensure that no clicks are allowed.
}
if (jc_pad->b && close_btn)
{
lv_action_t close_btn_action = lv_btn_get_action(close_btn, LV_BTN_ACTION_CLICK);
close_btn_action(close_btn);
close_btn = NULL;
}
return false; // No buffering so no more data read.
}
typedef struct _system_maintenance_tasks_t
{
union
@@ -1709,6 +1850,17 @@ void nyx_load_and_run()
disp_drv.disp_flush = _disp_fb_flush;
lv_disp_drv_register(&disp_drv);
// Initialize Joy-Con.
lv_task_t *task_jc_init_hw = lv_task_create(jc_init_hw, LV_TASK_ONESHOT, LV_TASK_PRIO_LOWEST, NULL);
lv_task_once(task_jc_init_hw);
lv_indev_drv_t indev_drv_jc;
lv_indev_drv_init(&indev_drv_jc);
indev_drv_jc.type = LV_INDEV_TYPE_POINTER;
indev_drv_jc.read = _jc_virt_mouse_read;
memset(&jc_drv_ctx, 0, sizeof(jc_lv_driver_t));
jc_drv_ctx.indev = lv_indev_drv_register(&indev_drv_jc);
close_btn = NULL;
// Initialize touch.
touch_power_on();
lv_indev_drv_t indev_drv_touch;
@@ -1728,6 +1880,11 @@ void nyx_load_and_run()
// Create main menu
_nyx_main_menu(th);
jc_drv_ctx.cursor = lv_img_create(lv_scr_act(), NULL);
lv_img_set_src(jc_drv_ctx.cursor, &touch_cursor);
lv_obj_set_opa_scale(jc_drv_ctx.cursor, LV_OPA_TRANSP);
lv_obj_set_opa_scale_enable(jc_drv_ctx.cursor, true);
// Check if sd card issues.
if (sd_get_mode() == SD_1BIT_HS25)
{