diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp
index ccfbce9ace..088f00b436 100644
--- a/src/core/hle/service/hid/controllers/keyboard.cpp
+++ b/src/core/hle/service/hid/controllers/keyboard.cpp
@@ -6,6 +6,7 @@
 #include "common/common_types.h"
 #include "core/core_timing.h"
 #include "core/hle/service/hid/controllers/keyboard.h"
+#include "core/settings.h"
 
 namespace Service::HID {
 constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800;
@@ -34,10 +35,24 @@ void Controller_Keyboard::OnUpdate(u8* data, std::size_t size) {
 
     cur_entry.sampling_number = last_entry.sampling_number + 1;
     cur_entry.sampling_number2 = cur_entry.sampling_number;
-    // TODO(ogniK): Update keyboard states
+
+    for (std::size_t i = 0; i < keyboard_keys.size(); ++i) {
+        for (std::size_t k = 0; k < 8; ++k) {
+            cur_entry.key[i / 8] |= (keyboard_keys[i]->GetStatus() << k);
+        }
+    }
+
+    for (std::size_t i = 0; i < keyboard_mods.size(); ++i) {
+        cur_entry.modifier |= (keyboard_mods[i]->GetStatus() << i);
+    }
 
     std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
 }
 
-void Controller_Keyboard::OnLoadInputDevices() {}
+void Controller_Keyboard::OnLoadInputDevices() {
+    std::transform(Settings::values.keyboard_keys.begin(), Settings::values.keyboard_keys.end(),
+                   keyboard_keys.begin(), Input::CreateDevice<Input::ButtonDevice>);
+    std::transform(Settings::values.keyboard_mods.begin(), Settings::values.keyboard_mods.end(),
+                   keyboard_mods.begin(), Input::CreateDevice<Input::ButtonDevice>);
+}
 } // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h
index 493e68fce0..f527754561 100644
--- a/src/core/hle/service/hid/controllers/keyboard.h
+++ b/src/core/hle/service/hid/controllers/keyboard.h
@@ -8,7 +8,9 @@
 #include "common/common_funcs.h"
 #include "common/common_types.h"
 #include "common/swap.h"
+#include "core/frontend/input.h"
 #include "core/hle/service/hid/controllers/controller_base.h"
+#include "core/settings.h"
 
 namespace Service::HID {
 class Controller_Keyboard final : public ControllerBase {
@@ -46,5 +48,10 @@ private:
     };
     static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size");
     SharedMemory shared_memory{};
+
+    std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardKeys>
+        keyboard_keys;
+    std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardMods>
+        keyboard_mods;
 };
 } // namespace Service::HID