mirror of
https://github.com/SSimco/Cemu.git
synced 2024-11-26 23:00:29 +00:00
Merge branch 'main' into android
Some checks are pending
Android build / build (push) Waiting to run
Some checks are pending
Android build / build (push) Waiting to run
This commit is contained in:
commit
f9c4b3aed7
@ -394,7 +394,7 @@ void cemu_initForGame()
|
|||||||
// replace any known function signatures with our HLE implementations and patch bugs in the games
|
// replace any known function signatures with our HLE implementations and patch bugs in the games
|
||||||
GamePatch_scan();
|
GamePatch_scan();
|
||||||
}
|
}
|
||||||
LatteGPUState.alwaysDisplayDRC = ActiveSettings::DisplayDRCEnabled();
|
LatteGPUState.isDRCPrimary = ActiveSettings::DisplayDRCEnabled();
|
||||||
InfoLog_PrintActiveSettings();
|
InfoLog_PrintActiveSettings();
|
||||||
Latte_Start();
|
Latte_Start();
|
||||||
// check for debugger entrypoint bp
|
// check for debugger entrypoint bp
|
||||||
|
@ -52,7 +52,7 @@ struct LatteGPUState_t
|
|||||||
uint32 gx2InitCalled; // incremented every time GX2Init() is called
|
uint32 gx2InitCalled; // incremented every time GX2Init() is called
|
||||||
// OpenGL control
|
// OpenGL control
|
||||||
uint32 glVendor; // GLVENDOR_*
|
uint32 glVendor; // GLVENDOR_*
|
||||||
bool alwaysDisplayDRC = false;
|
bool isDRCPrimary = false;
|
||||||
// temporary (replace with proper solution later)
|
// temporary (replace with proper solution later)
|
||||||
bool tvBufferUsesSRGB;
|
bool tvBufferUsesSRGB;
|
||||||
bool drcBufferUsesSRGB;
|
bool drcBufferUsesSRGB;
|
||||||
|
@ -991,8 +991,6 @@ void LatteRenderTarget_copyToBackbuffer(LatteTextureView* textureView, bool isPa
|
|||||||
g_renderer->ImguiEnd();
|
g_renderer->ImguiEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ctrlTabHotkeyPressed = false;
|
|
||||||
|
|
||||||
void LatteRenderTarget_itHLECopyColorBufferToScanBuffer(MPTR colorBufferPtr, uint32 colorBufferWidth, uint32 colorBufferHeight, uint32 colorBufferSliceIndex, uint32 colorBufferFormat, uint32 colorBufferPitch, Latte::E_HWTILEMODE colorBufferTilemode, uint32 colorBufferSwizzle, uint32 renderTarget)
|
void LatteRenderTarget_itHLECopyColorBufferToScanBuffer(MPTR colorBufferPtr, uint32 colorBufferWidth, uint32 colorBufferHeight, uint32 colorBufferSliceIndex, uint32 colorBufferFormat, uint32 colorBufferPitch, Latte::E_HWTILEMODE colorBufferTilemode, uint32 colorBufferSwizzle, uint32 renderTarget)
|
||||||
{
|
{
|
||||||
cemu_assert_debug(colorBufferSliceIndex == 0); // todo - support for non-zero slice
|
cemu_assert_debug(colorBufferSliceIndex == 0); // todo - support for non-zero slice
|
||||||
@ -1002,38 +1000,31 @@ void LatteRenderTarget_itHLECopyColorBufferToScanBuffer(MPTR colorBufferPtr, uin
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto getVPADScreenActive = [](size_t n) -> std::pair<bool, bool> {
|
||||||
|
auto controller = InputManager::instance().get_vpad_controller(n);
|
||||||
|
if (!controller)
|
||||||
|
return {false,false};
|
||||||
|
auto pressed = controller->is_screen_active();
|
||||||
|
auto toggle = controller->is_screen_active_toggle();
|
||||||
|
return {pressed && !toggle, pressed && toggle};
|
||||||
|
};
|
||||||
|
|
||||||
const bool tabPressed = GuiSystem::isKeyDown(GuiSystem::PlatformKeyCodes::TAB);
|
const bool tabPressed = GuiSystem::isKeyDown(GuiSystem::PlatformKeyCodes::TAB);
|
||||||
const bool ctrlPressed = GuiSystem::isKeyDown(GuiSystem::PlatformKeyCodes::LCONTROL);
|
const bool ctrlPressed = GuiSystem::isKeyDown(GuiSystem::PlatformKeyCodes::LCONTROL);
|
||||||
|
const auto [vpad0Active, vpad0Toggle] = getVPADScreenActive(0);
|
||||||
|
const auto [vpad1Active, vpad1Toggle] = getVPADScreenActive(1);
|
||||||
|
|
||||||
bool showDRC = swkbd::hasKeyboardInputHook() == false && tabPressed;
|
const bool altScreenRequested = (!ctrlPressed && tabPressed) || vpad0Active || vpad1Active;
|
||||||
bool& alwaysDisplayDRC = LatteGPUState.alwaysDisplayDRC;
|
const bool togglePressed = (ctrlPressed && tabPressed) || vpad0Toggle || vpad1Toggle;
|
||||||
|
static bool togglePressedLast = false;
|
||||||
|
|
||||||
if (ctrlPressed && tabPressed)
|
bool& isDRCPrimary = LatteGPUState.isDRCPrimary;
|
||||||
{
|
|
||||||
if (ctrlTabHotkeyPressed == false)
|
|
||||||
{
|
|
||||||
alwaysDisplayDRC = !alwaysDisplayDRC;
|
|
||||||
ctrlTabHotkeyPressed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ctrlTabHotkeyPressed = false;
|
|
||||||
|
|
||||||
if (alwaysDisplayDRC)
|
if(togglePressed && !togglePressedLast)
|
||||||
showDRC = !tabPressed;
|
isDRCPrimary = !isDRCPrimary;
|
||||||
|
togglePressedLast = togglePressed;
|
||||||
|
|
||||||
if (!showDRC)
|
bool showDRC = swkbd::hasKeyboardInputHook() == false && (isDRCPrimary ^ altScreenRequested);
|
||||||
{
|
|
||||||
auto controller = InputManager::instance().get_vpad_controller(0);
|
|
||||||
if (controller && controller->is_screen_active())
|
|
||||||
showDRC = true;
|
|
||||||
if (!showDRC)
|
|
||||||
{
|
|
||||||
controller = InputManager::instance().get_vpad_controller(1);
|
|
||||||
if (controller && controller->is_screen_active())
|
|
||||||
showDRC = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((renderTarget & RENDER_TARGET_DRC) && g_renderer->IsPadWindowActive())
|
if ((renderTarget & RENDER_TARGET_DRC) && g_renderer->IsPadWindowActive())
|
||||||
LatteRenderTarget_copyToBackbuffer(texView, true);
|
LatteRenderTarget_copyToBackbuffer(texView, true);
|
||||||
|
@ -213,7 +213,10 @@ bool LaunchSettings::HandleCommandline(const std::vector<std::wstring>& args)
|
|||||||
}
|
}
|
||||||
catch (const std::exception& ex)
|
catch (const std::exception& ex)
|
||||||
{
|
{
|
||||||
cemuLog_log(LogType::Force, "Error while trying to parse command line parameter: {}", ex.what());
|
std::string errorMsg;
|
||||||
|
errorMsg.append("Error while trying to parse command line parameter:\n");
|
||||||
|
errorMsg.append(ex.what());
|
||||||
|
std::cout << errorMsg << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1392,7 +1392,6 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo)
|
|||||||
const auto outputPath = shortcutDialog.GetPath();
|
const auto outputPath = shortcutDialog.GetPath();
|
||||||
|
|
||||||
std::optional<fs::path> icon_path = std::nullopt;
|
std::optional<fs::path> icon_path = std::nullopt;
|
||||||
[&]()
|
|
||||||
{
|
{
|
||||||
int iconIdx;
|
int iconIdx;
|
||||||
int smallIconIdx;
|
int smallIconIdx;
|
||||||
@ -1402,15 +1401,13 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto icon = m_image_list->GetIcon(iconIdx);
|
const auto icon = m_image_list->GetIcon(iconIdx);
|
||||||
PWSTR localAppData;
|
const auto folder = ActiveSettings::GetUserDataPath("icons");
|
||||||
const auto hres = SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &localAppData);
|
if (!fs::exists(folder) && !fs::create_directories(folder))
|
||||||
wxBitmap bitmap{};
|
|
||||||
auto folder = fs::path(localAppData) / "Cemu" / "icons";
|
|
||||||
if (!SUCCEEDED(hres) || (!fs::exists(folder) && !fs::create_directories(folder)))
|
|
||||||
{
|
{
|
||||||
cemuLog_log(LogType::Force, "Failed to create icon directory");
|
cemuLog_log(LogType::Force, "Failed to create icon directory");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
wxBitmap bitmap{};
|
||||||
if (!bitmap.CopyFromIcon(icon))
|
if (!bitmap.CopyFromIcon(icon))
|
||||||
{
|
{
|
||||||
cemuLog_log(LogType::Force, "Failed to copy icon");
|
cemuLog_log(LogType::Force, "Failed to copy icon");
|
||||||
@ -1426,7 +1423,7 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo)
|
|||||||
icon_path = std::nullopt;
|
icon_path = std::nullopt;
|
||||||
cemuLog_log(LogType::Force, "Icon failed to save");
|
cemuLog_log(LogType::Force, "Icon failed to save");
|
||||||
}
|
}
|
||||||
}();
|
}
|
||||||
|
|
||||||
IShellLinkW* shellLink;
|
IShellLinkW* shellLink;
|
||||||
HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLink, reinterpret_cast<LPVOID*>(&shellLink));
|
HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLink, reinterpret_cast<LPVOID*>(&shellLink));
|
||||||
|
@ -114,6 +114,11 @@ InputAPIAddWindow::InputAPIAddWindow(wxWindow* parent, const wxPoint& position,
|
|||||||
this->Bind(wxControllersRefreshed, &InputAPIAddWindow::on_controllers_refreshed, this);
|
this->Bind(wxControllersRefreshed, &InputAPIAddWindow::on_controllers_refreshed, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InputAPIAddWindow::~InputAPIAddWindow()
|
||||||
|
{
|
||||||
|
discard_thread_result();
|
||||||
|
}
|
||||||
|
|
||||||
void InputAPIAddWindow::on_add_button(wxCommandEvent& event)
|
void InputAPIAddWindow::on_add_button(wxCommandEvent& event)
|
||||||
{
|
{
|
||||||
const auto selection = m_input_api->GetSelection();
|
const auto selection = m_input_api->GetSelection();
|
||||||
@ -159,6 +164,8 @@ std::unique_ptr<ControllerProviderSettings> InputAPIAddWindow::get_settings() co
|
|||||||
|
|
||||||
void InputAPIAddWindow::on_api_selected(wxCommandEvent& event)
|
void InputAPIAddWindow::on_api_selected(wxCommandEvent& event)
|
||||||
{
|
{
|
||||||
|
discard_thread_result();
|
||||||
|
|
||||||
if (m_input_api->GetSelection() == wxNOT_FOUND)
|
if (m_input_api->GetSelection() == wxNOT_FOUND)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -239,19 +246,25 @@ void InputAPIAddWindow::on_controller_dropdown(wxCommandEvent& event)
|
|||||||
m_controller_list->Append(_("Searching for controllers..."), (wxClientData*)nullptr);
|
m_controller_list->Append(_("Searching for controllers..."), (wxClientData*)nullptr);
|
||||||
m_controller_list->SetSelection(wxNOT_FOUND);
|
m_controller_list->SetSelection(wxNOT_FOUND);
|
||||||
|
|
||||||
std::thread([this, provider, selected_uuid]()
|
m_search_thread_data = std::make_unique<AsyncThreadData>();
|
||||||
|
std::thread([this, provider, selected_uuid](std::shared_ptr<AsyncThreadData> data)
|
||||||
{
|
{
|
||||||
auto available_controllers = provider->get_controllers();
|
auto available_controllers = provider->get_controllers();
|
||||||
|
|
||||||
wxCommandEvent event(wxControllersRefreshed);
|
{
|
||||||
event.SetEventObject(m_controller_list);
|
std::lock_guard lock{data->mutex};
|
||||||
event.SetClientObject(new wxCustomData(std::move(available_controllers)));
|
if(!data->discardResult)
|
||||||
event.SetInt(provider->api());
|
{
|
||||||
event.SetString(selected_uuid);
|
wxCommandEvent event(wxControllersRefreshed);
|
||||||
wxPostEvent(this, event);
|
event.SetEventObject(m_controller_list);
|
||||||
|
event.SetClientObject(new wxCustomData(std::move(available_controllers)));
|
||||||
m_search_running = false;
|
event.SetInt(provider->api());
|
||||||
}).detach();
|
event.SetString(selected_uuid);
|
||||||
|
wxPostEvent(this, event);
|
||||||
|
m_search_running = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, m_search_thread_data).detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputAPIAddWindow::on_controller_selected(wxCommandEvent& event)
|
void InputAPIAddWindow::on_controller_selected(wxCommandEvent& event)
|
||||||
@ -301,3 +314,13 @@ void InputAPIAddWindow::on_controllers_refreshed(wxCommandEvent& event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InputAPIAddWindow::discard_thread_result()
|
||||||
|
{
|
||||||
|
m_search_running = false;
|
||||||
|
if(m_search_thread_data)
|
||||||
|
{
|
||||||
|
std::lock_guard lock{m_search_thread_data->mutex};
|
||||||
|
m_search_thread_data->discardResult = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -19,6 +19,7 @@ class InputAPIAddWindow : public wxDialog
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
InputAPIAddWindow(wxWindow* parent, const wxPoint& position, const std::vector<ControllerPtr>& controllers);
|
InputAPIAddWindow(wxWindow* parent, const wxPoint& position, const std::vector<ControllerPtr>& controllers);
|
||||||
|
~InputAPIAddWindow();
|
||||||
|
|
||||||
bool is_valid() const { return m_type.has_value() && m_controller != nullptr; }
|
bool is_valid() const { return m_type.has_value() && m_controller != nullptr; }
|
||||||
InputAPI::Type get_type() const { return m_type.value(); }
|
InputAPI::Type get_type() const { return m_type.value(); }
|
||||||
@ -38,6 +39,8 @@ private:
|
|||||||
void on_controller_selected(wxCommandEvent& event);
|
void on_controller_selected(wxCommandEvent& event);
|
||||||
void on_controllers_refreshed(wxCommandEvent& event);
|
void on_controllers_refreshed(wxCommandEvent& event);
|
||||||
|
|
||||||
|
void discard_thread_result();
|
||||||
|
|
||||||
wxChoice* m_input_api;
|
wxChoice* m_input_api;
|
||||||
wxComboBox* m_controller_list;
|
wxComboBox* m_controller_list;
|
||||||
wxButton* m_ok_button;
|
wxButton* m_ok_button;
|
||||||
@ -50,4 +53,10 @@ private:
|
|||||||
|
|
||||||
std::vector<ControllerPtr> m_controllers;
|
std::vector<ControllerPtr> m_controllers;
|
||||||
std::atomic_bool m_search_running = false;
|
std::atomic_bool m_search_running = false;
|
||||||
|
struct AsyncThreadData
|
||||||
|
{
|
||||||
|
std::atomic_bool discardResult = false;
|
||||||
|
std::mutex mutex;
|
||||||
|
};
|
||||||
|
std::shared_ptr<AsyncThreadData> m_search_thread_data;
|
||||||
};
|
};
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <wx/statline.h>
|
#include <wx/statline.h>
|
||||||
#include <wx/textctrl.h>
|
#include <wx/textctrl.h>
|
||||||
#include <wx/slider.h>
|
#include <wx/slider.h>
|
||||||
|
#include <wx/checkbox.h>
|
||||||
|
|
||||||
|
|
||||||
#include "helpers/wxControlObject.h"
|
#include "helpers/wxControlObject.h"
|
||||||
@ -131,11 +132,23 @@ VPADInputPanel::VPADInputPanel(wxWindow* parent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Blow Mic
|
// Blow Mic
|
||||||
row = 9;
|
row = 8;
|
||||||
add_button_row(main_sizer, row, column, VPADController::kButtonId_Mic, _("blow mic"));
|
add_button_row(main_sizer, row, column, VPADController::kButtonId_Mic, _("blow mic"));
|
||||||
row++;
|
row++;
|
||||||
|
|
||||||
add_button_row(main_sizer, row, column, VPADController::kButtonId_Screen, _("show screen"));
|
add_button_row(main_sizer, row, column, VPADController::kButtonId_Screen, _("show screen"));
|
||||||
|
row++;
|
||||||
|
|
||||||
|
auto toggleScreenText = new wxStaticText(this, wxID_ANY, _("toggle screen"));
|
||||||
|
main_sizer->Add(toggleScreenText,
|
||||||
|
wxGBPosition(row, column),
|
||||||
|
wxDefaultSpan,
|
||||||
|
wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||||
|
m_togglePadViewCheckBox = new wxCheckBox(this, wxID_ANY, {}, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||||
|
wxString toggleScreenTT = _("Makes the \"show screen\" button toggle between the TV and gamepad screens");
|
||||||
|
m_togglePadViewCheckBox->SetToolTip(toggleScreenTT);
|
||||||
|
toggleScreenText->SetToolTip(toggleScreenTT);
|
||||||
|
main_sizer->Add(m_togglePadViewCheckBox, wxGBPosition(row,column+1), wxDefaultSpan, wxALL | wxEXPAND, 5);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@ -168,6 +181,8 @@ void VPADInputPanel::on_timer(const EmulatedControllerPtr& emulated_controller,
|
|||||||
{
|
{
|
||||||
InputPanel::on_timer(emulated_controller, controller_base);
|
InputPanel::on_timer(emulated_controller, controller_base);
|
||||||
|
|
||||||
|
static_cast<VPADController*>(emulated_controller.get())->set_screen_toggle(m_togglePadViewCheckBox->GetValue());
|
||||||
|
|
||||||
if(emulated_controller)
|
if(emulated_controller)
|
||||||
{
|
{
|
||||||
const auto axis = emulated_controller->get_axis();
|
const auto axis = emulated_controller->get_axis();
|
||||||
@ -182,3 +197,10 @@ void VPADInputPanel::OnVolumeChange(wxCommandEvent& event)
|
|||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
void VPADInputPanel::load_controller(const EmulatedControllerPtr& controller)
|
||||||
|
{
|
||||||
|
InputPanel::load_controller(controller);
|
||||||
|
|
||||||
|
const bool isToggle = static_cast<VPADController*>(controller.get())->is_screen_active_toggle();
|
||||||
|
m_togglePadViewCheckBox->SetValue(isToggle);
|
||||||
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "input/panels/InputPanel.h"
|
#include "input/panels/InputPanel.h"
|
||||||
|
|
||||||
class wxInputDraw;
|
class wxInputDraw;
|
||||||
|
class wxCheckBox;
|
||||||
|
|
||||||
class VPADInputPanel : public InputPanel
|
class VPADInputPanel : public InputPanel
|
||||||
{
|
{
|
||||||
@ -11,11 +12,13 @@ public:
|
|||||||
VPADInputPanel(wxWindow* parent);
|
VPADInputPanel(wxWindow* parent);
|
||||||
|
|
||||||
void on_timer(const EmulatedControllerPtr& emulated_controller, const ControllerPtr& controller) override;
|
void on_timer(const EmulatedControllerPtr& emulated_controller, const ControllerPtr& controller) override;
|
||||||
|
virtual void load_controller(const EmulatedControllerPtr& controller) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnVolumeChange(wxCommandEvent& event);
|
void OnVolumeChange(wxCommandEvent& event);
|
||||||
|
|
||||||
wxInputDraw* m_left_draw, * m_right_draw;
|
wxInputDraw* m_left_draw, * m_right_draw;
|
||||||
|
wxCheckBox* m_togglePadViewCheckBox;
|
||||||
|
|
||||||
void add_button_row(wxGridBagSizer *sizer, sint32 row, sint32 column, const VPADController::ButtonId &button_id);
|
void add_button_row(wxGridBagSizer *sizer, sint32 row, sint32 column, const VPADController::ButtonId &button_id);
|
||||||
void add_button_row(wxGridBagSizer *sizer, sint32 row, sint32 column, const VPADController::ButtonId &button_id, const wxString &label);
|
void add_button_row(wxGridBagSizer *sizer, sint32 row, sint32 column, const VPADController::ButtonId &button_id, const wxString &label);
|
||||||
|
@ -690,3 +690,14 @@ bool VPADController::set_default_mapping(const std::shared_ptr<ControllerBase>&
|
|||||||
|
|
||||||
return mapping_updated;
|
return mapping_updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VPADController::load(const pugi::xml_node& node)
|
||||||
|
{
|
||||||
|
if (const auto value = node.child("toggle_display"))
|
||||||
|
m_screen_active_toggle = ConvertString<bool>(value.child_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
void VPADController::save(pugi::xml_node& node)
|
||||||
|
{
|
||||||
|
node.append_child("toggle_display").append_child(pugi::node_pcdata).set_value(fmt::format("{}", (int)m_screen_active_toggle).c_str());
|
||||||
|
}
|
||||||
|
@ -66,6 +66,8 @@ public:
|
|||||||
|
|
||||||
bool is_mic_active() { return m_mic_active; }
|
bool is_mic_active() { return m_mic_active; }
|
||||||
bool is_screen_active() { return m_screen_active; }
|
bool is_screen_active() { return m_screen_active; }
|
||||||
|
bool is_screen_active_toggle() { return m_screen_active_toggle; }
|
||||||
|
void set_screen_toggle(bool toggle) {m_screen_active_toggle = toggle;}
|
||||||
|
|
||||||
static std::string_view get_button_name(ButtonId id);
|
static std::string_view get_button_name(ButtonId id);
|
||||||
|
|
||||||
@ -86,9 +88,13 @@ public:
|
|||||||
|
|
||||||
bool set_default_mapping(const std::shared_ptr<ControllerBase>& controller) override;
|
bool set_default_mapping(const std::shared_ptr<ControllerBase>& controller) override;
|
||||||
|
|
||||||
|
void load(const pugi::xml_node& node) override;
|
||||||
|
void save(pugi::xml_node& node) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_mic_active = false;
|
bool m_mic_active = false;
|
||||||
bool m_screen_active = false;
|
bool m_screen_active = false;
|
||||||
|
bool m_screen_active_toggle = false;
|
||||||
uint32be m_last_holdvalue = 0;
|
uint32be m_last_holdvalue = 0;
|
||||||
|
|
||||||
std::chrono::high_resolution_clock::time_point m_last_hold_change{}, m_last_pulse{};
|
std::chrono::high_resolution_clock::time_point m_last_hold_change{}, m_last_pulse{};
|
||||||
|
Loading…
Reference in New Issue
Block a user