mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
Merge pull request #7880 from jordan-woyak/udraw-tablet-emu
WiimoteEmu: Implement 3rd-Party extension encryption and uDraw GameTablet.
This commit is contained in:
@@ -148,6 +148,7 @@ add_library(core
|
||||
HW/WiimoteEmu/Extension/Drums.cpp
|
||||
HW/WiimoteEmu/Extension/Guitar.cpp
|
||||
HW/WiimoteEmu/Extension/Turntable.cpp
|
||||
HW/WiimoteEmu/Extension/UDrawTablet.cpp
|
||||
HW/WiimoteReal/WiimoteReal.cpp
|
||||
HW/WiiSave.cpp
|
||||
IOS/Device.cpp
|
||||
|
||||
@@ -182,6 +182,7 @@
|
||||
<ClCompile Include="HW\WiimoteEmu\Extension\Guitar.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\Extension\Nunchuk.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\Extension\Turntable.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\Extension\UDrawTablet.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\I2CBus.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\MotionPlus.cpp" />
|
||||
<ClCompile Include="HW\WiimoteEmu\Speaker.cpp" />
|
||||
@@ -449,6 +450,7 @@
|
||||
<ClInclude Include="HW\WiimoteEmu\Extension\Guitar.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\Extension\Nunchuk.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\Extension\Turntable.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\Extension\UDrawTablet.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\I2CBus.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\MotionPlus.h" />
|
||||
<ClInclude Include="HW\WiimoteEmu\Speaker.h" />
|
||||
|
||||
@@ -907,6 +907,9 @@
|
||||
<ClCompile Include="HW\WiimoteEmu\Extension\Turntable.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\Extension\UDrawTablet.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\WiimoteEmu\Extension\Extension.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
|
||||
</ClCompile>
|
||||
@@ -1619,6 +1622,9 @@
|
||||
<ClInclude Include="HW\WiimoteEmu\Extension\Turntable.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\Extension\UDrawTablet.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\Extension\Extension.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu\Extension</Filter>
|
||||
</ClInclude>
|
||||
@@ -1628,6 +1634,7 @@
|
||||
<ClInclude Include="HW\WiimoteCommon\DataReport.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PowerPC\ConditionRegister.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
|
||||
@@ -66,6 +66,12 @@ ControllerEmu::ControlGroup* GetTurntableGroup(int number, WiimoteEmu::Turntable
|
||||
->GetTurntableGroup(group);
|
||||
}
|
||||
|
||||
ControllerEmu::ControlGroup* GetUDrawTabletGroup(int number, WiimoteEmu::UDrawTabletGroup group)
|
||||
{
|
||||
return static_cast<WiimoteEmu::Wiimote*>(s_config.GetController(number))
|
||||
->GetUDrawTabletGroup(group);
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
s_config.UnregisterHotplugCallback();
|
||||
|
||||
@@ -26,6 +26,7 @@ enum class ClassicGroup;
|
||||
enum class GuitarGroup;
|
||||
enum class DrumsGroup;
|
||||
enum class TurntableGroup;
|
||||
enum class UDrawTabletGroup;
|
||||
} // namespace WiimoteEmu
|
||||
|
||||
enum
|
||||
@@ -78,6 +79,7 @@ ControllerEmu::ControlGroup* GetClassicGroup(int number, WiimoteEmu::ClassicGrou
|
||||
ControllerEmu::ControlGroup* GetGuitarGroup(int number, WiimoteEmu::GuitarGroup group);
|
||||
ControllerEmu::ControlGroup* GetDrumsGroup(int number, WiimoteEmu::DrumsGroup group);
|
||||
ControllerEmu::ControlGroup* GetTurntableGroup(int number, WiimoteEmu::TurntableGroup group);
|
||||
ControllerEmu::ControlGroup* GetUDrawTabletGroup(int number, WiimoteEmu::UDrawTabletGroup group);
|
||||
|
||||
void ControlChannel(int number, u16 channel_id, const void* data, u32 size);
|
||||
void InterruptChannel(int number, u16 channel_id, const void* data, u32 size);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
namespace WiimoteEmu
|
||||
@@ -13,14 +15,50 @@ namespace WiimoteEmu
|
||||
class EncryptionKey
|
||||
{
|
||||
public:
|
||||
void Generate(const u8* keydata);
|
||||
void Encrypt(u8* data, u32 addr, u32 len) const;
|
||||
void Decrypt(u8* data, u32 addr, u32 len) const;
|
||||
|
||||
void Encrypt(u8* data, int addr, u8 len) const;
|
||||
void Decrypt(u8* data, int addr, u8 len) const;
|
||||
using RandData = std::array<u8, 10>;
|
||||
using KeyData = std::array<u8, 6>;
|
||||
|
||||
void GenerateTables(const RandData& rand, const KeyData& key, const u32 idx, const u8 offset);
|
||||
|
||||
std::array<u8, 8> ft = {};
|
||||
std::array<u8, 8> sb = {};
|
||||
};
|
||||
|
||||
class KeyGen
|
||||
{
|
||||
public:
|
||||
virtual ~KeyGen() = default;
|
||||
|
||||
using ExtKeyData = std::array<u8, 16>;
|
||||
|
||||
EncryptionKey GenerateFromExtensionKeyData(const ExtKeyData& key_data) const;
|
||||
|
||||
protected:
|
||||
virtual EncryptionKey::KeyData GenerateKeyData(const EncryptionKey::RandData& rand,
|
||||
u32 idx) const = 0;
|
||||
virtual EncryptionKey GenerateTables(const EncryptionKey::RandData& rand,
|
||||
const EncryptionKey::KeyData& key, u32 idx) const = 0;
|
||||
};
|
||||
|
||||
class KeyGen1stParty final : public KeyGen
|
||||
{
|
||||
private:
|
||||
u8 ft[8] = {};
|
||||
u8 sb[8] = {};
|
||||
EncryptionKey::KeyData GenerateKeyData(const EncryptionKey::RandData& rand,
|
||||
u32 idx) const final override;
|
||||
EncryptionKey GenerateTables(const EncryptionKey::RandData& rand,
|
||||
const EncryptionKey::KeyData& key, u32 idx) const final override;
|
||||
};
|
||||
|
||||
class KeyGen3rdParty final : public KeyGen
|
||||
{
|
||||
private:
|
||||
EncryptionKey::KeyData GenerateKeyData(const EncryptionKey::RandData& rand,
|
||||
u32 idx) const final override;
|
||||
EncryptionKey GenerateTables(const EncryptionKey::RandData& rand,
|
||||
const EncryptionKey::KeyData& key, u32 idx) const final override;
|
||||
};
|
||||
|
||||
} // namespace WiimoteEmu
|
||||
|
||||
@@ -72,7 +72,7 @@ constexpr std::array<u16, 4> classic_dpad_bitmasks{{
|
||||
Classic::PAD_RIGHT,
|
||||
}};
|
||||
|
||||
Classic::Classic() : EncryptedExtension(_trans("Classic"))
|
||||
Classic::Classic() : Extension1stParty(_trans("Classic"))
|
||||
{
|
||||
// buttons
|
||||
groups.emplace_back(m_buttons = new ControllerEmu::Buttons(_trans("Buttons")));
|
||||
@@ -172,7 +172,8 @@ bool Classic::IsButtonPressed() const
|
||||
|
||||
void Classic::Reset()
|
||||
{
|
||||
m_reg = {};
|
||||
EncryptedExtension::Reset();
|
||||
|
||||
m_reg.identifier = classic_id;
|
||||
|
||||
// Build calibration data:
|
||||
|
||||
@@ -26,7 +26,7 @@ enum class ClassicGroup
|
||||
RightStick
|
||||
};
|
||||
|
||||
class Classic : public EncryptedExtension
|
||||
class Classic : public Extension1stParty
|
||||
{
|
||||
public:
|
||||
union ButtonFormat
|
||||
|
||||
@@ -44,7 +44,7 @@ constexpr std::array<u16, 2> drum_button_bitmasks{{
|
||||
Drums::BUTTON_PLUS,
|
||||
}};
|
||||
|
||||
Drums::Drums() : EncryptedExtension(_trans("Drums"))
|
||||
Drums::Drums() : Extension1stParty(_trans("Drums"))
|
||||
{
|
||||
// pads
|
||||
groups.emplace_back(m_pads = new ControllerEmu::Buttons(_trans("Pads")));
|
||||
@@ -106,7 +106,8 @@ bool Drums::IsButtonPressed() const
|
||||
|
||||
void Drums::Reset()
|
||||
{
|
||||
m_reg = {};
|
||||
EncryptedExtension::Reset();
|
||||
|
||||
m_reg.identifier = drums_id;
|
||||
|
||||
// TODO: Is there calibration data?
|
||||
|
||||
@@ -22,8 +22,8 @@ enum class DrumsGroup
|
||||
Stick
|
||||
};
|
||||
|
||||
// TODO: Do the drums ever use encryption?
|
||||
class Drums : public EncryptedExtension
|
||||
// The Drums use the "1st-party" extension encryption scheme.
|
||||
class Drums : public Extension1stParty
|
||||
{
|
||||
public:
|
||||
struct DataFormat
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include "Common/Compiler.h"
|
||||
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
||||
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
namespace WiimoteEmu
|
||||
{
|
||||
Extension::Extension(const char* name) : m_name(name)
|
||||
@@ -85,15 +87,16 @@ int EncryptedExtension::BusRead(u8 slave_addr, u8 addr, int count, u8* data_out)
|
||||
|
||||
auto const result = RawRead(&m_reg, addr, count, data_out);
|
||||
|
||||
// Encrypt data read from extension register
|
||||
// Encrypt data read from extension register.
|
||||
if (ENCRYPTION_ENABLED == m_reg.encryption)
|
||||
{
|
||||
// INFO_LOG(WIIMOTE, "Encrypted read.");
|
||||
ext_key.Encrypt(data_out, addr, (u8)count);
|
||||
}
|
||||
else
|
||||
{
|
||||
// INFO_LOG(WIIMOTE, "Unencrypted read.");
|
||||
if (m_is_key_dirty)
|
||||
{
|
||||
UpdateEncryptionKey();
|
||||
m_is_key_dirty = false;
|
||||
}
|
||||
|
||||
ext_key.Encrypt(data_out, addr, count);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -106,24 +109,48 @@ int EncryptedExtension::BusWrite(u8 slave_addr, u8 addr, int count, const u8* da
|
||||
|
||||
auto const result = RawWrite(&m_reg, addr, count, data_in);
|
||||
|
||||
// TODO: make this check less ugly:
|
||||
if (addr + count > 0x40 && addr < 0x50)
|
||||
constexpr u8 ENCRYPTION_KEY_DATA_BEGIN = offsetof(Register, encryption_key_data);
|
||||
constexpr u8 ENCRYPTION_KEY_DATA_END = ENCRYPTION_KEY_DATA_BEGIN + 0x10;
|
||||
|
||||
if (addr + count > ENCRYPTION_KEY_DATA_BEGIN && addr < ENCRYPTION_KEY_DATA_END)
|
||||
{
|
||||
// Run the key generation on all writes in the key area, it doesn't matter
|
||||
// that we send it parts of a key, only the last full key will have an effect
|
||||
ext_key.Generate(m_reg.encryption_key_data);
|
||||
// FYI: Real extensions seem to require the key data written in specifically sized chunks.
|
||||
// We just run the key generation on all writes to the key area.
|
||||
m_is_key_dirty = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void EncryptedExtension::Reset()
|
||||
{
|
||||
// Clear register state.
|
||||
m_reg = {};
|
||||
|
||||
// Clear encryption key state.
|
||||
ext_key = {};
|
||||
m_is_key_dirty = true;
|
||||
}
|
||||
|
||||
void EncryptedExtension::DoState(PointerWrap& p)
|
||||
{
|
||||
p.Do(m_reg);
|
||||
|
||||
// No need to sync this when we can regenerate it:
|
||||
if (p.GetMode() == PointerWrap::MODE_READ)
|
||||
ext_key.Generate(m_reg.encryption_key_data);
|
||||
{
|
||||
// No need to sync the key when we can just regenerate it.
|
||||
m_is_key_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Extension1stParty::UpdateEncryptionKey()
|
||||
{
|
||||
ext_key = KeyGen1stParty().GenerateFromExtensionKeyData(m_reg.encryption_key_data);
|
||||
}
|
||||
|
||||
void Extension3rdParty::UpdateEncryptionKey()
|
||||
{
|
||||
ext_key = KeyGen3rdParty().GenerateFromExtensionKeyData(m_reg.encryption_key_data);
|
||||
}
|
||||
|
||||
} // namespace WiimoteEmu
|
||||
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
|
||||
// TODO: This is public for TAS reasons.
|
||||
// TODO: TAS handles encryption poorly.
|
||||
WiimoteEmu::EncryptionKey ext_key = {};
|
||||
EncryptionKey ext_key;
|
||||
|
||||
protected:
|
||||
static constexpr int CALIBRATION_CHECKSUM_BYTES = 2;
|
||||
@@ -82,7 +82,7 @@ protected:
|
||||
u8 unknown3[0x10];
|
||||
|
||||
// address 0x40
|
||||
u8 encryption_key_data[0x10];
|
||||
std::array<u8, 0x10> encryption_key_data;
|
||||
u8 unknown4[0xA0];
|
||||
|
||||
// address 0xF0
|
||||
@@ -98,9 +98,14 @@ protected:
|
||||
|
||||
Register m_reg = {};
|
||||
|
||||
void Reset() override;
|
||||
void DoState(PointerWrap& p) override;
|
||||
|
||||
virtual void UpdateEncryptionKey() = 0;
|
||||
|
||||
private:
|
||||
bool m_is_key_dirty = true;
|
||||
|
||||
static constexpr u8 ENCRYPTION_ENABLED = 0xaa;
|
||||
|
||||
bool ReadDeviceDetectPin() const override;
|
||||
@@ -109,4 +114,22 @@ private:
|
||||
int BusWrite(u8 slave_addr, u8 addr, int count, const u8* data_in) override;
|
||||
};
|
||||
|
||||
class Extension1stParty : public EncryptedExtension
|
||||
{
|
||||
protected:
|
||||
using EncryptedExtension::EncryptedExtension;
|
||||
|
||||
private:
|
||||
void UpdateEncryptionKey() final override;
|
||||
};
|
||||
|
||||
class Extension3rdParty : public EncryptedExtension
|
||||
{
|
||||
protected:
|
||||
using EncryptedExtension::EncryptedExtension;
|
||||
|
||||
private:
|
||||
void UpdateEncryptionKey() final override;
|
||||
};
|
||||
|
||||
} // namespace WiimoteEmu
|
||||
|
||||
@@ -62,7 +62,7 @@ constexpr std::array<u16, 2> guitar_strum_bitmasks{{
|
||||
Guitar::BAR_DOWN,
|
||||
}};
|
||||
|
||||
Guitar::Guitar() : EncryptedExtension(_trans("Guitar"))
|
||||
Guitar::Guitar() : Extension1stParty(_trans("Guitar"))
|
||||
{
|
||||
// frets
|
||||
groups.emplace_back(m_frets = new ControllerEmu::Buttons(_trans("Frets")));
|
||||
@@ -152,7 +152,8 @@ bool Guitar::IsButtonPressed() const
|
||||
|
||||
void Guitar::Reset()
|
||||
{
|
||||
m_reg = {};
|
||||
EncryptedExtension::Reset();
|
||||
|
||||
m_reg.identifier = guitar_id;
|
||||
|
||||
// TODO: Is there calibration data?
|
||||
|
||||
@@ -27,8 +27,8 @@ enum class GuitarGroup
|
||||
SliderBar
|
||||
};
|
||||
|
||||
// TODO: Does the guitar ever use encryption?
|
||||
class Guitar : public EncryptedExtension
|
||||
// The Guitar uses the "1st-party" extension encryption scheme.
|
||||
class Guitar : public Extension1stParty
|
||||
{
|
||||
public:
|
||||
struct DataFormat
|
||||
|
||||
@@ -31,7 +31,7 @@ constexpr std::array<u8, 2> nunchuk_button_bitmasks{{
|
||||
Nunchuk::BUTTON_Z,
|
||||
}};
|
||||
|
||||
Nunchuk::Nunchuk() : EncryptedExtension(_trans("Nunchuk"))
|
||||
Nunchuk::Nunchuk() : Extension1stParty(_trans("Nunchuk"))
|
||||
{
|
||||
// buttons
|
||||
groups.emplace_back(m_buttons = new ControllerEmu::Buttons(_trans("Buttons")));
|
||||
@@ -121,7 +121,8 @@ bool Nunchuk::IsButtonPressed() const
|
||||
|
||||
void Nunchuk::Reset()
|
||||
{
|
||||
m_reg = {};
|
||||
EncryptedExtension::Reset();
|
||||
|
||||
m_reg.identifier = nunchuk_id;
|
||||
|
||||
m_swing_state = {};
|
||||
|
||||
@@ -30,7 +30,7 @@ enum class NunchukGroup
|
||||
Shake
|
||||
};
|
||||
|
||||
class Nunchuk : public EncryptedExtension
|
||||
class Nunchuk : public Extension1stParty
|
||||
{
|
||||
public:
|
||||
union ButtonFormat
|
||||
|
||||
@@ -45,7 +45,7 @@ constexpr std::array<const char*, 6> turntable_button_names{{
|
||||
_trans("Blue Right"),
|
||||
}};
|
||||
|
||||
Turntable::Turntable() : EncryptedExtension(_trans("Turntable"))
|
||||
Turntable::Turntable() : Extension1stParty(_trans("Turntable"))
|
||||
{
|
||||
// buttons
|
||||
groups.emplace_back(m_buttons = new ControllerEmu::Buttons(_trans("Buttons")));
|
||||
@@ -148,7 +148,8 @@ bool Turntable::IsButtonPressed() const
|
||||
|
||||
void Turntable::Reset()
|
||||
{
|
||||
m_reg = {};
|
||||
EncryptedExtension::Reset();
|
||||
|
||||
m_reg.identifier = turntable_id;
|
||||
|
||||
// TODO: Is there calibration data?
|
||||
|
||||
@@ -27,8 +27,8 @@ enum class TurntableGroup
|
||||
Crossfade
|
||||
};
|
||||
|
||||
// TODO: Does the turntable ever use encryption?
|
||||
class Turntable : public EncryptedExtension
|
||||
// The DJ Hero Turntable uses the "1st-party" extension encryption scheme.
|
||||
class Turntable : public Extension1stParty
|
||||
{
|
||||
public:
|
||||
struct DataFormat
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/HW/WiimoteEmu/Extension/UDrawTablet.h"
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
|
||||
#include "Common/BitUtils.h"
|
||||
#include "Common/Common.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
||||
|
||||
#include "InputCommon/ControllerEmu/Control/Input.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/AnalogStick.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Buttons.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Triggers.h"
|
||||
|
||||
namespace WiimoteEmu
|
||||
{
|
||||
constexpr std::array<u8, 6> udraw_tablet_id{{0xff, 0x00, 0xa4, 0x20, 0x01, 0x12}};
|
||||
|
||||
constexpr std::array<u8, 2> udraw_tablet_button_bitmasks{{
|
||||
UDrawTablet::BUTTON_ROCKER_UP,
|
||||
UDrawTablet::BUTTON_ROCKER_DOWN,
|
||||
}};
|
||||
|
||||
constexpr std::array<const char*, 2> udraw_tablet_button_names{{
|
||||
_trans("Rocker Up"),
|
||||
_trans("Rocker Down"),
|
||||
}};
|
||||
|
||||
UDrawTablet::UDrawTablet() : Extension3rdParty(_trans("uDraw"))
|
||||
{
|
||||
// Buttons
|
||||
groups.emplace_back(m_buttons = new ControllerEmu::Buttons(_trans("Buttons")));
|
||||
for (auto& button_name : udraw_tablet_button_names)
|
||||
{
|
||||
m_buttons->controls.emplace_back(
|
||||
new ControllerEmu::Input(ControllerEmu::Translate, button_name));
|
||||
}
|
||||
|
||||
// Stylus
|
||||
groups.emplace_back(m_stylus = new ControllerEmu::AnalogStick(
|
||||
_trans("Stylus"), std::make_unique<ControllerEmu::SquareStickGate>(1.0)));
|
||||
|
||||
// Touch
|
||||
groups.emplace_back(m_touch = new ControllerEmu::Triggers(_trans("Touch")));
|
||||
m_touch->controls.emplace_back(
|
||||
new ControllerEmu::Input(ControllerEmu::Translate, _trans("Pressure")));
|
||||
}
|
||||
|
||||
void UDrawTablet::Update()
|
||||
{
|
||||
DataFormat tablet_data = {};
|
||||
|
||||
// Pressure:
|
||||
// Min/Max values produced on my device: 0x08, 0xf2
|
||||
// We're just gonna assume it's an old sensor and use the full byte range:
|
||||
// Note: Pressure values are valid even when stylus is lifted.
|
||||
constexpr u8 max_pressure = 0xff;
|
||||
|
||||
const auto touch_state = m_touch->GetState();
|
||||
tablet_data.pressure = static_cast<u8>(touch_state.data[0] * max_pressure);
|
||||
|
||||
// Stylus X/Y:
|
||||
// Min/Max X values (when touched) produced on my device: 0x4f, 0x7B3
|
||||
// Drawing area edge (approx) X values on my device: 0x56, 0x7a5
|
||||
// Min/Max Y values (when touched) produced on my device: 0x53, 0x5b4
|
||||
// Drawing area edge (approx) Y values on my device: 0x5e, 0x5a5
|
||||
|
||||
// Calibrated for "uDraw Studio: Instant Artist".
|
||||
constexpr u16 min_x = 0x56;
|
||||
constexpr u16 max_x = 0x780;
|
||||
constexpr u16 min_y = 0x65;
|
||||
constexpr u16 max_y = 0x5a5;
|
||||
constexpr double center_x = (max_x + min_x) / 2.0;
|
||||
constexpr double center_y = (max_y + min_y) / 2.0;
|
||||
|
||||
// Neutral (lifted) stylus state:
|
||||
u16 stylus_x = 0x7ff;
|
||||
u16 stylus_y = 0x7ff;
|
||||
|
||||
// TODO: Expose the lifted stylus state in the UI.
|
||||
bool is_stylus_lifted = false;
|
||||
|
||||
const auto stylus_state = m_stylus->GetState();
|
||||
|
||||
if (!is_stylus_lifted)
|
||||
{
|
||||
stylus_x = u16(center_x + stylus_state.x * (max_x - center_x));
|
||||
stylus_y = u16(center_y + stylus_state.y * (max_y - center_y));
|
||||
}
|
||||
|
||||
tablet_data.stylus_x1 = stylus_x & 0xff;
|
||||
tablet_data.stylus_x2 = stylus_x >> 8;
|
||||
tablet_data.stylus_y1 = stylus_y & 0xff;
|
||||
tablet_data.stylus_y2 = stylus_y >> 8;
|
||||
|
||||
// Buttons:
|
||||
m_buttons->GetState(&tablet_data.buttons, udraw_tablet_button_bitmasks.data());
|
||||
|
||||
// Flip button bits
|
||||
constexpr u8 buttons_neutral_state = 0xfb;
|
||||
tablet_data.buttons ^= buttons_neutral_state;
|
||||
|
||||
// Always 0xff
|
||||
tablet_data.unk = 0xff;
|
||||
|
||||
Common::BitCastPtr<DataFormat>(&m_reg.controller_data) = tablet_data;
|
||||
}
|
||||
|
||||
void UDrawTablet::Reset()
|
||||
{
|
||||
EncryptedExtension::Reset();
|
||||
|
||||
m_reg.identifier = udraw_tablet_id;
|
||||
|
||||
// Both 0x20 and 0x30 calibration sections are just filled with 0xff on the real tablet:
|
||||
m_reg.calibration.fill(0xff);
|
||||
}
|
||||
|
||||
bool UDrawTablet::IsButtonPressed() const
|
||||
{
|
||||
u8 buttons = 0;
|
||||
m_buttons->GetState(&buttons, udraw_tablet_button_bitmasks.data());
|
||||
return buttons != 0;
|
||||
}
|
||||
|
||||
ControllerEmu::ControlGroup* UDrawTablet::GetGroup(UDrawTabletGroup group)
|
||||
{
|
||||
switch (group)
|
||||
{
|
||||
case UDrawTabletGroup::Buttons:
|
||||
return m_buttons;
|
||||
case UDrawTabletGroup::Stylus:
|
||||
return m_stylus;
|
||||
case UDrawTabletGroup::Touch:
|
||||
return m_touch;
|
||||
default:
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace WiimoteEmu
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user