mirror of
https://github.com/palera1n/palera1n.git
synced 2026-10-23 02:29:48 +02:00
feat: wxWidgets gui
This commit is contained in:
53 files changed
+2494
-296
No files matched your search
@@ -0,0 +1,427 @@
|
||||
#ifdef WITH_GUI
|
||||
|
||||
#include "DfuPanel.hpp"
|
||||
|
||||
#include "AppFrame.hpp"
|
||||
#include "DevicePanel.hpp"
|
||||
#include "../state.hpp"
|
||||
#include "../sequence.hpp"
|
||||
#include "../utils/log.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include <wx/wx.h>
|
||||
#include <wx/mstream.h>
|
||||
#include <wx/image.h>
|
||||
#include <wx/bitmap.h>
|
||||
|
||||
#include "../gen/images/atv_std_brd.h"
|
||||
#include "../gen/images/ipad.h"
|
||||
#include "../gen/images/ipadmini.h"
|
||||
#include "../gen/images/iphone6s.h"
|
||||
#include "../gen/images/iphone7.h"
|
||||
#include "../gen/images/iphone8.h"
|
||||
#include "../gen/images/iphonese.h"
|
||||
#include "../gen/images/iphonex.h"
|
||||
#include "../gen/images/ipodtouch.h"
|
||||
#include "../gen/images/siriremote.h"
|
||||
|
||||
#include <libirecovery.h>
|
||||
|
||||
static const wxColour kActive =
|
||||
wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
|
||||
|
||||
static const wxColour kInactive =
|
||||
wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);
|
||||
|
||||
DfuPanel::DfuPanel(MainFrame* frame, wxWindow* parent)
|
||||
: DevicePanel(frame, parent)
|
||||
{
|
||||
auto* root = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
m_headerText = new wxStaticText(this, wxID_ANY, "Time to put the device into DFU mode. Locate the buttons as marked below\non your device and check the instructions on the right.");
|
||||
root->Add(m_headerText, 0, wxALL, 10);
|
||||
|
||||
auto* contentRow = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
m_devicePanel = new wxPanel(this);
|
||||
m_devicePanel->SetMinSize(wxSize(310, 260));
|
||||
|
||||
m_deviceImage = new wxStaticBitmap(
|
||||
m_devicePanel,
|
||||
wxID_ANY,
|
||||
wxBitmap()
|
||||
);
|
||||
|
||||
contentRow->Add(m_devicePanel, 1, wxTOP, 10);
|
||||
m_stepsSizer = new wxBoxSizer(wxVERTICAL);
|
||||
contentRow->Add(m_stepsSizer, 2, wxEXPAND | wxALL, 0);
|
||||
|
||||
root->Add(contentRow, 1, wxEXPAND);
|
||||
|
||||
m_backButton = new wxButton(this, wxID_ANY, "Back");
|
||||
m_startButton = new wxButton(this, wxID_ANY, "Start");
|
||||
|
||||
m_backButton->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&)
|
||||
{
|
||||
frame->ShowMain();
|
||||
});
|
||||
|
||||
m_startButton->Bind(wxEVT_BUTTON, [this](wxCommandEvent&)
|
||||
{
|
||||
m_isEnteringDfu = true;
|
||||
m_backButton->Disable();
|
||||
m_startButton->Disable();
|
||||
|
||||
StartSequence(m_sequence);
|
||||
});
|
||||
|
||||
m_timer.Bind(wxEVT_TIMER, [this](wxTimerEvent&)
|
||||
{
|
||||
RunStep();
|
||||
});
|
||||
|
||||
m_stagnentTimer.Bind(wxEVT_TIMER, [this](wxTimerEvent&)
|
||||
{
|
||||
m_backButton->Enable();
|
||||
m_startButton->Enable();
|
||||
GetMainFrame()->ShowExploit();
|
||||
});
|
||||
|
||||
auto* bottomRow = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
bottomRow->AddStretchSpacer();
|
||||
bottomRow->Add(m_backButton, 0, wxALL, 10);
|
||||
bottomRow->Add(m_startButton, 0, wxALL, 10);
|
||||
|
||||
root->Add(bottomRow, 0, wxEXPAND);
|
||||
|
||||
SetSizer(root);
|
||||
}
|
||||
|
||||
void DfuPanel::SetDeviceState(const DeviceState& state)
|
||||
{
|
||||
DevicePanel::SetDeviceState(state);
|
||||
|
||||
if (!(this->IsShown()))
|
||||
return;
|
||||
|
||||
if (m_isEnteringDfu && state.mode == DeviceMode::DFU)
|
||||
{
|
||||
m_isEnteringDfu = false;
|
||||
m_headerText->SetLabel("Device entered DFU mode successfully.\n");
|
||||
|
||||
if (!m_stagnentTimer.IsRunning())
|
||||
m_stagnentTimer.StartOnce(3000);
|
||||
}
|
||||
|
||||
if (m_isEnteringDfu && state.mode == DeviceMode::Normal)
|
||||
{
|
||||
m_isEnteringDfu = false;
|
||||
m_backButton->Enable();
|
||||
m_startButton->Enable();
|
||||
GetMainFrame()->ShowRecovery();
|
||||
GetMainFrame()->GetRecoveryPanel()->SetStatusText("Hmm... It seems like the device didn't enter DFU mode.");
|
||||
}
|
||||
|
||||
if (m_isEnteringDfu && state.mode == DeviceMode::Recovery)
|
||||
{
|
||||
m_isEnteringDfu = false;
|
||||
m_backButton->Enable();
|
||||
m_startButton->Enable();
|
||||
GetMainFrame()->ShowMain();
|
||||
}
|
||||
}
|
||||
|
||||
void DfuPanel::LoadDevice(const std::string& productType)
|
||||
{
|
||||
m_sequence = ParseSequence(productType);
|
||||
m_index = 0;
|
||||
|
||||
m_deviceImage->SetBitmap(wxBitmap());
|
||||
|
||||
for (auto* lbl : m_stepLabels)
|
||||
lbl->Destroy();
|
||||
|
||||
m_stepLabels.clear();
|
||||
m_stepsSizer->Clear(false);
|
||||
|
||||
for (auto* lbl : m_buttonLabels)
|
||||
lbl->Destroy();
|
||||
|
||||
m_buttonLabels.clear();
|
||||
|
||||
const unsigned char* imageData = nullptr;
|
||||
size_t imageSize = 0;
|
||||
|
||||
if (m_sequence.imageName == "ipadmini")
|
||||
{
|
||||
imageData = ipadmini;
|
||||
imageSize = ipadmini_len;
|
||||
}
|
||||
else if (m_sequence.imageName == "ipad")
|
||||
{
|
||||
imageData = ipad;
|
||||
imageSize = ipad_len;
|
||||
}
|
||||
else if (m_sequence.imageName == "iphonese")
|
||||
{
|
||||
imageData = iphonese;
|
||||
imageSize = iphonese_len;
|
||||
}
|
||||
else if (m_sequence.imageName == "iphone6s")
|
||||
{
|
||||
imageData = iphone6s;
|
||||
imageSize = iphone6s_len;
|
||||
}
|
||||
else if (m_sequence.imageName == "iphone7")
|
||||
{
|
||||
imageData = iphone7;
|
||||
imageSize = iphone7_len;
|
||||
}
|
||||
else if (m_sequence.imageName == "iphone8")
|
||||
{
|
||||
imageData = iphone8;
|
||||
imageSize = iphone8_len;
|
||||
}
|
||||
else if (m_sequence.imageName == "iphonex")
|
||||
{
|
||||
imageData = iphonex;
|
||||
imageSize = iphonex_len;
|
||||
}
|
||||
else if (m_sequence.imageName == "ipodtouch")
|
||||
{
|
||||
imageData = ipodtouch;
|
||||
imageSize = ipodtouch_len;
|
||||
}
|
||||
else if (m_sequence.imageName == "siriremote")
|
||||
{
|
||||
imageData = siriremote;
|
||||
imageSize = siriremote_len;
|
||||
}
|
||||
else if (m_sequence.imageName == "atv_std_brd")
|
||||
{
|
||||
imageData = atv_std_brd;
|
||||
imageSize = atv_std_brd_len;
|
||||
}
|
||||
|
||||
if (imageData)
|
||||
{
|
||||
wxMemoryInputStream stream(imageData, imageSize);
|
||||
|
||||
wxImage img(stream, wxBITMAP_TYPE_PNG);
|
||||
|
||||
if (img.IsOk())
|
||||
{
|
||||
img = img.Scale(
|
||||
m_sequence.imageWidth,
|
||||
m_sequence.imageHeight,
|
||||
wxIMAGE_QUALITY_HIGH
|
||||
);
|
||||
|
||||
m_deviceImage->SetBitmap(wxBitmap(img));
|
||||
m_deviceImage->SetPosition(wxPoint(m_sequence.imageOffsetX, 0));
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& button : m_sequence.buttons)
|
||||
{
|
||||
auto* lbl = new wxStaticText(
|
||||
m_devicePanel,
|
||||
wxID_ANY,
|
||||
button.name
|
||||
);
|
||||
|
||||
lbl->SetPosition(wxPoint(button.x, button.y));
|
||||
|
||||
m_buttonLabels.push_back(lbl);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < m_sequence.steps.size(); i++)
|
||||
{
|
||||
const auto& step = m_sequence.steps[i];
|
||||
|
||||
wxString label = wxString::Format(
|
||||
"%zu. %s (%d)",
|
||||
i + 1,
|
||||
step.description,
|
||||
step.duration
|
||||
);
|
||||
|
||||
auto* lbl = new wxStaticText(
|
||||
this,
|
||||
wxID_ANY,
|
||||
label
|
||||
);
|
||||
|
||||
lbl->SetForegroundColour(i == 0 ? kActive : kInactive);
|
||||
|
||||
m_stepsSizer->Add(lbl, 0, wxBOTTOM, 5);
|
||||
m_stepLabels.push_back(lbl);
|
||||
}
|
||||
|
||||
m_devicePanel->Layout();
|
||||
m_stepsSizer->Layout();
|
||||
|
||||
Layout();
|
||||
Fit();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void DfuPanel::StartSequence(const DfuSequence& seq)
|
||||
{
|
||||
m_sequence = seq;
|
||||
m_index = 0;
|
||||
m_stepRemaining = -1;
|
||||
m_actionExecutedIndex = -1;
|
||||
|
||||
RunStep();
|
||||
m_timer.StartOnce(1000);
|
||||
}
|
||||
|
||||
void DfuPanel::RunStep()
|
||||
{
|
||||
if (m_sequence.steps.empty())
|
||||
return;
|
||||
|
||||
if (m_index >= m_sequence.steps.size())
|
||||
{
|
||||
for (auto* lbl : m_stepLabels)
|
||||
lbl->SetForegroundColour(kInactive);
|
||||
|
||||
Layout();
|
||||
Refresh();
|
||||
|
||||
m_timer.Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& step = m_sequence.steps[m_index];
|
||||
|
||||
if (m_stepRemaining < 0)
|
||||
m_stepRemaining = step.duration;
|
||||
|
||||
if (m_stepRemaining > 0)
|
||||
--m_stepRemaining;
|
||||
|
||||
bool finished = (m_stepRemaining == 0);
|
||||
size_t completedIndex = m_index;
|
||||
|
||||
if (finished)
|
||||
{
|
||||
++m_index;
|
||||
m_stepRemaining = -1;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < m_stepLabels.size(); i++)
|
||||
{
|
||||
auto* lbl = m_stepLabels[i];
|
||||
|
||||
if (i == m_index)
|
||||
{
|
||||
lbl->SetForegroundColour(kActive);
|
||||
|
||||
lbl->SetLabel(wxString::Format(
|
||||
"%zu. %s (%d)",
|
||||
i + 1,
|
||||
m_sequence.steps[i].description,
|
||||
m_stepRemaining < 0 ? m_sequence.steps[i].duration : m_stepRemaining
|
||||
));
|
||||
}
|
||||
else if (finished && i == completedIndex)
|
||||
{
|
||||
lbl->SetForegroundColour(kInactive);
|
||||
|
||||
lbl->SetLabel(wxString::Format(
|
||||
"%zu. %s (0)",
|
||||
i + 1,
|
||||
m_sequence.steps[i].description
|
||||
));
|
||||
}
|
||||
else
|
||||
{
|
||||
lbl->SetForegroundColour(kInactive);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto* lbl : m_buttonLabels)
|
||||
lbl->SetForegroundColour(kInactive);
|
||||
|
||||
const auto& activeStep =
|
||||
(m_index < m_sequence.steps.size())
|
||||
? m_sequence.steps[m_index]
|
||||
: m_sequence.steps.back();
|
||||
|
||||
for (const auto& buttonId : activeStep.activeButtons)
|
||||
{
|
||||
for (const auto& btn : m_sequence.buttons)
|
||||
{
|
||||
if (btn.id == buttonId)
|
||||
{
|
||||
for (auto* lbl : m_buttonLabels)
|
||||
{
|
||||
if (lbl->GetLabel() == btn.name)
|
||||
lbl->SetForegroundColour(kActive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_index < m_sequence.steps.size())
|
||||
{
|
||||
const auto& activeStep = m_sequence.steps[m_index];
|
||||
|
||||
if (!activeStep.action.empty() && m_actionExecutedIndex != m_index)
|
||||
{
|
||||
m_actionExecutedIndex = m_index;
|
||||
|
||||
if (activeStep.action == "reboot")
|
||||
{
|
||||
Reboot();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Layout();
|
||||
Refresh();
|
||||
Update();
|
||||
|
||||
m_timer.StartOnce(1000);
|
||||
}
|
||||
|
||||
void DfuPanel::Reboot()
|
||||
{
|
||||
std::thread([this]()
|
||||
{
|
||||
const auto state = GetDeviceState();
|
||||
|
||||
if (!state.connected || state.mode != DeviceMode::Recovery)
|
||||
return;
|
||||
|
||||
irecv_client_t client = nullptr;
|
||||
|
||||
int attempts = 0;
|
||||
const int max_attempts = 8;
|
||||
|
||||
while (attempts < max_attempts)
|
||||
{
|
||||
if (irecv_open_with_ecid(&client, state.ecid) == IRECV_E_SUCCESS)
|
||||
break;
|
||||
|
||||
attempts++;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(250));
|
||||
}
|
||||
|
||||
if (!client)
|
||||
{
|
||||
return;
|
||||
}
|
||||
irecv_setenv(client, "auto-boot", "true");
|
||||
irecv_saveenv(client);
|
||||
irecv_reboot(client);
|
||||
|
||||
irecv_close(client);
|
||||
}).detach();
|
||||
}
|
||||
|
||||
#endif // WITH_GUI
|
||||
Reference in new issue
Block a user