From 94db6e5f3fc347b4fe1cbeb862019be55f8203ea Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Mon, 24 Dec 2018 16:16:28 -0500
Subject: [PATCH 01/15] am: Add size parameter to am:IStorage logging

---
 src/core/hle/service/am/am.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index d13ce4dca..512386422 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -721,10 +721,10 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
 
     const u64 offset{rp.Pop<u64>()};
-    LOG_DEBUG(Service_AM, "called, offset={}", offset);
-
     const std::vector<u8> data{ctx.ReadBuffer()};
 
+    LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size());
+
     if (data.size() > backing.buffer.size() - offset) {
         LOG_ERROR(Service_AM,
                   "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}",
@@ -744,10 +744,10 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
 
     const u64 offset{rp.Pop<u64>()};
-    LOG_DEBUG(Service_AM, "called, offset={}", offset);
-
     const std::size_t size{ctx.GetWriteBufferSize()};
 
+    LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size);
+
     if (size > backing.buffer.size() - offset) {
         LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}",
                   backing.buffer.size(), size, offset);

From abbcc8e61e33ba093df9c823a03c70eccf010e4c Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Mon, 24 Dec 2018 16:18:28 -0500
Subject: [PATCH 02/15] romfs: Add SingleDiscard extraction type Needed for
 manual RomFS extraction, as Full generates an extra directory and Truncated
 generates variable results.

---
 src/core/file_sys/romfs.cpp | 3 +++
 src/core/file_sys/romfs.h   | 5 +++--
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp
index 81e1f66ac..ebbdf081e 100644
--- a/src/core/file_sys/romfs.cpp
+++ b/src/core/file_sys/romfs.cpp
@@ -119,6 +119,9 @@ VirtualDir ExtractRomFS(VirtualFile file, RomFSExtractionType type) {
 
     VirtualDir out = std::move(root);
 
+    if (type == RomFSExtractionType::SingleDiscard)
+        return out->GetSubdirectories().front();
+
     while (out->GetSubdirectories().size() == 1 && out->GetFiles().empty()) {
         if (out->GetSubdirectories().front()->GetName() == "data" &&
             type == RomFSExtractionType::Truncated)
diff --git a/src/core/file_sys/romfs.h b/src/core/file_sys/romfs.h
index 0ec404731..0f35639bc 100644
--- a/src/core/file_sys/romfs.h
+++ b/src/core/file_sys/romfs.h
@@ -33,8 +33,9 @@ struct IVFCHeader {
 static_assert(sizeof(IVFCHeader) == 0xE0, "IVFCHeader has incorrect size.");
 
 enum class RomFSExtractionType {
-    Full,      // Includes data directory
-    Truncated, // Traverses into data directory
+    Full,          // Includes data directory
+    Truncated,     // Traverses into data directory
+    SingleDiscard, // Traverses into the first subdirectory of root
 };
 
 // Converts a RomFS binary blob to VFS Filesystem

From 621b25b6be99d357c9996fcb2df77f42c7dc2001 Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Mon, 24 Dec 2018 16:19:16 -0500
Subject: [PATCH 03/15] hid: Make Hid service accessible and add GetPressState

---
 src/core/hle/service/hid/controllers/npad.cpp |   8 +
 src/core/hle/service/hid/controllers/npad.h   |   6 +
 src/core/hle/service/hid/hid.cpp              | 941 +++++++++---------
 src/core/hle/service/hid/hid.h                | 110 ++
 4 files changed, 573 insertions(+), 492 deletions(-)

diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 75fdb861a..2829f64e9 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -410,6 +410,8 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
         libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw;
         libnx_entry.pad.l_stick = pad_state.l_stick;
         libnx_entry.pad.r_stick = pad_state.r_stick;
+
+        press_state |= static_cast<u32>(pad_state.pad_states.raw);
     }
     std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(),
                 shared_memory_entries.size() * sizeof(NPadEntry));
@@ -636,6 +638,12 @@ void Controller_NPad::ClearAllControllers() {
                   });
 }
 
+u32 Controller_NPad::GetPressState() {
+    const auto res = press_state;
+    press_state = 0;
+    return res;
+}
+
 bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const {
     const bool support_handheld =
         std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), NPAD_HANDHELD) !=
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 29851f16a..6906d9ffb 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -124,6 +124,10 @@ public:
     void ConnectAllDisconnectedControllers();
     void ClearAllControllers();
 
+    // Logical OR for all buttons presses on all controllers
+    // Specifically for cheat engine and other features.
+    u32 GetPressState();
+
     static std::size_t NPadIdToIndex(u32 npad_id);
     static u32 IndexToNPad(std::size_t index);
 
@@ -292,6 +296,8 @@ private:
         bool is_connected;
     };
 
+    u32 press_state{};
+
     NPadType style{};
     std::array<NPadEntry, 10> shared_memory_entries{};
     std::array<
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 268409257..acb4152a4 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -40,119 +40,82 @@ constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 66;
 constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
 constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
 constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
-enum class HidController : std::size_t {
-    DebugPad,
-    Touchscreen,
-    Mouse,
-    Keyboard,
-    XPad,
-    Unknown1,
-    Unknown2,
-    Unknown3,
-    SixAxisSensor,
-    NPad,
-    Gesture,
 
-    MaxControllers,
-};
+IAppletResource::IAppletResource() : ServiceFramework("IAppletResource") {
+    static const FunctionInfo functions[] = {
+        {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
+    };
+    RegisterHandlers(functions);
 
-class IAppletResource final : public ServiceFramework<IAppletResource> {
-public:
-    IAppletResource() : ServiceFramework("IAppletResource") {
-        static const FunctionInfo functions[] = {
-            {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
-        };
-        RegisterHandlers(functions);
+    auto& kernel = Core::System::GetInstance().Kernel();
+    shared_mem = Kernel::SharedMemory::Create(
+        kernel, nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite,
+        Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory");
 
-        auto& kernel = Core::System::GetInstance().Kernel();
-        shared_mem = Kernel::SharedMemory::Create(
-            kernel, nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite,
-            Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory");
+    MakeController<Controller_DebugPad>(HidController::DebugPad);
+    MakeController<Controller_Touchscreen>(HidController::Touchscreen);
+    MakeController<Controller_Mouse>(HidController::Mouse);
+    MakeController<Controller_Keyboard>(HidController::Keyboard);
+    MakeController<Controller_XPad>(HidController::XPad);
+    MakeController<Controller_Stubbed>(HidController::Unknown1);
+    MakeController<Controller_Stubbed>(HidController::Unknown2);
+    MakeController<Controller_Stubbed>(HidController::Unknown3);
+    MakeController<Controller_Stubbed>(HidController::SixAxisSensor);
+    MakeController<Controller_NPad>(HidController::NPad);
+    MakeController<Controller_Gesture>(HidController::Gesture);
 
-        MakeController<Controller_DebugPad>(HidController::DebugPad);
-        MakeController<Controller_Touchscreen>(HidController::Touchscreen);
-        MakeController<Controller_Mouse>(HidController::Mouse);
-        MakeController<Controller_Keyboard>(HidController::Keyboard);
-        MakeController<Controller_XPad>(HidController::XPad);
-        MakeController<Controller_Stubbed>(HidController::Unknown1);
-        MakeController<Controller_Stubbed>(HidController::Unknown2);
-        MakeController<Controller_Stubbed>(HidController::Unknown3);
-        MakeController<Controller_Stubbed>(HidController::SixAxisSensor);
-        MakeController<Controller_NPad>(HidController::NPad);
-        MakeController<Controller_Gesture>(HidController::Gesture);
+    // Homebrew doesn't try to activate some controllers, so we activate them by default
+    GetController<Controller_NPad>(HidController::NPad).ActivateController();
+    GetController<Controller_Touchscreen>(HidController::Touchscreen).ActivateController();
 
-        // Homebrew doesn't try to activate some controllers, so we activate them by default
-        GetController<Controller_NPad>(HidController::NPad).ActivateController();
-        GetController<Controller_Touchscreen>(HidController::Touchscreen).ActivateController();
+    GetController<Controller_Stubbed>(HidController::Unknown1).SetCommonHeaderOffset(0x4c00);
+    GetController<Controller_Stubbed>(HidController::Unknown2).SetCommonHeaderOffset(0x4e00);
+    GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000);
 
-        GetController<Controller_Stubbed>(HidController::Unknown1).SetCommonHeaderOffset(0x4c00);
-        GetController<Controller_Stubbed>(HidController::Unknown2).SetCommonHeaderOffset(0x4e00);
-        GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000);
+    // Register update callbacks
+    pad_update_event =
+        CoreTiming::RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, int cycles_late) {
+            UpdateControllers(userdata, cycles_late);
+        });
 
-        // Register update callbacks
-        pad_update_event = CoreTiming::RegisterEvent(
-            "HID::UpdatePadCallback",
-            [this](u64 userdata, int cycles_late) { UpdateControllers(userdata, cycles_late); });
+    // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
 
-        // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
+    CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event);
 
-        CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event);
+    ReloadInputDevices();
+}
 
-        ReloadInputDevices();
-    }
+void IAppletResource::ActivateController(HidController controller) {
+    controllers[static_cast<size_t>(controller)]->ActivateController();
+}
 
-    void ActivateController(HidController controller) {
-        controllers[static_cast<size_t>(controller)]->ActivateController();
-    }
+void IAppletResource::DeactivateController(HidController controller) {
+    controllers[static_cast<size_t>(controller)]->DeactivateController();
+}
 
-    void DeactivateController(HidController controller) {
-        controllers[static_cast<size_t>(controller)]->DeactivateController();
-    }
+IAppletResource ::~IAppletResource() {
+    CoreTiming::UnscheduleEvent(pad_update_event, 0);
+}
 
-    template <typename T>
-    void MakeController(HidController controller) {
-        controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>();
-    }
+void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
+    LOG_DEBUG(Service_HID, "called");
 
-    template <typename T>
-    T& GetController(HidController controller) {
-        return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
-    }
+    IPC::ResponseBuilder rb{ctx, 2, 1};
+    rb.Push(RESULT_SUCCESS);
+    rb.PushCopyObjects(shared_mem);
+}
 
-    ~IAppletResource() {
-        CoreTiming::UnscheduleEvent(pad_update_event, 0);
-    }
-
-private:
-    void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
-        LOG_DEBUG(Service_HID, "called");
-
-        IPC::ResponseBuilder rb{ctx, 2, 1};
-        rb.Push(RESULT_SUCCESS);
-        rb.PushCopyObjects(shared_mem);
-    }
-
-    void UpdateControllers(u64 userdata, int cycles_late) {
-        const bool should_reload = Settings::values.is_device_reload_pending.exchange(false);
-        for (const auto& controller : controllers) {
-            if (should_reload) {
-                controller->OnLoadInputDevices();
-            }
-            controller->OnUpdate(shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
+void IAppletResource::UpdateControllers(u64 userdata, int cycles_late) {
+    const bool should_reload = Settings::values.is_device_reload_pending.exchange(false);
+    for (const auto& controller : controllers) {
+        if (should_reload) {
+            controller->OnLoadInputDevices();
         }
-
-        CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);
+        controller->OnUpdate(shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
     }
 
-    // Handle to shared memory region designated to HID service
-    Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
-
-    // CoreTiming update events
-    CoreTiming::EventType* pad_update_event;
-
-    std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
-        controllers{};
-};
+    CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);
+}
 
 class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
 public:
@@ -172,10 +135,12 @@ private:
     }
 };
 
-class Hid final : public ServiceFramework<Hid> {
-public:
-    Hid() : ServiceFramework("hid") {
-        // clang-format off
+std::shared_ptr<IAppletResource> Hid::GetAppletResource() {
+    return applet_resource;
+}
+
+Hid::Hid() : ServiceFramework("hid") {
+    // clang-format off
         static const FunctionInfo functions[] = {
             {0, &Hid::CreateAppletResource, "CreateAppletResource"},
             {1, &Hid::ActivateDebugPad, "ActivateDebugPad"},
@@ -296,475 +261,467 @@ public:
             {1000, nullptr, "SetNpadCommunicationMode"},
             {1001, nullptr, "GetNpadCommunicationMode"},
         };
-        // clang-format on
+    // clang-format on
 
-        RegisterHandlers(functions);
-    }
-    ~Hid() = default;
+    RegisterHandlers(functions);
+}
 
-private:
-    std::shared_ptr<IAppletResource> applet_resource;
+Hid::~Hid() = default;
 
-    void CreateAppletResource(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
+void Hid::CreateAppletResource(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
 
-        LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
 
-        if (applet_resource == nullptr) {
-            applet_resource = std::make_shared<IAppletResource>();
-        }
-
-        IPC::ResponseBuilder rb{ctx, 2, 0, 1};
-        rb.Push(RESULT_SUCCESS);
-        rb.PushIpcInterface<IAppletResource>(applet_resource);
+    if (applet_resource == nullptr) {
+        applet_resource = std::make_shared<IAppletResource>();
     }
 
-    void ActivateXpad(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto basic_xpad_id{rp.Pop<u32>()};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
-
-        LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}",
-                  basic_xpad_id, applet_resource_user_id);
-
-        applet_resource->ActivateController(HidController::XPad);
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
-
-    void ActivateDebugPad(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
-
-        LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+    IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+    rb.Push(RESULT_SUCCESS);
+    rb.PushIpcInterface<IAppletResource>(applet_resource);
+}
+
+void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto basic_xpad_id{rp.Pop<u32>()};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}", basic_xpad_id,
+              applet_resource_user_id);
+
+    applet_resource->ActivateController(HidController::XPad);
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
+void Hid::ActivateDebugPad(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+    applet_resource->ActivateController(HidController::DebugPad);
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
+void Hid::ActivateTouchScreen(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
 
-        applet_resource->ActivateController(HidController::DebugPad);
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
-
-    void ActivateTouchScreen(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
-
-        LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+    applet_resource->ActivateController(HidController::Touchscreen);
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
+void Hid::ActivateMouse(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
 
-        applet_resource->ActivateController(HidController::Touchscreen);
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
+    applet_resource->ActivateController(HidController::Mouse);
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
 
-    void ActivateMouse(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
+void Hid::ActivateKeyboard(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
 
-        LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
 
-        applet_resource->ActivateController(HidController::Mouse);
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
+    applet_resource->ActivateController(HidController::Keyboard);
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
 
-    void ActivateKeyboard(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
+void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto unknown{rp.Pop<u32>()};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
 
-        LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+    LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown,
+              applet_resource_user_id);
 
-        applet_resource->ActivateController(HidController::Keyboard);
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
+    applet_resource->ActivateController(HidController::Gesture);
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
 
-    void ActivateGesture(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto unknown{rp.Pop<u32>()};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
+void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
+    // Should have no effect with how our npad sets up the data
+    IPC::RequestParser rp{ctx};
+    const auto unknown{rp.Pop<u32>()};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
 
-        LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown,
-                  applet_resource_user_id);
+    LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown,
+              applet_resource_user_id);
 
-        applet_resource->ActivateController(HidController::Gesture);
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
+    applet_resource->ActivateController(HidController::NPad);
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
 
-    void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
-        // Should have no effect with how our npad sets up the data
-        IPC::RequestParser rp{ctx};
-        const auto unknown{rp.Pop<u32>()};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
+void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto handle{rp.Pop<u32>()};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
 
-        LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown,
-                  applet_resource_user_id);
+    LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
+                applet_resource_user_id);
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
 
-        applet_resource->ActivateController(HidController::NPad);
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
+void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto handle{rp.Pop<u32>()};
+    const auto drift_mode{rp.Pop<u32>()};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
 
-    void StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto handle{rp.Pop<u32>()};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
+    LOG_WARNING(Service_HID,
+                "(STUBBED) called, handle={}, drift_mode={}, applet_resource_user_id={}", handle,
+                drift_mode, applet_resource_user_id);
 
-        LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
-                    applet_resource_user_id);
-
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
 
-    void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto handle{rp.Pop<u32>()};
-        const auto drift_mode{rp.Pop<u32>()};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
+void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto handle{rp.Pop<u32>()};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
 
-        LOG_WARNING(Service_HID,
-                    "(STUBBED) called, handle={}, drift_mode={}, applet_resource_user_id={}",
-                    handle, drift_mode, applet_resource_user_id);
+    LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
+                applet_resource_user_id);
+
+    IPC::ResponseBuilder rb{ctx, 3};
+    rb.Push(RESULT_SUCCESS);
+    // TODO (Hexagon12): Properly implement reading gyroscope values from controllers.
+    rb.Push(true);
+}
 
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
+void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto supported_styleset{rp.Pop<u32>()};
 
-    void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto handle{rp.Pop<u32>()};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
+    LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset);
 
-        LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
-                    applet_resource_user_id);
-
-        IPC::ResponseBuilder rb{ctx, 3};
-        rb.Push(RESULT_SUCCESS);
-        // TODO (Hexagon12): Properly implement reading gyroscope values from controllers.
-        rb.Push(true);
-    }
+    applet_resource->GetController<Controller_NPad>(HidController::NPad)
+        .SetSupportedStyleSet({supported_styleset});
 
-    void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto supported_styleset{rp.Pop<u32>()};
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
 
-        LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset);
+void Hid::GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
 
-        applet_resource->GetController<Controller_NPad>(HidController::NPad)
-            .SetSupportedStyleSet({supported_styleset});
-
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
+
+    IPC::ResponseBuilder rb{ctx, 3};
+    rb.Push(RESULT_SUCCESS);
+    rb.Push<u32>(controller.GetSupportedStyleSet().raw);
+}
 
-    void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
-
-        LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
-        auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
-
-        IPC::ResponseBuilder rb{ctx, 3};
-        rb.Push(RESULT_SUCCESS);
-        rb.Push<u32>(controller.GetSupportedStyleSet().raw);
-    }
-
-    void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
-
-        LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
-        applet_resource->GetController<Controller_NPad>(HidController::NPad)
-            .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
+void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+    applet_resource->GetController<Controller_NPad>(HidController::NPad)
+        .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
 
-    void ActivateNpad(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
-
-        LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-        applet_resource->ActivateController(HidController::NPad);
-    }
-
-    void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto npad_id{rp.Pop<u32>()};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
-        const auto unknown{rp.Pop<u64>()};
-
-        LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}",
-                  npad_id, applet_resource_user_id, unknown);
-
-        IPC::ResponseBuilder rb{ctx, 2, 1};
-        rb.Push(RESULT_SUCCESS);
-        rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad)
-                               .GetStyleSetChangedEvent());
-    }
+void Hid::ActivateNpad(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
 
-    void DisconnectNpad(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto npad_id{rp.Pop<u32>()};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
-
-        LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id,
-                  applet_resource_user_id);
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+    applet_resource->ActivateController(HidController::NPad);
+}
 
-        applet_resource->GetController<Controller_NPad>(HidController::NPad)
-            .DisconnectNPad(npad_id);
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
+void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto npad_id{rp.Pop<u32>()};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+    const auto unknown{rp.Pop<u64>()};
 
-    void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto npad_id{rp.Pop<u32>()};
+    LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}", npad_id,
+              applet_resource_user_id, unknown);
 
-        LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id);
+    IPC::ResponseBuilder rb{ctx, 2, 1};
+    rb.Push(RESULT_SUCCESS);
+    rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad)
+                           .GetStyleSetChangedEvent());
+}
 
-        IPC::ResponseBuilder rb{ctx, 4};
-        rb.Push(RESULT_SUCCESS);
-        rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad)
-                            .GetLedPattern(npad_id)
-                            .raw);
-    }
+void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto npad_id{rp.Pop<u32>()};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
 
-    void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
-        const auto hold_type{rp.Pop<u64>()};
+    LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id,
+              applet_resource_user_id);
 
-        LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}",
-                  applet_resource_user_id, hold_type);
+    applet_resource->GetController<Controller_NPad>(HidController::NPad).DisconnectNPad(npad_id);
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
 
-        auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
-        controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type});
+void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto npad_id{rp.Pop<u32>()};
 
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
+    LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id);
 
-    void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
-
-        LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
-        const auto& controller =
-            applet_resource->GetController<Controller_NPad>(HidController::NPad);
-        IPC::ResponseBuilder rb{ctx, 4};
-        rb.Push(RESULT_SUCCESS);
-        rb.Push<u64>(static_cast<u64>(controller.GetHoldType()));
-    }
+    IPC::ResponseBuilder rb{ctx, 4};
+    rb.Push(RESULT_SUCCESS);
+    rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad)
+                        .GetLedPattern(npad_id)
+                        .raw);
+}
 
-    void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto npad_id{rp.Pop<u32>()};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
-
-        LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
-                    npad_id, applet_resource_user_id);
-
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
-
-    void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
-
-        LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
-        applet_resource->GetController<Controller_NPad>(HidController::NPad)
-            .SetVibrationEnabled(true);
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
-
-    void EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
-        LOG_DEBUG(Service_HID, "called");
-
-        applet_resource->GetController<Controller_NPad>(HidController::NPad)
-            .SetVibrationEnabled(false);
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
-
-    void SendVibrationValue(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto controller_id{rp.Pop<u32>()};
-        const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
-
-        LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}",
-                  controller_id, applet_resource_user_id);
-
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-
-        applet_resource->GetController<Controller_NPad>(HidController::NPad)
-            .VibrateController({controller_id}, {vibration_values});
-    }
-
-    void SendVibrationValues(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
-
-        LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
-        const auto controllers = ctx.ReadBuffer(0);
-        const auto vibrations = ctx.ReadBuffer(1);
+void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+    const auto hold_type{rp.Pop<u64>()};
 
-        std::vector<u32> controller_list(controllers.size() / sizeof(u32));
-        std::vector<Controller_NPad::Vibration> vibration_list(vibrations.size() /
-                                                               sizeof(Controller_NPad::Vibration));
-
-        std::memcpy(controller_list.data(), controllers.data(), controllers.size());
-        std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size());
-        std::transform(controller_list.begin(), controller_list.end(), controller_list.begin(),
-                       [](u32 controller_id) { return controller_id - 3; });
-
-        applet_resource->GetController<Controller_NPad>(HidController::NPad)
-            .VibrateController(controller_list, vibration_list);
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}",
+              applet_resource_user_id, hold_type);
 
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
+    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
+    controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type});
 
-    void GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto controller_id{rp.Pop<u32>()};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
 
-        LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}",
-                  controller_id, applet_resource_user_id);
+void Hid::GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
 
-        IPC::ResponseBuilder rb{ctx, 6};
-        rb.Push(RESULT_SUCCESS);
-        rb.PushRaw<Controller_NPad::Vibration>(
-            applet_resource->GetController<Controller_NPad>(HidController::NPad)
-                .GetLastVibration());
-    }
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
 
-    void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto npad_id{rp.Pop<u32>()};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
-
-        LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id,
-                  applet_resource_user_id);
+    const auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
+    IPC::ResponseBuilder rb{ctx, 4};
+    rb.Push(RESULT_SUCCESS);
+    rb.Push<u64>(static_cast<u64>(controller.GetHoldType()));
+}
 
-        auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
-        controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual);
+void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto npad_id{rp.Pop<u32>()};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", npad_id,
+                applet_resource_user_id);
 
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
 
-    void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto unknown_1{rp.Pop<u32>()};
-        const auto unknown_2{rp.Pop<u32>()};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
+void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(true);
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
 
-        LOG_WARNING(Service_HID,
-                    "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}",
-                    unknown_1, unknown_2, applet_resource_user_id);
+void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
+    LOG_DEBUG(Service_HID, "called");
+
+    applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(false);
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
 
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
+void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto controller_id{rp.Pop<u32>()};
+    const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
 
-    void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
-        const auto mode{rp.Pop<u64>()};
+    LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id,
+              applet_resource_user_id);
 
-        LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, mode={}",
-                    applet_resource_user_id, mode);
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+
+    applet_resource->GetController<Controller_NPad>(HidController::NPad)
+        .VibrateController({controller_id}, {vibration_values});
+}
 
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
+void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
 
-    void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
-        LOG_DEBUG(Service_HID, "called");
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
 
-        IPC::ResponseBuilder rb{ctx, 4};
-        rb.Push(RESULT_SUCCESS);
-        rb.Push<u32>(1);
-        rb.Push<u32>(0);
-    }
+    const auto controllers = ctx.ReadBuffer(0);
+    const auto vibrations = ctx.ReadBuffer(1);
 
-    void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
-        LOG_DEBUG(Service_HID, "called");
+    std::vector<u32> controller_list(controllers.size() / sizeof(u32));
+    std::vector<Controller_NPad::Vibration> vibration_list(vibrations.size() /
+                                                           sizeof(Controller_NPad::Vibration));
 
-        IPC::ResponseBuilder rb{ctx, 2, 0, 1};
-        rb.Push(RESULT_SUCCESS);
-        rb.PushIpcInterface<IActiveVibrationDeviceList>();
-    }
+    std::memcpy(controller_list.data(), controllers.data(), controllers.size());
+    std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size());
+    std::transform(controller_list.begin(), controller_list.end(), controller_list.begin(),
+                   [](u32 controller_id) { return controller_id - 3; });
 
-    void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
+    applet_resource->GetController<Controller_NPad>(HidController::NPad)
+        .VibrateController(controller_list, vibration_list);
 
-        LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
-                    applet_resource_user_id);
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
 
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
+void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto controller_id{rp.Pop<u32>()};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
 
-    void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto handle{rp.Pop<u32>()};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
-
-        LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
-                    applet_resource_user_id);
+    LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id,
+              applet_resource_user_id);
 
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
+    IPC::ResponseBuilder rb{ctx, 6};
+    rb.Push(RESULT_SUCCESS);
+    rb.PushRaw<Controller_NPad::Vibration>(
+        applet_resource->GetController<Controller_NPad>(HidController::NPad).GetLastVibration());
+}
 
-    void StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto handle{rp.Pop<u32>()};
+void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto npad_id{rp.Pop<u32>()};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
 
-        LOG_WARNING(Service_HID, "(STUBBED) called, handle={}", handle);
+    LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id,
+              applet_resource_user_id);
 
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
+    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
+    controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual);
 
-    void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto applet_resource_user_id{rp.Pop<u64>()};
-        const auto unknown{rp.Pop<u32>()};
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
 
-        LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, unknown={}",
-                    applet_resource_user_id, unknown);
+void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto unknown_1{rp.Pop<u32>()};
+    const auto unknown_2{rp.Pop<u32>()};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
 
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
+    LOG_WARNING(Service_HID,
+                "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}",
+                unknown_1, unknown_2, applet_resource_user_id);
 
-    void SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
-        IPC::RequestParser rp{ctx};
-        const auto unknown{rp.Pop<u32>()};
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
 
-        LOG_WARNING(Service_HID, "(STUBBED) called, unknown={}", unknown);
+void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+    const auto mode{rp.Pop<u64>()};
 
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(RESULT_SUCCESS);
-    }
-};
+    LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, mode={}",
+                applet_resource_user_id, mode);
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
+void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
+    LOG_DEBUG(Service_HID, "called");
+
+    IPC::ResponseBuilder rb{ctx, 4};
+    rb.Push(RESULT_SUCCESS);
+    rb.Push<u32>(1);
+    rb.Push<u32>(0);
+}
+
+void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
+    LOG_DEBUG(Service_HID, "called");
+
+    IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+    rb.Push(RESULT_SUCCESS);
+    rb.PushIpcInterface<IActiveVibrationDeviceList>();
+}
+
+void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
+                applet_resource_user_id);
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
+void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto handle{rp.Pop<u32>()};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
+                applet_resource_user_id);
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
+void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto handle{rp.Pop<u32>()};
+
+    LOG_WARNING(Service_HID, "(STUBBED) called, handle={}", handle);
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
+void Hid::SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+    const auto unknown{rp.Pop<u32>()};
+
+    LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, unknown={}",
+                applet_resource_user_id, unknown);
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
+void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto unknown{rp.Pop<u32>()};
+
+    LOG_WARNING(Service_HID, "(STUBBED) called, unknown={}", unknown);
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
 
 class HidDbg final : public ServiceFramework<HidDbg> {
 public:
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 773035460..615d4e6d8 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -3,6 +3,15 @@
 // Refer to the license.txt file included.
 
 #pragma once
+#include "core/hle/service/service.h"
+
+namespace CoreTiming {
+struct EventType;
+}
+
+namespace Kernel {
+class SharedMemory;
+}
 
 namespace SM {
 class ServiceManager;
@@ -10,6 +19,107 @@ class ServiceManager;
 
 namespace Service::HID {
 
+class ControllerBase;
+
+enum class HidController : std::size_t {
+    DebugPad,
+    Touchscreen,
+    Mouse,
+    Keyboard,
+    XPad,
+    Unknown1,
+    Unknown2,
+    Unknown3,
+    SixAxisSensor,
+    NPad,
+    Gesture,
+
+    MaxControllers,
+};
+
+class IAppletResource final : public ServiceFramework<IAppletResource> {
+public:
+    IAppletResource();
+    ~IAppletResource() override;
+
+    void ActivateController(HidController controller);
+    void DeactivateController(HidController controller);
+
+    template <typename T>
+    T& GetController(HidController controller) {
+        return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
+    }
+
+    template <typename T>
+    const T& GetController(HidController controller) const {
+        return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
+    }
+
+private:
+    template <typename T>
+    void MakeController(HidController controller) {
+        controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>();
+    }
+
+    void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
+    void UpdateControllers(u64 userdata, int cycles_late);
+
+    Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
+
+    CoreTiming::EventType* pad_update_event;
+
+    std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
+        controllers{};
+};
+
+class Hid final : public ServiceFramework<Hid> {
+public:
+    Hid();
+    ~Hid() override;
+
+    std::shared_ptr<IAppletResource> GetAppletResource();
+
+private:
+    void CreateAppletResource(Kernel::HLERequestContext& ctx);
+    void ActivateXpad(Kernel::HLERequestContext& ctx);
+    void ActivateDebugPad(Kernel::HLERequestContext& ctx);
+    void ActivateTouchScreen(Kernel::HLERequestContext& ctx);
+    void ActivateMouse(Kernel::HLERequestContext& ctx);
+    void ActivateKeyboard(Kernel::HLERequestContext& ctx);
+    void ActivateGesture(Kernel::HLERequestContext& ctx);
+    void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx);
+    void StartSixAxisSensor(Kernel::HLERequestContext& ctx);
+    void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
+    void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx);
+    void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);
+    void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);
+    void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx);
+    void ActivateNpad(Kernel::HLERequestContext& ctx);
+    void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx);
+    void DisconnectNpad(Kernel::HLERequestContext& ctx);
+    void GetPlayerLedPattern(Kernel::HLERequestContext& ctx);
+    void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx);
+    void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx);
+    void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx);
+    void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx);
+    void EndPermitVibrationSession(Kernel::HLERequestContext& ctx);
+    void SendVibrationValue(Kernel::HLERequestContext& ctx);
+    void SendVibrationValues(Kernel::HLERequestContext& ctx);
+    void GetActualVibrationValue(Kernel::HLERequestContext& ctx);
+    void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx);
+    void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx);
+    void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx);
+    void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx);
+    void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx);
+    void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
+    void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
+    void StopSixAxisSensor(Kernel::HLERequestContext& ctx);
+    void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx);
+    void SetPalmaBoostMode(Kernel::HLERequestContext& ctx);
+
+    std::shared_ptr<IAppletResource> applet_resource;
+};
+
 /// Reload input devices. Used when input configuration changed
 void ReloadInputDevices();
 

From 4c20a3982807386a2e5fc6f536498b73e6f4f6ce Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Mon, 24 Dec 2018 16:19:41 -0500
Subject: [PATCH 04/15] loader: Add accessor for Manual RomFS

---
 src/core/loader/loader.h | 9 +++++++++
 src/core/loader/nsp.cpp  | 8 ++++++++
 src/core/loader/nsp.h    | 2 ++
 src/core/loader/xci.cpp  | 9 +++++++++
 src/core/loader/xci.h    | 2 ++
 5 files changed, 30 insertions(+)

diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 30eacd803..01f984098 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -259,6 +259,15 @@ public:
         return ResultStatus::ErrorNotImplemented;
     }
 
+    /**
+     * Get the RomFS of the manual of the application
+     * @param file The raw manual RomFS of the game
+     * @return ResultStatus result of function
+     */
+    virtual ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) {
+        return ResultStatus::ErrorNotImplemented;
+    }
+
 protected:
     FileSys::VirtualFile file;
     bool is_loaded = false;
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp
index 4d4b44571..7fcb12aa2 100644
--- a/src/core/loader/nsp.cpp
+++ b/src/core/loader/nsp.cpp
@@ -158,4 +158,12 @@ ResultStatus AppLoader_NSP::ReadControlData(FileSys::NACP& nacp) {
     nacp = *nacp_file;
     return ResultStatus::Success;
 }
+
+ResultStatus AppLoader_NSP::ReadManualRomFS(FileSys::VirtualFile& file) {
+    const auto nca = nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Manual);
+    if (nsp->GetStatus() != ResultStatus::Success || nca == nullptr)
+        return ResultStatus::ErrorNoRomFS;
+    file = nca->GetRomFS();
+    return file == nullptr ? ResultStatus::ErrorNoRomFS : ResultStatus::Success;
+}
 } // namespace Loader
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h
index 32eb0193d..0841578d4 100644
--- a/src/core/loader/nsp.h
+++ b/src/core/loader/nsp.h
@@ -44,6 +44,8 @@ public:
     ResultStatus ReadIcon(std::vector<u8>& buffer) override;
     ResultStatus ReadTitle(std::string& title) override;
     ResultStatus ReadControlData(FileSys::NACP& nacp) override;
+    ResultStatus ReadDeveloper(std::string& developer) override;
+    ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) override;
 
 private:
     std::unique_ptr<FileSys::NSP> nsp;
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index e67e43c69..ff60a3756 100644
--- a/src/core/loader/xci.cpp
+++ b/src/core/loader/xci.cpp
@@ -128,4 +128,13 @@ ResultStatus AppLoader_XCI::ReadControlData(FileSys::NACP& control) {
     return ResultStatus::Success;
 }
 
+ResultStatus AppLoader_XCI::ReadManualRomFS(FileSys::VirtualFile& file) {
+    const auto nca = xci->GetSecurePartitionNSP()->GetNCA(xci->GetProgramTitleID(),
+                                                          FileSys::ContentRecordType::Manual);
+    if (xci->GetStatus() != ResultStatus::Success || nca == nullptr)
+        return ResultStatus::ErrorXCIMissingPartition;
+    file = nca->GetRomFS();
+    return file == nullptr ? ResultStatus::ErrorNoRomFS : ResultStatus::Success;
+}
+
 } // namespace Loader
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h
index 9d3923f62..3e6e19a44 100644
--- a/src/core/loader/xci.h
+++ b/src/core/loader/xci.h
@@ -44,6 +44,8 @@ public:
     ResultStatus ReadIcon(std::vector<u8>& buffer) override;
     ResultStatus ReadTitle(std::string& title) override;
     ResultStatus ReadControlData(FileSys::NACP& control) override;
+    ResultStatus ReadDeveloper(std::string& developer) override;
+    ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) override;
 
 private:
     std::unique_ptr<FileSys::XCI> xci;

From 69f622be363418fcf61e79a0aed1fd06523ff690 Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Mon, 24 Dec 2018 16:21:12 -0500
Subject: [PATCH 05/15] applets: Implement LibAppletOff (Web) applet

---
 src/core/CMakeLists.txt                       |   2 +
 src/core/hle/service/am/am.cpp                |   4 +
 .../hle/service/am/applets/web_browser.cpp    | 184 ++++++++++++++++++
 src/core/hle/service/am/applets/web_browser.h |  44 +++++
 4 files changed, 234 insertions(+)
 create mode 100644 src/core/hle/service/am/applets/web_browser.cpp
 create mode 100644 src/core/hle/service/am/applets/web_browser.h

diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index f38271336..82c934f7e 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -172,6 +172,8 @@ add_library(core STATIC
     hle/service/am/applets/software_keyboard.h
     hle/service/am/applets/stub_applet.cpp
     hle/service/am/applets/stub_applet.h
+    hle/service/am/applets/web_browser.cpp
+    hle/service/am/applets/web_browser.h
     hle/service/am/idle.cpp
     hle/service/am/idle.h
     hle/service/am/omm.cpp
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 512386422..c851e5420 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -23,6 +23,7 @@
 #include "core/hle/service/am/applets/profile_select.h"
 #include "core/hle/service/am/applets/software_keyboard.h"
 #include "core/hle/service/am/applets/stub_applet.h"
+#include "core/hle/service/am/applets/web_browser.h"
 #include "core/hle/service/am/idle.h"
 #include "core/hle/service/am/omm.h"
 #include "core/hle/service/am/spsm.h"
@@ -43,6 +44,7 @@ constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7};
 enum class AppletId : u32 {
     ProfileSelect = 0x10,
     SoftwareKeyboard = 0x11,
+    LibAppletOff = 0x17,
 };
 
 constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA;
@@ -782,6 +784,8 @@ static std::shared_ptr<Applets::Applet> GetAppletFromId(AppletId id) {
         return std::make_shared<Applets::ProfileSelect>();
     case AppletId::SoftwareKeyboard:
         return std::make_shared<Applets::SoftwareKeyboard>();
+    case AppletId::LibAppletOff:
+        return std::make_shared<Applets::WebBrowser>();
     default:
         LOG_ERROR(Service_AM, "Unimplemented AppletId [{:08X}]! -- Falling back to stub!",
                   static_cast<u32>(id));
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp
new file mode 100644
index 000000000..53118324b
--- /dev/null
+++ b/src/core/hle/service/am/applets/web_browser.cpp
@@ -0,0 +1,184 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/common_paths.h"
+#include "common/hex_util.h"
+#include "common/logging/backend.h"
+#include "common/string_util.h"
+#include "core/core.h"
+#include "core/file_sys/content_archive.h"
+#include "core/file_sys/mode.h"
+#include "core/file_sys/nca_metadata.h"
+#include "core/file_sys/registered_cache.h"
+#include "core/file_sys/romfs.h"
+#include "core/file_sys/romfs_factory.h"
+#include "core/file_sys/vfs_types.h"
+#include "core/frontend/applets/web_browser.h"
+#include "core/hle/kernel/process.h"
+#include "core/hle/service/am/applets/web_browser.h"
+#include "core/hle/service/filesystem/filesystem.h"
+#include "core/loader/loader.h"
+
+namespace Service::AM::Applets {
+
+// TODO(DarkLordZach): There are other arguments in the WebBuffer structure that are currently not
+// parsed, for example footer mode and left stick mode. Some of these are not particularly relevant,
+// but some may be worth an implementation.
+constexpr u16 WEB_ARGUMENT_URL_TYPE = 0x6;
+
+struct WebBufferHeader {
+    u16 count;
+    INSERT_PADDING_BYTES(6);
+};
+static_assert(sizeof(WebBufferHeader) == 0x8, "WebBufferHeader has incorrect size.");
+
+struct WebArgumentHeader {
+    u16 type;
+    u16 size;
+    u32 offset;
+};
+static_assert(sizeof(WebArgumentHeader) == 0x8, "WebArgumentHeader has incorrect size.");
+
+struct WebArgumentResult {
+    u32 result_code;
+    std::array<char, 0x1000> last_url;
+    u64 last_url_size;
+};
+static_assert(sizeof(WebArgumentResult) == 0x1010, "WebArgumentResult has incorrect size.");
+
+static std::vector<u8> GetArgumentDataForTagType(const std::vector<u8>& data, u16 type) {
+    WebBufferHeader header;
+    std::memcpy(&header, data.data(), sizeof(WebBufferHeader));
+
+    u64 offset = sizeof(WebBufferHeader);
+    for (u16 i = 0; i < header.count; ++i) {
+        WebArgumentHeader arg;
+        std::memcpy(&arg, data.data() + offset, sizeof(WebArgumentHeader));
+        offset += sizeof(WebArgumentHeader);
+
+        if (arg.type == type) {
+            std::vector<u8> out(arg.size);
+            offset += arg.offset;
+            std::memcpy(out.data(), data.data() + offset, out.size());
+            return out;
+        }
+
+        offset += arg.offset + arg.size;
+    }
+
+    return {};
+}
+
+static FileSys::VirtualFile GetManualRomFS() {
+    auto& loader{Core::System::GetInstance().GetAppLoader()};
+
+    FileSys::VirtualFile out;
+    if (loader.ReadManualRomFS(out) == Loader::ResultStatus::Success)
+        return out;
+
+    const auto& installed{FileSystem::GetUnionContents()};
+    const auto res = installed.GetEntry(Core::System::GetInstance().CurrentProcess()->GetTitleID(),
+                                        FileSys::ContentRecordType::Manual);
+
+    if (res != nullptr)
+        return res->GetRomFS();
+    return nullptr;
+}
+
+WebBrowser::WebBrowser() = default;
+
+WebBrowser::~WebBrowser() = default;
+
+void WebBrowser::Initialize() {
+    complete = false;
+    temporary_dir.clear();
+    filename.clear();
+    status = RESULT_SUCCESS;
+
+    Applet::Initialize();
+
+    const auto web_arg_storage = broker.PopNormalDataToApplet();
+    ASSERT(web_arg_storage != nullptr);
+    const auto& web_arg = web_arg_storage->GetData();
+
+    LOG_CRITICAL(Service_AM, "{}", Common::HexVectorToString(web_arg));
+
+    const auto url_data = GetArgumentDataForTagType(web_arg, WEB_ARGUMENT_URL_TYPE);
+    filename = Common::StringFromFixedZeroTerminatedBuffer(
+        reinterpret_cast<const char*>(url_data.data()), url_data.size());
+
+    temporary_dir = FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) +
+                                               "web_applet_manual",
+                                           FileUtil::DirectorySeparator::PlatformDefault);
+    FileUtil::DeleteDirRecursively(temporary_dir);
+
+    manual_romfs = GetManualRomFS();
+    if (manual_romfs == nullptr) {
+        status = ResultCode(-1);
+        LOG_ERROR(Service_AM, "Failed to find manual for current process!");
+    }
+
+    filename =
+        FileUtil::SanitizePath(temporary_dir + DIR_SEP + "html-document" + DIR_SEP + filename,
+                               FileUtil::DirectorySeparator::PlatformDefault);
+}
+
+bool WebBrowser::TransactionComplete() const {
+    return complete;
+}
+
+ResultCode WebBrowser::GetStatus() const {
+    return status;
+}
+
+void WebBrowser::ExecuteInteractive() {
+    UNIMPLEMENTED_MSG(Service_AM, "Unexpected interactive data recieved!");
+}
+
+void WebBrowser::Execute() {
+    if (complete)
+        return;
+
+    if (status != RESULT_SUCCESS) {
+        complete = true;
+        return;
+    }
+
+    const auto& frontend{Core::System::GetInstance().GetWebBrowser()};
+
+    frontend.OpenPage(
+        filename, [this] { UnpackRomFS(); }, [this] { Finalize(); });
+}
+
+void WebBrowser::UnpackRomFS() {
+    if (unpacked)
+        return;
+
+    ASSERT(manual_romfs != nullptr);
+    const auto dir =
+        FileSys::ExtractRomFS(manual_romfs, FileSys::RomFSExtractionType::SingleDiscard);
+    const auto& vfs{Core::System::GetInstance().GetFilesystem()};
+    const auto temp_dir = vfs->CreateDirectory(temporary_dir, FileSys::Mode::ReadWrite);
+    FileSys::VfsRawCopyD(dir, temp_dir);
+
+    unpacked = true;
+}
+
+void WebBrowser::Finalize() {
+    complete = true;
+
+    WebArgumentResult out{};
+    out.result_code = 0;
+    out.last_url_size = 0;
+
+    std::vector<u8> data(sizeof(WebArgumentResult));
+    std::memcpy(data.data(), &out, sizeof(WebArgumentResult));
+
+    broker.PushNormalDataFromApplet(IStorage{data});
+    broker.SignalStateChanged();
+
+    FileUtil::DeleteDirRecursively(temporary_dir);
+}
+
+} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h
new file mode 100644
index 000000000..b9e228fac
--- /dev/null
+++ b/src/core/hle/service/am/applets/web_browser.h
@@ -0,0 +1,44 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/file_sys/vfs_types.h"
+#include "core/hle/service/am/am.h"
+#include "core/hle/service/am/applets/applets.h"
+
+namespace Service::AM::Applets {
+
+class WebBrowser final : public Applet {
+public:
+    WebBrowser();
+    ~WebBrowser() override;
+
+    void Initialize() override;
+
+    bool TransactionComplete() const override;
+    ResultCode GetStatus() const override;
+    void ExecuteInteractive() override;
+    void Execute() override;
+
+    // Callback to be fired when the frontend needs the manual RomFS unpacked to temporary
+    // directory. This is a blocking call and may take a while as some manuals can be up to 100MB in
+    // size. Attempting to access files at filename before invocation is likely to not work.
+    void UnpackRomFS();
+
+    // Callback to be fired when the frontend is finished browsing. This will delete the temporary
+    // manual RomFS extracted files, so ensure this is only called at actual finalization.
+    void Finalize();
+
+private:
+    bool complete = false;
+    bool unpacked = false;
+    ResultCode status = RESULT_SUCCESS;
+
+    FileSys::VirtualFile manual_romfs;
+    std::string temporary_dir;
+    std::string filename;
+};
+
+} // namespace Service::AM::Applets

From 85a3368e6d73e84478b2a168227250769bf7168f Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Mon, 24 Dec 2018 16:21:41 -0500
Subject: [PATCH 06/15] frontend: Add frontend responder for web browser

---
 src/core/frontend/applets/web_browser.cpp | 24 +++++++++++++++++++
 src/core/frontend/applets/web_browser.h   | 28 +++++++++++++++++++++++
 2 files changed, 52 insertions(+)
 create mode 100644 src/core/frontend/applets/web_browser.cpp
 create mode 100644 src/core/frontend/applets/web_browser.h

diff --git a/src/core/frontend/applets/web_browser.cpp b/src/core/frontend/applets/web_browser.cpp
new file mode 100644
index 000000000..6a36b4b8f
--- /dev/null
+++ b/src/core/frontend/applets/web_browser.cpp
@@ -0,0 +1,24 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/logging/log.h"
+#include "core/frontend/applets/web_browser.h"
+
+namespace Core::Frontend {
+
+WebBrowserApplet::~WebBrowserApplet() = default;
+
+DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default;
+
+void DefaultWebBrowserApplet::OpenPage(std::string_view filename,
+                                       std::function<void()> unpack_romfs_callback,
+                                       std::function<void()> finished_callback) const {
+    LOG_INFO(Service_AM,
+             "(STUBBED) called - No suitable web browser implementation found to open website page "
+             "at '{}'!",
+             filename);
+    finished_callback();
+}
+
+} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/web_browser.h b/src/core/frontend/applets/web_browser.h
new file mode 100644
index 000000000..41d272d26
--- /dev/null
+++ b/src/core/frontend/applets/web_browser.h
@@ -0,0 +1,28 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <functional>
+#include <string_view>
+
+namespace Core::Frontend {
+
+class WebBrowserApplet {
+public:
+    virtual ~WebBrowserApplet();
+
+    virtual void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback,
+                          std::function<void()> finished_callback) const = 0;
+};
+
+class DefaultWebBrowserApplet final : public WebBrowserApplet {
+public:
+    ~DefaultWebBrowserApplet() override;
+
+    void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback,
+                  std::function<void()> finished_callback) const override;
+};
+
+} // namespace Core::Frontend

From 32bfa92c7137d20f2c105595831b3c8cefe40326 Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Mon, 24 Dec 2018 16:22:07 -0500
Subject: [PATCH 07/15] core: Add getter and setter for WebBrowserApplet
 frontend

---
 src/core/CMakeLists.txt                            |  2 ++
 src/core/core.cpp                                  | 13 +++++++++++++
 src/core/core.h                                    |  7 ++++++-
 src/core/hle/service/am/applets/profile_select.cpp |  2 +-
 4 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 82c934f7e..94a576508 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -87,6 +87,8 @@ add_library(core STATIC
     frontend/applets/profile_select.h
     frontend/applets/software_keyboard.cpp
     frontend/applets/software_keyboard.h
+    frontend/applets/web_browser.cpp
+    frontend/applets/web_browser.h
     frontend/emu_window.cpp
     frontend/emu_window.h
     frontend/framebuffer_layout.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index fd10199ec..373dff2e6 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -31,7 +31,9 @@
 #include "core/loader/loader.h"
 #include "core/perf_stats.h"
 #include "core/telemetry_session.h"
+#include "frontend/applets/profile_select.h"
 #include "frontend/applets/software_keyboard.h"
+#include "frontend/applets/web_browser.h"
 #include "video_core/debug_utils/debug_utils.h"
 #include "video_core/gpu.h"
 #include "video_core/renderer_base.h"
@@ -103,6 +105,8 @@ struct System::Impl {
             profile_selector = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
         if (software_keyboard == nullptr)
             software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
+        if (web_browser == nullptr)
+            web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
 
         auto main_process = Kernel::Process::Create(kernel, "main");
         kernel.MakeCurrentProcess(main_process.get());
@@ -233,6 +237,7 @@ struct System::Impl {
     /// Frontend applets
     std::unique_ptr<Core::Frontend::ProfileSelectApplet> profile_selector;
     std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard;
+    std::unique_ptr<Core::Frontend::WebBrowserApplet> web_browser;
 
     /// Service manager
     std::shared_ptr<Service::SM::ServiceManager> service_manager;
@@ -443,6 +448,14 @@ const Core::Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() cons
     return *impl->software_keyboard;
 }
 
+void System::SetWebBrowser(std::unique_ptr<Core::Frontend::WebBrowserApplet> applet) {
+    impl->web_browser = std::move(applet);
+}
+
+const Core::Frontend::WebBrowserApplet& System::GetWebBrowser() const {
+    return *impl->web_browser;
+}
+
 System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
     return impl->Init(*this, emu_window);
 }
diff --git a/src/core/core.h b/src/core/core.h
index 869921493..a53dbb4d4 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -11,11 +11,12 @@
 #include "common/common_types.h"
 #include "core/file_sys/vfs_types.h"
 #include "core/hle/kernel/object.h"
-#include "frontend/applets/profile_select.h"
 
 namespace Core::Frontend {
 class EmuWindow;
+class ProfileSelectApplet;
 class SoftwareKeyboardApplet;
+class WebBrowserApplet;
 } // namespace Core::Frontend
 
 namespace FileSys {
@@ -250,6 +251,10 @@ public:
 
     const Core::Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const;
 
+    void SetWebBrowser(std::unique_ptr<Core::Frontend::WebBrowserApplet> applet);
+
+    const Core::Frontend::WebBrowserApplet& GetWebBrowser() const;
+
 private:
     System();
 
diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp
index 4c7b45454..14e2a1fee 100644
--- a/src/core/hle/service/am/applets/profile_select.cpp
+++ b/src/core/hle/service/am/applets/profile_select.cpp
@@ -7,7 +7,7 @@
 #include "common/assert.h"
 #include "common/string_util.h"
 #include "core/core.h"
-#include "core/frontend/applets/software_keyboard.h"
+#include "core/frontend/applets/profile_select.h"
 #include "core/hle/service/am/am.h"
 #include "core/hle/service/am/applets/profile_select.h"
 

From e00e1fc755501018c4106e8453045037d5b9e3ee Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Mon, 24 Dec 2018 16:22:49 -0500
Subject: [PATCH 08/15] qt: Implement Qt frontend to web browser Using a custom
 reimplementation of QWebEngineView and an injector script.

---
 src/yuzu/applets/web_browser.cpp | 109 +++++++++++++++++++++++++++++++
 src/yuzu/applets/web_browser.h   |  45 +++++++++++++
 2 files changed, 154 insertions(+)
 create mode 100644 src/yuzu/applets/web_browser.cpp
 create mode 100644 src/yuzu/applets/web_browser.h

diff --git a/src/yuzu/applets/web_browser.cpp b/src/yuzu/applets/web_browser.cpp
new file mode 100644
index 000000000..e1a34bb5f
--- /dev/null
+++ b/src/yuzu/applets/web_browser.cpp
@@ -0,0 +1,109 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <mutex>
+
+#include <QKeyEvent>
+
+#include "core/hle/lock.h"
+#include "yuzu/applets/web_browser.h"
+#include "yuzu/main.h"
+
+constexpr char NX_SHIM_INJECT_SCRIPT[] = R"(
+    window.nx = {};
+    window.nx.playReport = {};
+    window.nx.playReport.setCounterSetIdentifier = function () {
+        console.log("nx.footer.setCounterSetIdentifier called - unimplemented");
+    };
+
+    window.nx.playReport.incrementCounter = function () {
+        console.log("nx.footer.incrementCounter called - unimplemented");
+    };
+
+    window.nx.footer = {};
+    window.nx.footer.unsetAssign = function () {
+        console.log("nx.footer.unsetAssign called - unimplemented");
+    };
+
+    var yuzu_key_callbacks = [];
+    window.nx.footer.setAssign = function(key, discard1, func, discard2) {
+        switch (key) {
+        case 'A':
+            yuzu_key_callbacks[0] = func;
+            break;
+        case 'B':
+            yuzu_key_callbacks[1] = func;
+            break;
+        case 'X':
+            yuzu_key_callbacks[2] = func;
+            break;
+        case 'Y':
+            yuzu_key_callbacks[3] = func;
+            break;
+        case 'L':
+            yuzu_key_callbacks[6] = func;
+            break;
+        case 'R':
+            yuzu_key_callbacks[7] = func;
+            break;
+        }
+    };
+
+    var applet_done = false;
+    window.nx.endApplet = function() {
+        applet_done = true;
+    };
+)";
+
+void NXInputWebEngineView::keyPressEvent(QKeyEvent* event) {
+    parent()->event(event);
+}
+
+void NXInputWebEngineView::keyReleaseEvent(QKeyEvent* event) {
+    parent()->event(event);
+}
+
+QString GetNXShimInjectionScript() {
+    return QString::fromStdString(NX_SHIM_INJECT_SCRIPT);
+}
+
+NXInputWebEngineView::NXInputWebEngineView(QWidget* parent) : QWebEngineView(parent) {}
+
+QtWebBrowser::QtWebBrowser(GMainWindow& main_window) {
+    connect(this, &QtWebBrowser::MainWindowOpenPage, &main_window, &GMainWindow::WebBrowserOpenPage,
+            Qt::QueuedConnection);
+    connect(&main_window, &GMainWindow::WebBrowserUnpackRomFS, this,
+            &QtWebBrowser::MainWindowUnpackRomFS, Qt::QueuedConnection);
+    connect(&main_window, &GMainWindow::WebBrowserFinishedBrowsing, this,
+            &QtWebBrowser::MainWindowFinishedBrowsing, Qt::QueuedConnection);
+}
+
+QtWebBrowser::~QtWebBrowser() = default;
+
+void QtWebBrowser::OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback,
+                            std::function<void()> finished_callback) const {
+    this->unpack_romfs_callback = unpack_romfs_callback;
+    this->finished_callback = finished_callback;
+
+    const auto index = url.find('?');
+    if (index == std::string::npos) {
+        emit MainWindowOpenPage(url, "");
+    } else {
+        const auto front = url.substr(0, index);
+        const auto back = url.substr(index);
+        emit MainWindowOpenPage(front, back);
+    }
+}
+
+void QtWebBrowser::MainWindowUnpackRomFS() {
+    // Acquire the HLE mutex
+    std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
+    unpack_romfs_callback();
+}
+
+void QtWebBrowser::MainWindowFinishedBrowsing() {
+    // Acquire the HLE mutex
+    std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
+    finished_callback();
+}
diff --git a/src/yuzu/applets/web_browser.h b/src/yuzu/applets/web_browser.h
new file mode 100644
index 000000000..74f6698be
--- /dev/null
+++ b/src/yuzu/applets/web_browser.h
@@ -0,0 +1,45 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <functional>
+#include <QObject>
+#include <QWebEngineView>
+#include "core/frontend/applets/web_browser.h"
+
+class GMainWindow;
+
+QString GetNXShimInjectionScript();
+
+class NXInputWebEngineView : public QWebEngineView {
+public:
+    NXInputWebEngineView(QWidget* parent = nullptr);
+
+protected:
+    void keyPressEvent(QKeyEvent* event) override;
+    void keyReleaseEvent(QKeyEvent* event) override;
+};
+
+class QtWebBrowser final : public QObject, public Core::Frontend::WebBrowserApplet {
+    Q_OBJECT
+
+public:
+    explicit QtWebBrowser(GMainWindow& main_window);
+    ~QtWebBrowser() override;
+
+    void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback,
+                  std::function<void()> finished_callback) const override;
+
+signals:
+    void MainWindowOpenPage(std::string_view filename, std::string_view additional_args) const;
+
+public slots:
+    void MainWindowUnpackRomFS();
+    void MainWindowFinishedBrowsing();
+
+private:
+    mutable std::function<void()> unpack_romfs_callback;
+    mutable std::function<void()> finished_callback;
+};

From 45da3be40edd71195b7aac633187fc81956e3150 Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Mon, 24 Dec 2018 16:23:31 -0500
Subject: [PATCH 09/15] main: Add main window integrations for
 QtWebBrowserApplet

---
 src/yuzu/CMakeLists.txt |   7 ++
 src/yuzu/main.cpp       | 151 ++++++++++++++++++++++++++++++++++++++++
 src/yuzu/main.h         |  10 +++
 3 files changed, 168 insertions(+)

diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 17ecaafde..c6378bce9 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -11,6 +11,8 @@ add_executable(yuzu
     applets/profile_select.h
     applets/software_keyboard.cpp
     applets/software_keyboard.h
+    applets/web_browser.cpp
+    applets/web_browser.h
     bootmanager.cpp
     bootmanager.h
     compatibility_list.cpp
@@ -154,6 +156,11 @@ if (USE_DISCORD_PRESENCE)
     target_compile_definitions(yuzu PRIVATE -DUSE_DISCORD_PRESENCE)
 endif()
 
+if (YUZU_USE_QT_WEB_ENGINE)
+    target_link_libraries(yuzu PRIVATE Qt5::WebEngineCore Qt5::WebEngineWidgets)
+    target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_WEB_ENGINE)
+endif ()
+
 if(UNIX AND NOT APPLE)
     install(TARGETS yuzu RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
 endif()
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 01a0f94ab..18dc93c95 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -10,11 +10,14 @@
 // VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
 #include "applets/profile_select.h"
 #include "applets/software_keyboard.h"
+#include "applets/web_browser.h"
 #include "configuration/configure_per_general.h"
 #include "core/file_sys/vfs.h"
 #include "core/file_sys/vfs_real.h"
 #include "core/hle/service/acc/profile_manager.h"
 #include "core/hle/service/am/applets/applets.h"
+#include "core/hle/service/hid/controllers/npad.h"
+#include "core/hle/service/hid/hid.h"
 
 // These are wrappers to avoid the calls to CreateDirectory and CreateFile because of the Windows
 // defines.
@@ -96,6 +99,14 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
 #include "yuzu/discord_impl.h"
 #endif
 
+#ifdef YUZU_USE_QT_WEB_ENGINE
+#include <QWebEngineProfile>
+#include <QWebEngineScript>
+#include <QWebEngineScriptCollection>
+#include <QWebEngineSettings>
+#include <QWebEngineView>
+#endif
+
 #ifdef QT_STATICPLUGIN
 Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
 #endif
@@ -252,6 +263,144 @@ void GMainWindow::SoftwareKeyboardInvokeCheckDialog(std::u16string error_message
     emit SoftwareKeyboardFinishedCheckDialog();
 }
 
+#ifdef YUZU_USE_QT_WEB_ENGINE
+
+void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view additional_args) {
+    NXInputWebEngineView web_browser_view(this);
+
+    // Scope to contain the QProgressDialog for initalization
+    {
+        QProgressDialog progress(this);
+        progress.setMinimumDuration(200);
+        progress.setLabelText(tr("Loading Web Applet..."));
+        progress.setRange(0, 4);
+        progress.setValue(0);
+        progress.show();
+
+        auto future = QtConcurrent::run([this] { emit WebBrowserUnpackRomFS(); });
+
+        while (!future.isFinished())
+            QApplication::processEvents();
+
+        progress.setValue(1);
+
+        // Load the special shim script to handle input and exit.
+        QWebEngineScript nx_shim;
+        nx_shim.setSourceCode(GetNXShimInjectionScript());
+        nx_shim.setWorldId(QWebEngineScript::MainWorld);
+        nx_shim.setName("nx_inject.js");
+        nx_shim.setInjectionPoint(QWebEngineScript::DocumentCreation);
+        nx_shim.setRunsOnSubFrames(true);
+        web_browser_view.page()->profile()->scripts()->insert(nx_shim);
+
+        web_browser_view.load(
+            QUrl(QUrl::fromLocalFile(QString::fromStdString(std::string(filename))).toString() +
+                 QString::fromStdString(std::string(additional_args))));
+
+        progress.setValue(2);
+
+        render_window->hide();
+        web_browser_view.setFocus();
+
+        const auto& layout = render_window->GetFramebufferLayout();
+        web_browser_view.resize(layout.screen.GetWidth(), layout.screen.GetHeight());
+        web_browser_view.move(layout.screen.left, layout.screen.top + menuBar()->height());
+        web_browser_view.setZoomFactor(static_cast<qreal>(layout.screen.GetWidth()) /
+                                       Layout::ScreenUndocked::Width);
+        web_browser_view.settings()->setAttribute(
+            QWebEngineSettings::LocalContentCanAccessRemoteUrls, true);
+
+        web_browser_view.show();
+
+        progress.setValue(3);
+
+        QApplication::processEvents();
+
+        progress.setValue(4);
+    }
+
+    bool finished = false;
+    QAction* exit_action = new QAction(tr("Exit Web Applet"), this);
+    connect(exit_action, &QAction::triggered, this, [&finished] { finished = true; });
+    ui.menubar->addAction(exit_action);
+
+    auto& npad =
+        Core::System::GetInstance()
+            .ServiceManager()
+            .GetService<Service::HID::Hid>("hid")
+            ->GetAppletResource()
+            ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
+
+    const auto fire_js_keypress = [&web_browser_view](u32 key_code) {
+        web_browser_view.page()->runJavaScript(
+            QStringLiteral("document.dispatchEvent(new KeyboardEvent('keydown', {'key': %1}));")
+                .arg(QString::fromStdString(std::to_string(key_code))));
+    };
+
+    bool running_exit_check = false;
+    while (!finished) {
+        QApplication::processEvents();
+
+        if (!running_exit_check) {
+            web_browser_view.page()->runJavaScript(QStringLiteral("applet_done;"),
+                                                   [&](const QVariant& res) {
+                                                       running_exit_check = false;
+                                                       if (res.toBool())
+                                                           finished = true;
+                                                   });
+            running_exit_check = true;
+        }
+
+        const auto input = npad.GetPressState();
+        for (std::size_t i = 0; i < Settings::NativeButton::NumButtons; ++i) {
+            if ((input & (1 << i)) != 0) {
+                LOG_DEBUG(Frontend, "firing input for button id={:02X}", i);
+                web_browser_view.page()->runJavaScript(
+                    QStringLiteral("yuzu_key_callbacks[%1]();").arg(i));
+            }
+        }
+
+        if (input & 0x00888000)      // RStick Down | LStick Down | DPad Down
+            fire_js_keypress(40);    // Down Arrow Key
+        else if (input & 0x00444000) // RStick Right | LStick Right | DPad Right
+            fire_js_keypress(39);    // Right Arrow Key
+        else if (input & 0x00222000) // RStick Up | LStick Up | DPad Up
+            fire_js_keypress(38);    // Up Arrow Key
+        else if (input & 0x00111000) // RStick Left | LStick Left | DPad Left
+            fire_js_keypress(37);    // Left Arrow Key
+        else if (input & 0x00000001) // A Button
+            fire_js_keypress(13);    // Enter Key
+    }
+
+    web_browser_view.hide();
+    render_window->show();
+    render_window->setFocus();
+    ui.menubar->removeAction(exit_action);
+
+    // Needed to update render window focus/show and remove menubar action
+    QApplication::processEvents();
+    emit WebBrowserFinishedBrowsing();
+}
+
+#else
+
+void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view additional_args) {
+    QMessageBox::warning(
+        this, tr("Web Applet"),
+        tr("This version of yuzu was built without QtWebEngine support, meaning that yuzu cannot "
+           "properly display the game manual or web page requested."),
+        QMessageBox::Ok, QMessageBox::Ok);
+
+    LOG_INFO(Frontend,
+             "(STUBBED) called - Missing QtWebEngine dependency needed to open website page at "
+             "'{}' with arguments '{}'!",
+             filename, additional_args);
+
+    emit WebBrowserFinishedBrowsing();
+}
+
+#endif
+
 void GMainWindow::InitializeWidgets() {
 #ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING
     ui.action_Report_Compatibility->setVisible(true);
@@ -612,6 +761,7 @@ bool GMainWindow::LoadROM(const QString& filename) {
 
     system.SetProfileSelector(std::make_unique<QtProfileSelector>(*this));
     system.SetSoftwareKeyboard(std::make_unique<QtSoftwareKeyboard>(*this));
+    system.SetWebBrowser(std::make_unique<QtWebBrowser>(*this));
 
     const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())};
 
@@ -1315,6 +1465,7 @@ void GMainWindow::OnStartGame() {
     qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
     qRegisterMetaType<std::string>("std::string");
     qRegisterMetaType<std::optional<std::u16string>>("std::optional<std::u16string>");
+    qRegisterMetaType<std::string_view>("std::string_view");
 
     connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError);
 
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 4e37f6a2d..3af5fa1f3 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -26,6 +26,7 @@ class GraphicsSurfaceWidget;
 class GRenderWindow;
 class MicroProfileDialog;
 class ProfilerWidget;
+class QLabel;
 class WaitTreeWidget;
 enum class GameListOpenTarget;
 
@@ -38,6 +39,10 @@ class RegisteredCacheUnion;
 class VfsFilesystem;
 } // namespace FileSys
 
+namespace Service::Account {
+struct UUID;
+} // namespace Service::Account
+
 namespace Tegra {
 class DebugContext;
 }
@@ -103,11 +108,16 @@ signals:
     void SoftwareKeyboardFinishedText(std::optional<std::u16string> text);
     void SoftwareKeyboardFinishedCheckDialog();
 
+    void WebBrowserUnpackRomFS();
+    void WebBrowserFinishedBrowsing();
+
 public slots:
     void ProfileSelectorSelectProfile();
     void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters);
     void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message);
 
+    void WebBrowserOpenPage(std::string_view filename, std::string_view arguments);
+
 private:
     void InitializeWidgets();
     void InitializeDebugWidgets();

From ef4c4e239da8e5771f61bf079eae25b28cbd0318 Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Mon, 24 Dec 2018 16:24:01 -0500
Subject: [PATCH 10/15] cmake: Add USE_QT_WEB_ENGINE flag and update build
 system

---
 .travis/linux/docker.sh            |  4 ++--
 .travis/macos/build.sh             |  2 +-
 CMakeLists.txt                     |  6 ++++++
 CMakeModules/CopyYuzuQt5Deps.cmake | 27 +++++++++++++++++++++++++++
 appveyor.yml                       |  2 +-
 5 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/.travis/linux/docker.sh b/.travis/linux/docker.sh
index 4fe3326f9..ec2cd0874 100755
--- a/.travis/linux/docker.sh
+++ b/.travis/linux/docker.sh
@@ -1,12 +1,12 @@
 #!/bin/bash -ex
 
 apt-get update
-apt-get install --no-install-recommends -y build-essential git libqt5opengl5-dev libsdl2-dev libssl-dev python qtbase5-dev wget cmake ninja-build ccache
+apt-get install --no-install-recommends -y build-essential git libqt5opengl5-dev libsdl2-dev libssl-dev python qtbase5-dev libqt5webengine5 wget cmake ninja-build ccache
 
 cd /yuzu
 
 mkdir build && cd build
-cmake .. -DYUZU_USE_BUNDLED_UNICORN=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -G Ninja
+cmake .. -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -G Ninja
 ninja
 
 ccache -s
diff --git a/.travis/macos/build.sh b/.travis/macos/build.sh
index dce12099b..4a14837fc 100755
--- a/.travis/macos/build.sh
+++ b/.travis/macos/build.sh
@@ -9,7 +9,7 @@ export PATH="/usr/local/opt/ccache/libexec:$PATH"
 
 mkdir build && cd build
 cmake --version
-cmake .. -DYUZU_USE_BUNDLED_UNICORN=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DUSE_DISCORD_PRESENCE=ON
+cmake .. -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DUSE_DISCORD_PRESENCE=ON
 make -j4
 
 ccache -s
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1f71f9fd9..f8635d91f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,6 +19,8 @@ option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
 
 option(YUZU_USE_BUNDLED_UNICORN "Build/Download bundled Unicorn" ON)
 
+option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
+
 option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
 
 option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
@@ -319,6 +321,10 @@ if (ENABLE_QT)
     endif()
 
     find_package(Qt5 REQUIRED COMPONENTS Widgets OpenGL ${QT_PREFIX_HINT})
+
+    if (YUZU_USE_QT_WEB_ENGINE)
+        find_package(Qt5 REQUIRED COMPONENTS WebEngineCore WebEngineWidgets ${QT_PREFIX_HINT})
+    endif ()
 endif()
 
 # Platform-specific library requirements
diff --git a/CMakeModules/CopyYuzuQt5Deps.cmake b/CMakeModules/CopyYuzuQt5Deps.cmake
index aaf80b77b..a1ad8d8fb 100644
--- a/CMakeModules/CopyYuzuQt5Deps.cmake
+++ b/CMakeModules/CopyYuzuQt5Deps.cmake
@@ -5,18 +5,45 @@ function(copy_yuzu_Qt5_deps target_dir)
     set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/")
     set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/")
     set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/")
+    set(Qt5_RESOURCES_DIR "${Qt5_DIR}/../../../resources/")
     set(PLATFORMS ${DLL_DEST}platforms/)
     set(STYLES ${DLL_DEST}styles/)
     set(IMAGEFORMATS ${DLL_DEST}imageformats/)
+    set(RESOURCES ${DLL_DEST}resources/)
     windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST}
         icudt*.dll
         icuin*.dll
         icuuc*.dll
         Qt5Core$<$<CONFIG:Debug>:d>.*
         Qt5Gui$<$<CONFIG:Debug>:d>.*
+        Qt5Network$<$<CONFIG:Debug>:d>.*
         Qt5OpenGL$<$<CONFIG:Debug>:d>.*
         Qt5Widgets$<$<CONFIG:Debug>:d>.*
     )
+
+    if (YUZU_USE_QT_WEB_ENGINE)
+        windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST} 
+            Qt5Positioning$<$<CONFIG:Debug>:d>.*
+            Qt5PrintSupport$<$<CONFIG:Debug>:d>.*
+            Qt5Qml$<$<CONFIG:Debug>:d>.*
+            Qt5Quick$<$<CONFIG:Debug>:d>.*
+            Qt5QuickWidgets$<$<CONFIG:Debug>:d>.*
+            Qt5WebChannel$<$<CONFIG:Debug>:d>.*
+            Qt5WebEngine$<$<CONFIG:Debug>:d>.*
+            Qt5WebEngineCore$<$<CONFIG:Debug>:d>.*
+            Qt5WebEngineWidgets$<$<CONFIG:Debug>:d>.*
+            QtWebEngineProcess$<$<CONFIG:Debug>:d>.*
+        )
+
+        windows_copy_files(${target_dir} ${Qt5_RESOURCES_DIR} ${RESOURCES}
+            qtwebengine_resources.pak
+            qtwebengine_devtools_resources.pak
+            qtwebengine_resources_100p.pak
+            qtwebengine_resources_200p.pak
+            icudtl.dat
+        )
+    endif ()
+
     windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*)
     windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*)
     windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS} qjpeg$<$<CONFIG:Debug>:d>.*)
diff --git a/appveyor.yml b/appveyor.yml
index d6a69fbc2..0e40336df 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -42,7 +42,7 @@ before_build:
         $COMPAT = if ($env:ENABLE_COMPATIBILITY_REPORTING -eq $null) {0} else {$env:ENABLE_COMPATIBILITY_REPORTING}
         if ($env:BUILD_TYPE -eq 'msvc') {
           # redirect stderr and change the exit code to prevent powershell from cancelling the build if cmake prints a warning
-          cmd /C 'cmake -G "Visual Studio 15 2017 Win64" -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_BUNDLED_UNICORN=1 -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON .. 2>&1 && exit 0'
+          cmd /C 'cmake -G "Visual Studio 15 2017 Win64" -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_BUNDLED_UNICORN=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON .. 2>&1 && exit 0'
         } else {
           C:\msys64\usr\bin\bash.exe -lc "cmake -G 'MSYS Makefiles' -DYUZU_BUILD_UNICORN=1 -DCMAKE_BUILD_TYPE=Release -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON .. 2>&1"
         }

From cb930c4b5a3f8f3931ba93ef35d4000558ffa79e Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Fri, 28 Dec 2018 18:20:29 -0500
Subject: [PATCH 11/15] web_browser: Add bounds checking to applet interface

---
 src/core/core.cpp                             |   5 +
 .../hle/service/am/applets/web_browser.cpp    |  14 +-
 src/core/hle/service/hid/controllers/npad.cpp |   6 +-
 src/core/hle/service/hid/controllers/npad.h   |   2 +-
 src/core/hle/service/hid/hid.cpp              | 244 +++++++++---------
 src/core/loader/nsp.h                         |   1 -
 src/core/loader/xci.h                         |   1 -
 src/yuzu/applets/web_browser.cpp              |  18 +-
 src/yuzu/applets/web_browser.h                |  10 +-
 src/yuzu/main.h                               |   5 +-
 10 files changed, 160 insertions(+), 146 deletions(-)

diff --git a/src/core/core.cpp b/src/core/core.cpp
index 373dff2e6..715172771 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -203,6 +203,11 @@ struct System::Impl {
         // Close app loader
         app_loader.reset();
 
+        // Clear all applets
+        profile_selector.reset();
+        software_keyboard.reset();
+        web_browser.reset();
+
         LOG_DEBUG(Core, "Shutdown OK");
     }
 
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp
index 53118324b..d975207f5 100644
--- a/src/core/hle/service/am/applets/web_browser.cpp
+++ b/src/core/hle/service/am/applets/web_browser.cpp
@@ -49,17 +49,20 @@ static_assert(sizeof(WebArgumentResult) == 0x1010, "WebArgumentResult has incorr
 
 static std::vector<u8> GetArgumentDataForTagType(const std::vector<u8>& data, u16 type) {
     WebBufferHeader header;
+    ASSERT(sizeof(WebBufferHeader) <= data.size());
     std::memcpy(&header, data.data(), sizeof(WebBufferHeader));
 
     u64 offset = sizeof(WebBufferHeader);
     for (u16 i = 0; i < header.count; ++i) {
         WebArgumentHeader arg;
+        ASSERT(offset + sizeof(WebArgumentHeader) <= data.size());
         std::memcpy(&arg, data.data() + offset, sizeof(WebArgumentHeader));
         offset += sizeof(WebArgumentHeader);
 
         if (arg.type == type) {
             std::vector<u8> out(arg.size);
             offset += arg.offset;
+            ASSERT(offset + arg.size <= data.size());
             std::memcpy(out.data(), data.data() + offset, out.size());
             return out;
         }
@@ -91,19 +94,17 @@ WebBrowser::WebBrowser() = default;
 WebBrowser::~WebBrowser() = default;
 
 void WebBrowser::Initialize() {
+    Applet::Initialize();
+
     complete = false;
     temporary_dir.clear();
     filename.clear();
     status = RESULT_SUCCESS;
 
-    Applet::Initialize();
-
     const auto web_arg_storage = broker.PopNormalDataToApplet();
     ASSERT(web_arg_storage != nullptr);
     const auto& web_arg = web_arg_storage->GetData();
 
-    LOG_CRITICAL(Service_AM, "{}", Common::HexVectorToString(web_arg));
-
     const auto url_data = GetArgumentDataForTagType(web_arg, WEB_ARGUMENT_URL_TYPE);
     filename = Common::StringFromFixedZeroTerminatedBuffer(
         reinterpret_cast<const char*>(url_data.data()), url_data.size());
@@ -133,7 +134,7 @@ ResultCode WebBrowser::GetStatus() const {
 }
 
 void WebBrowser::ExecuteInteractive() {
-    UNIMPLEMENTED_MSG(Service_AM, "Unexpected interactive data recieved!");
+    UNIMPLEMENTED_MSG("Unexpected interactive data recieved!");
 }
 
 void WebBrowser::Execute() {
@@ -147,8 +148,7 @@ void WebBrowser::Execute() {
 
     const auto& frontend{Core::System::GetInstance().GetWebBrowser()};
 
-    frontend.OpenPage(
-        filename, [this] { UnpackRomFS(); }, [this] { Finalize(); });
+    frontend.OpenPage(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); });
 }
 
 void WebBrowser::UnpackRomFS() {
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 2829f64e9..04c8c35a8 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -638,10 +638,8 @@ void Controller_NPad::ClearAllControllers() {
                   });
 }
 
-u32 Controller_NPad::GetPressState() {
-    const auto res = press_state;
-    press_state = 0;
-    return res;
+u32 Controller_NPad::GetAndResetPressState() {
+    return std::exchange(press_state, 0);
 }
 
 bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const {
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 6906d9ffb..106cf58c8 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -126,7 +126,7 @@ public:
 
     // Logical OR for all buttons presses on all controllers
     // Specifically for cheat engine and other features.
-    u32 GetPressState();
+    u32 GetAndResetPressState();
 
     static std::size_t NPadIdToIndex(u32 npad_id);
     static u32 IndexToNPad(std::size_t index);
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index acb4152a4..008bf3f02 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -136,131 +136,135 @@ private:
 };
 
 std::shared_ptr<IAppletResource> Hid::GetAppletResource() {
+    if (applet_resource == nullptr) {
+        applet_resource = std::make_shared<IAppletResource>();
+    }
+
     return applet_resource;
 }
 
 Hid::Hid() : ServiceFramework("hid") {
     // clang-format off
-        static const FunctionInfo functions[] = {
-            {0, &Hid::CreateAppletResource, "CreateAppletResource"},
-            {1, &Hid::ActivateDebugPad, "ActivateDebugPad"},
-            {11, &Hid::ActivateTouchScreen, "ActivateTouchScreen"},
-            {21, &Hid::ActivateMouse, "ActivateMouse"},
-            {31, &Hid::ActivateKeyboard, "ActivateKeyboard"},
-            {32, nullptr, "SendKeyboardLockKeyEvent"},
-            {40, nullptr, "AcquireXpadIdEventHandle"},
-            {41, nullptr, "ReleaseXpadIdEventHandle"},
-            {51, &Hid::ActivateXpad, "ActivateXpad"},
-            {55, nullptr, "GetXpadIds"},
-            {56, nullptr, "ActivateJoyXpad"},
-            {58, nullptr, "GetJoyXpadLifoHandle"},
-            {59, nullptr, "GetJoyXpadIds"},
-            {60, nullptr, "ActivateSixAxisSensor"},
-            {61, nullptr, "DeactivateSixAxisSensor"},
-            {62, nullptr, "GetSixAxisSensorLifoHandle"},
-            {63, nullptr, "ActivateJoySixAxisSensor"},
-            {64, nullptr, "DeactivateJoySixAxisSensor"},
-            {65, nullptr, "GetJoySixAxisSensorLifoHandle"},
-            {66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"},
-            {67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"},
-            {68, nullptr, "IsSixAxisSensorFusionEnabled"},
-            {69, nullptr, "EnableSixAxisSensorFusion"},
-            {70, nullptr, "SetSixAxisSensorFusionParameters"},
-            {71, nullptr, "GetSixAxisSensorFusionParameters"},
-            {72, nullptr, "ResetSixAxisSensorFusionParameters"},
-            {73, nullptr, "SetAccelerometerParameters"},
-            {74, nullptr, "GetAccelerometerParameters"},
-            {75, nullptr, "ResetAccelerometerParameters"},
-            {76, nullptr, "SetAccelerometerPlayMode"},
-            {77, nullptr, "GetAccelerometerPlayMode"},
-            {78, nullptr, "ResetAccelerometerPlayMode"},
-            {79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"},
-            {80, nullptr, "GetGyroscopeZeroDriftMode"},
-            {81, nullptr, "ResetGyroscopeZeroDriftMode"},
-            {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"},
-            {83, nullptr, "IsFirmwareUpdateAvailableForSixAxisSensor"},
-            {91, &Hid::ActivateGesture, "ActivateGesture"},
-            {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"},
-            {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"},
-            {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"},
-            {103, &Hid::ActivateNpad, "ActivateNpad"},
-            {104, nullptr, "DeactivateNpad"},
-            {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"},
-            {107, &Hid::DisconnectNpad, "DisconnectNpad"},
-            {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"},
-            {109, &Hid::ActivateNpadWithRevision, "ActivateNpadWithRevision"},
-            {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"},
-            {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"},
-            {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"},
-            {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"},
-            {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"},
-            {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"},
-            {126, nullptr, "StartLrAssignmentMode"},
-            {127, nullptr, "StopLrAssignmentMode"},
-            {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
-            {129, nullptr, "GetNpadHandheldActivationMode"},
-            {130, nullptr, "SwapNpadAssignment"},
-            {131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"},
-            {132, nullptr, "EnableUnintendedHomeButtonInputProtection"},
-            {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"},
-            {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"},
-            {201, &Hid::SendVibrationValue, "SendVibrationValue"},
-            {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"},
-            {203, &Hid::CreateActiveVibrationDeviceList, "CreateActiveVibrationDeviceList"},
-            {204, nullptr, "PermitVibration"},
-            {205, nullptr, "IsVibrationPermitted"},
-            {206, &Hid::SendVibrationValues, "SendVibrationValues"},
-            {207, nullptr, "SendVibrationGcErmCommand"},
-            {208, nullptr, "GetActualVibrationGcErmCommand"},
-            {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"},
-            {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"},
-            {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},
-            {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},
-            {302, nullptr, "StopConsoleSixAxisSensor"},
-            {303, nullptr, "ActivateSevenSixAxisSensor"},
-            {304, nullptr, "StartSevenSixAxisSensor"},
-            {305, nullptr, "StopSevenSixAxisSensor"},
-            {306, nullptr, "InitializeSevenSixAxisSensor"},
-            {307, nullptr, "FinalizeSevenSixAxisSensor"},
-            {308, nullptr, "SetSevenSixAxisSensorFusionStrength"},
-            {309, nullptr, "GetSevenSixAxisSensorFusionStrength"},
-            {310, nullptr, "ResetSevenSixAxisSensorTimestamp"},
-            {400, nullptr, "IsUsbFullKeyControllerEnabled"},
-            {401, nullptr, "EnableUsbFullKeyController"},
-            {402, nullptr, "IsUsbFullKeyControllerConnected"},
-            {403, nullptr, "HasBattery"},
-            {404, nullptr, "HasLeftRightBattery"},
-            {405, nullptr, "GetNpadInterfaceType"},
-            {406, nullptr, "GetNpadLeftRightInterfaceType"},
-            {500, nullptr, "GetPalmaConnectionHandle"},
-            {501, nullptr, "InitializePalma"},
-            {502, nullptr, "AcquirePalmaOperationCompleteEvent"},
-            {503, nullptr, "GetPalmaOperationInfo"},
-            {504, nullptr, "PlayPalmaActivity"},
-            {505, nullptr, "SetPalmaFrModeType"},
-            {506, nullptr, "ReadPalmaStep"},
-            {507, nullptr, "EnablePalmaStep"},
-            {508, nullptr, "ResetPalmaStep"},
-            {509, nullptr, "ReadPalmaApplicationSection"},
-            {510, nullptr, "WritePalmaApplicationSection"},
-            {511, nullptr, "ReadPalmaUniqueCode"},
-            {512, nullptr, "SetPalmaUniqueCodeInvalid"},
-            {513, nullptr, "WritePalmaActivityEntry"},
-            {514, nullptr, "WritePalmaRgbLedPatternEntry"},
-            {515, nullptr, "WritePalmaWaveEntry"},
-            {516, nullptr, "SetPalmaDataBaseIdentificationVersion"},
-            {517, nullptr, "GetPalmaDataBaseIdentificationVersion"},
-            {518, nullptr, "SuspendPalmaFeature"},
-            {519, nullptr, "GetPalmaOperationResult"},
-            {520, nullptr, "ReadPalmaPlayLog"},
-            {521, nullptr, "ResetPalmaPlayLog"},
-            {522, &Hid::SetIsPalmaAllConnectable, "SetIsPalmaAllConnectable"},
-            {523, nullptr, "SetIsPalmaPairedConnectable"},
-            {524, nullptr, "PairPalma"},
-            {525, &Hid::SetPalmaBoostMode, "SetPalmaBoostMode"},
-            {1000, nullptr, "SetNpadCommunicationMode"},
-            {1001, nullptr, "GetNpadCommunicationMode"},
-        };
+    static const FunctionInfo functions[] = {
+        {0, &Hid::CreateAppletResource, "CreateAppletResource"},
+        {1, &Hid::ActivateDebugPad, "ActivateDebugPad"},
+        {11, &Hid::ActivateTouchScreen, "ActivateTouchScreen"},
+        {21, &Hid::ActivateMouse, "ActivateMouse"},
+        {31, &Hid::ActivateKeyboard, "ActivateKeyboard"},
+        {32, nullptr, "SendKeyboardLockKeyEvent"},
+        {40, nullptr, "AcquireXpadIdEventHandle"},
+        {41, nullptr, "ReleaseXpadIdEventHandle"},
+        {51, &Hid::ActivateXpad, "ActivateXpad"},
+        {55, nullptr, "GetXpadIds"},
+        {56, nullptr, "ActivateJoyXpad"},
+        {58, nullptr, "GetJoyXpadLifoHandle"},
+        {59, nullptr, "GetJoyXpadIds"},
+        {60, nullptr, "ActivateSixAxisSensor"},
+        {61, nullptr, "DeactivateSixAxisSensor"},
+        {62, nullptr, "GetSixAxisSensorLifoHandle"},
+        {63, nullptr, "ActivateJoySixAxisSensor"},
+        {64, nullptr, "DeactivateJoySixAxisSensor"},
+        {65, nullptr, "GetJoySixAxisSensorLifoHandle"},
+        {66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"},
+        {67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"},
+        {68, nullptr, "IsSixAxisSensorFusionEnabled"},
+        {69, nullptr, "EnableSixAxisSensorFusion"},
+        {70, nullptr, "SetSixAxisSensorFusionParameters"},
+        {71, nullptr, "GetSixAxisSensorFusionParameters"},
+        {72, nullptr, "ResetSixAxisSensorFusionParameters"},
+        {73, nullptr, "SetAccelerometerParameters"},
+        {74, nullptr, "GetAccelerometerParameters"},
+        {75, nullptr, "ResetAccelerometerParameters"},
+        {76, nullptr, "SetAccelerometerPlayMode"},
+        {77, nullptr, "GetAccelerometerPlayMode"},
+        {78, nullptr, "ResetAccelerometerPlayMode"},
+        {79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"},
+        {80, nullptr, "GetGyroscopeZeroDriftMode"},
+        {81, nullptr, "ResetGyroscopeZeroDriftMode"},
+        {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"},
+        {83, nullptr, "IsFirmwareUpdateAvailableForSixAxisSensor"},
+        {91, &Hid::ActivateGesture, "ActivateGesture"},
+        {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"},
+        {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"},
+        {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"},
+        {103, &Hid::ActivateNpad, "ActivateNpad"},
+        {104, nullptr, "DeactivateNpad"},
+        {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"},
+        {107, &Hid::DisconnectNpad, "DisconnectNpad"},
+        {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"},
+        {109, &Hid::ActivateNpadWithRevision, "ActivateNpadWithRevision"},
+        {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"},
+        {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"},
+        {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"},
+        {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"},
+        {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"},
+        {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"},
+        {126, nullptr, "StartLrAssignmentMode"},
+        {127, nullptr, "StopLrAssignmentMode"},
+        {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
+        {129, nullptr, "GetNpadHandheldActivationMode"},
+        {130, nullptr, "SwapNpadAssignment"},
+        {131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"},
+        {132, nullptr, "EnableUnintendedHomeButtonInputProtection"},
+        {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"},
+        {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"},
+        {201, &Hid::SendVibrationValue, "SendVibrationValue"},
+        {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"},
+        {203, &Hid::CreateActiveVibrationDeviceList, "CreateActiveVibrationDeviceList"},
+        {204, nullptr, "PermitVibration"},
+        {205, nullptr, "IsVibrationPermitted"},
+        {206, &Hid::SendVibrationValues, "SendVibrationValues"},
+        {207, nullptr, "SendVibrationGcErmCommand"},
+        {208, nullptr, "GetActualVibrationGcErmCommand"},
+        {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"},
+        {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"},
+        {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},
+        {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},
+        {302, nullptr, "StopConsoleSixAxisSensor"},
+        {303, nullptr, "ActivateSevenSixAxisSensor"},
+        {304, nullptr, "StartSevenSixAxisSensor"},
+        {305, nullptr, "StopSevenSixAxisSensor"},
+        {306, nullptr, "InitializeSevenSixAxisSensor"},
+        {307, nullptr, "FinalizeSevenSixAxisSensor"},
+        {308, nullptr, "SetSevenSixAxisSensorFusionStrength"},
+        {309, nullptr, "GetSevenSixAxisSensorFusionStrength"},
+        {310, nullptr, "ResetSevenSixAxisSensorTimestamp"},
+        {400, nullptr, "IsUsbFullKeyControllerEnabled"},
+        {401, nullptr, "EnableUsbFullKeyController"},
+        {402, nullptr, "IsUsbFullKeyControllerConnected"},
+        {403, nullptr, "HasBattery"},
+        {404, nullptr, "HasLeftRightBattery"},
+        {405, nullptr, "GetNpadInterfaceType"},
+        {406, nullptr, "GetNpadLeftRightInterfaceType"},
+        {500, nullptr, "GetPalmaConnectionHandle"},
+        {501, nullptr, "InitializePalma"},
+        {502, nullptr, "AcquirePalmaOperationCompleteEvent"},
+        {503, nullptr, "GetPalmaOperationInfo"},
+        {504, nullptr, "PlayPalmaActivity"},
+        {505, nullptr, "SetPalmaFrModeType"},
+        {506, nullptr, "ReadPalmaStep"},
+        {507, nullptr, "EnablePalmaStep"},
+        {508, nullptr, "ResetPalmaStep"},
+        {509, nullptr, "ReadPalmaApplicationSection"},
+        {510, nullptr, "WritePalmaApplicationSection"},
+        {511, nullptr, "ReadPalmaUniqueCode"},
+        {512, nullptr, "SetPalmaUniqueCodeInvalid"},
+        {513, nullptr, "WritePalmaActivityEntry"},
+        {514, nullptr, "WritePalmaRgbLedPatternEntry"},
+        {515, nullptr, "WritePalmaWaveEntry"},
+        {516, nullptr, "SetPalmaDataBaseIdentificationVersion"},
+        {517, nullptr, "GetPalmaDataBaseIdentificationVersion"},
+        {518, nullptr, "SuspendPalmaFeature"},
+        {519, nullptr, "GetPalmaOperationResult"},
+        {520, nullptr, "ReadPalmaPlayLog"},
+        {521, nullptr, "ResetPalmaPlayLog"},
+        {522, &Hid::SetIsPalmaAllConnectable, "SetIsPalmaAllConnectable"},
+        {523, nullptr, "SetIsPalmaPairedConnectable"},
+        {524, nullptr, "PairPalma"},
+        {525, &Hid::SetPalmaBoostMode, "SetPalmaBoostMode"},
+        {1000, nullptr, "SetNpadCommunicationMode"},
+        {1001, nullptr, "GetNpadCommunicationMode"},
+    };
     // clang-format on
 
     RegisterHandlers(functions);
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h
index 0841578d4..b6b309400 100644
--- a/src/core/loader/nsp.h
+++ b/src/core/loader/nsp.h
@@ -44,7 +44,6 @@ public:
     ResultStatus ReadIcon(std::vector<u8>& buffer) override;
     ResultStatus ReadTitle(std::string& title) override;
     ResultStatus ReadControlData(FileSys::NACP& nacp) override;
-    ResultStatus ReadDeveloper(std::string& developer) override;
     ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) override;
 
 private:
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h
index 3e6e19a44..e18531c93 100644
--- a/src/core/loader/xci.h
+++ b/src/core/loader/xci.h
@@ -44,7 +44,6 @@ public:
     ResultStatus ReadIcon(std::vector<u8>& buffer) override;
     ResultStatus ReadTitle(std::string& title) override;
     ResultStatus ReadControlData(FileSys::NACP& control) override;
-    ResultStatus ReadDeveloper(std::string& developer) override;
     ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) override;
 
 private:
diff --git a/src/yuzu/applets/web_browser.cpp b/src/yuzu/applets/web_browser.cpp
index e1a34bb5f..c59b7ade1 100644
--- a/src/yuzu/applets/web_browser.cpp
+++ b/src/yuzu/applets/web_browser.cpp
@@ -10,15 +10,17 @@
 #include "yuzu/applets/web_browser.h"
 #include "yuzu/main.h"
 
+#ifdef YUZU_USE_QT_WEB_ENGINE
+
 constexpr char NX_SHIM_INJECT_SCRIPT[] = R"(
     window.nx = {};
     window.nx.playReport = {};
     window.nx.playReport.setCounterSetIdentifier = function () {
-        console.log("nx.footer.setCounterSetIdentifier called - unimplemented");
+        console.log("nx.playReport.setCounterSetIdentifier called - unimplemented");
     };
 
     window.nx.playReport.incrementCounter = function () {
-        console.log("nx.footer.incrementCounter called - unimplemented");
+        console.log("nx.playReport.incrementCounter called - unimplemented");
     };
 
     window.nx.footer = {};
@@ -56,6 +58,12 @@ constexpr char NX_SHIM_INJECT_SCRIPT[] = R"(
     };
 )";
 
+QString GetNXShimInjectionScript() {
+    return QString::fromStdString(NX_SHIM_INJECT_SCRIPT);
+}
+
+NXInputWebEngineView::NXInputWebEngineView(QWidget* parent) : QWebEngineView(parent) {}
+
 void NXInputWebEngineView::keyPressEvent(QKeyEvent* event) {
     parent()->event(event);
 }
@@ -64,11 +72,7 @@ void NXInputWebEngineView::keyReleaseEvent(QKeyEvent* event) {
     parent()->event(event);
 }
 
-QString GetNXShimInjectionScript() {
-    return QString::fromStdString(NX_SHIM_INJECT_SCRIPT);
-}
-
-NXInputWebEngineView::NXInputWebEngineView(QWidget* parent) : QWebEngineView(parent) {}
+#endif
 
 QtWebBrowser::QtWebBrowser(GMainWindow& main_window) {
     connect(this, &QtWebBrowser::MainWindowOpenPage, &main_window, &GMainWindow::WebBrowserOpenPage,
diff --git a/src/yuzu/applets/web_browser.h b/src/yuzu/applets/web_browser.h
index 74f6698be..bba273767 100644
--- a/src/yuzu/applets/web_browser.h
+++ b/src/yuzu/applets/web_browser.h
@@ -6,22 +6,30 @@
 
 #include <functional>
 #include <QObject>
+
+#ifdef YUZU_USE_QT_WEB_ENGINE
 #include <QWebEngineView>
+#endif
+
 #include "core/frontend/applets/web_browser.h"
 
 class GMainWindow;
 
+#ifdef YUZU_USE_QT_WEB_ENGINE
+
 QString GetNXShimInjectionScript();
 
 class NXInputWebEngineView : public QWebEngineView {
 public:
-    NXInputWebEngineView(QWidget* parent = nullptr);
+    explicit NXInputWebEngineView(QWidget* parent = nullptr);
 
 protected:
     void keyPressEvent(QKeyEvent* event) override;
     void keyReleaseEvent(QKeyEvent* event) override;
 };
 
+#endif
+
 class QtWebBrowser final : public QObject, public Core::Frontend::WebBrowserApplet {
     Q_OBJECT
 
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 3af5fa1f3..8a0485de9 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -13,6 +13,7 @@
 
 #include "common/common_types.h"
 #include "core/core.h"
+#include "core/hle/service/acc/profile_manager.h"
 #include "ui_main.h"
 #include "yuzu/compatibility_list.h"
 #include "yuzu/hotkeys.h"
@@ -39,10 +40,6 @@ class RegisteredCacheUnion;
 class VfsFilesystem;
 } // namespace FileSys
 
-namespace Service::Account {
-struct UUID;
-} // namespace Service::Account
-
 namespace Tegra {
 class DebugContext;
 }

From 0c5ede492f8dd2e321bb237a56e7f38609541366 Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Fri, 28 Dec 2018 19:29:44 -0500
Subject: [PATCH 12/15] travis: Use correct package for linux Qt5WebEngine

---
 .travis/linux/docker.sh          | 2 +-
 src/core/hle/service/hid/hid.h   | 4 ++--
 src/core/hle/service/nfp/nfp.cpp | 1 -
 src/yuzu/main.cpp                | 2 +-
 4 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/.travis/linux/docker.sh b/.travis/linux/docker.sh
index ec2cd0874..8b7e65911 100755
--- a/.travis/linux/docker.sh
+++ b/.travis/linux/docker.sh
@@ -1,7 +1,7 @@
 #!/bin/bash -ex
 
 apt-get update
-apt-get install --no-install-recommends -y build-essential git libqt5opengl5-dev libsdl2-dev libssl-dev python qtbase5-dev libqt5webengine5 wget cmake ninja-build ccache
+apt-get install --no-install-recommends -y build-essential git libqt5opengl5-dev libsdl2-dev libssl-dev python qtbase5-dev qtwebengine5-dev wget cmake ninja-build ccache
 
 cd /yuzu
 
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 615d4e6d8..eca27c056 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -3,6 +3,8 @@
 // Refer to the license.txt file included.
 
 #pragma once
+
+#include "controllers/controller_base.h"
 #include "core/hle/service/service.h"
 
 namespace CoreTiming {
@@ -19,8 +21,6 @@ class ServiceManager;
 
 namespace Service::HID {
 
-class ControllerBase;
-
 enum class HidController : std::size_t {
     DebugPad,
     Touchscreen,
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index a7bed0040..9ca5461db 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -11,7 +11,6 @@
 #include "core/hle/kernel/readable_event.h"
 #include "core/hle/kernel/writable_event.h"
 #include "core/hle/lock.h"
-#include "core/hle/service/hid/hid.h"
 #include "core/hle/service/nfp/nfp.h"
 #include "core/hle/service/nfp/nfp_user.h"
 
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 18dc93c95..4eb73792f 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -351,7 +351,7 @@ void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view
             running_exit_check = true;
         }
 
-        const auto input = npad.GetPressState();
+        const auto input = npad.GetAndResetPressState();
         for (std::size_t i = 0; i < Settings::NativeButton::NumButtons; ++i) {
             if ((input & (1 << i)) != 0) {
                 LOG_DEBUG(Frontend, "firing input for button id={:02X}", i);

From 15501477e75962f52d42cf5f4ada883319f33a7c Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Mon, 31 Dec 2018 13:19:23 -0500
Subject: [PATCH 13/15] Update Qt MSVC external to 5.12.0

---
 CMakeLists.txt                     | 2 +-
 CMakeModules/CopyYuzuQt5Deps.cmake | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index f8635d91f..871e0ca1a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -304,7 +304,7 @@ endif()
 if (ENABLE_QT)
     if (YUZU_USE_BUNDLED_QT)
         if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64)
-            set(QT_VER qt-5.10.0-msvc2015_64)
+            set(QT_VER qt-5.12.0-msvc2017_64)
         else()
             message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable YUZU_USE_BUNDLED_QT and provide your own.")
         endif()
diff --git a/CMakeModules/CopyYuzuQt5Deps.cmake b/CMakeModules/CopyYuzuQt5Deps.cmake
index a1ad8d8fb..db4cd88b6 100644
--- a/CMakeModules/CopyYuzuQt5Deps.cmake
+++ b/CMakeModules/CopyYuzuQt5Deps.cmake
@@ -16,13 +16,13 @@ function(copy_yuzu_Qt5_deps target_dir)
         icuuc*.dll
         Qt5Core$<$<CONFIG:Debug>:d>.*
         Qt5Gui$<$<CONFIG:Debug>:d>.*
-        Qt5Network$<$<CONFIG:Debug>:d>.*
         Qt5OpenGL$<$<CONFIG:Debug>:d>.*
         Qt5Widgets$<$<CONFIG:Debug>:d>.*
     )
 
     if (YUZU_USE_QT_WEB_ENGINE)
         windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST} 
+            Qt5Network$<$<CONFIG:Debug>:d>.*
             Qt5Positioning$<$<CONFIG:Debug>:d>.*
             Qt5PrintSupport$<$<CONFIG:Debug>:d>.*
             Qt5Qml$<$<CONFIG:Debug>:d>.*

From 0f887daa721cb563bd7e804efafbe7b9e09f1837 Mon Sep 17 00:00:00 2001
From: Zach Hilman <DarkLordZach@users.noreply.github.com>
Date: Thu, 3 Jan 2019 12:37:54 -0500
Subject: [PATCH 14/15] build: Copy QtWebEngineProcess[d].exe to release dir on
 windows

---
 appveyor.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/appveyor.yml b/appveyor.yml
index 0e40336df..cef19c259 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -94,6 +94,7 @@ after_build:
           Copy-Item "$BUILD_DIR\*" -Destination $RELEASE_DIST -Recurse
           rm "$RELEASE_DIST\*.exe"
           Get-ChildItem "$BUILD_DIR" -Recurse -Filter "yuzu*.exe" | Copy-Item -destination $RELEASE_DIST
+          Get-ChildItem "$BUILD_DIR" -Recurse -Filter "QtWebEngineProcess*.exe" | Copy-Item -destination $RELEASE_DIST
           Copy-Item .\license.txt -Destination $RELEASE_DIST
           Copy-Item .\README.md -Destination $RELEASE_DIST
           7z a -tzip $MSVC_BUILD_ZIP $RELEASE_DIST\*

From 2378ecd0e8709efc47fbc73ef41e5ee0b952ee59 Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Sat, 5 Jan 2019 15:27:15 -0500
Subject: [PATCH 15/15] build: Copy web engine resources to correct location

---
 CMakeModules/CopyYuzuQt5Deps.cmake | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/CMakeModules/CopyYuzuQt5Deps.cmake b/CMakeModules/CopyYuzuQt5Deps.cmake
index db4cd88b6..4fef66659 100644
--- a/CMakeModules/CopyYuzuQt5Deps.cmake
+++ b/CMakeModules/CopyYuzuQt5Deps.cmake
@@ -9,7 +9,6 @@ function(copy_yuzu_Qt5_deps target_dir)
     set(PLATFORMS ${DLL_DEST}platforms/)
     set(STYLES ${DLL_DEST}styles/)
     set(IMAGEFORMATS ${DLL_DEST}imageformats/)
-    set(RESOURCES ${DLL_DEST}resources/)
     windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST}
         icudt*.dll
         icuin*.dll
@@ -35,7 +34,7 @@ function(copy_yuzu_Qt5_deps target_dir)
             QtWebEngineProcess$<$<CONFIG:Debug>:d>.*
         )
 
-        windows_copy_files(${target_dir} ${Qt5_RESOURCES_DIR} ${RESOURCES}
+        windows_copy_files(${target_dir} ${Qt5_RESOURCES_DIR} ${DLL_DEST}
             qtwebengine_resources.pak
             qtwebengine_devtools_resources.pak
             qtwebengine_resources_100p.pak