diff --git a/include/kernel/kernel.hpp b/include/kernel/kernel.hpp
index 9d46d1b9..ddeec2e1 100644
--- a/include/kernel/kernel.hpp
+++ b/include/kernel/kernel.hpp
@@ -201,5 +201,10 @@ public:
 
 	void sendGPUInterrupt(GPUInterrupt type) { serviceManager.requestGPUInterrupt(type); }
 	void signalDSPEvents() { serviceManager.signalDSPEvents(); }
+
+	void pressKey(u32 key) { serviceManager.pressKey(key); }
+	void releaseKey(u32 key) { serviceManager.releaseKey(key); }
+	void setCirclepadX(u16 x) { serviceManager.setCirclepadX(x); }
+	void setCirclepadY(u16 y) { serviceManager.setCirclepadY(y); }
 	void updateInputs() { serviceManager.updateInputs(); }
 };
\ No newline at end of file
diff --git a/include/services/hid.hpp b/include/services/hid.hpp
index 8464cd48..2199d367 100644
--- a/include/services/hid.hpp
+++ b/include/services/hid.hpp
@@ -34,6 +34,11 @@ public:
 	HIDService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
 	void reset();
 	void handleSyncRequest(u32 messagePointer);
+
+	void pressKey(u32 key);
+	void releaseKey(u32 key);
+	void setCirclepadX(u16 x);
+	void setCirclepadY(u16 y);
 	void updateInputs();
 
 	void setSharedMem(u8* ptr) {
diff --git a/include/services/service_manager.hpp b/include/services/service_manager.hpp
index 2a50ffaf..c67794de 100644
--- a/include/services/service_manager.hpp
+++ b/include/services/service_manager.hpp
@@ -84,5 +84,10 @@ public:
 	void setHIDSharedMem(u8* ptr) { hid.setSharedMem(ptr); }
 
 	void signalDSPEvents() { dsp.signalEvents(); }
+
+	void pressKey(u32 key) { hid.pressKey(key); }
+	void releaseKey(u32 key) { hid.releaseKey(key); }
+	void setCirclepadX(u16 x) { hid.setCirclepadX(x); }
+	void setCirclepadY(u16 y) { hid.setCirclepadY(y); }
 	void updateInputs() { hid.updateInputs(); }
 };
\ No newline at end of file
diff --git a/src/core/services/hid.cpp b/src/core/services/hid.cpp
index 21e38dba..854a4286 100644
--- a/src/core/services/hid.cpp
+++ b/src/core/services/hid.cpp
@@ -108,6 +108,11 @@ void HIDService::getIPCHandles(u32 messagePointer) {
 	}
 }
 
+void HIDService::pressKey(u32 key) { sharedMem[0]++; *(u32*)&sharedMem[0x28] |= key; }
+void HIDService::releaseKey(u32 key) { sharedMem[0]++; *(u32*)&sharedMem[0x28] &= ~key; }
+void HIDService::setCirclepadX(u16 x) { sharedMem[0]++; *(u16*)&sharedMem[0x28 + 0xC] = x; }
+void HIDService::setCirclepadY(u16 y) { sharedMem[0]++; *(u16*)&sharedMem[0x28 + 0xC + 2] = y; }
+
 // TODO: We don't currently have inputs but we must at least try to signal the HID key input events now and then
 void HIDService::updateInputs() {
 	// For some reason, the original developers decided to signal the HID events each time the OS rescanned inputs
diff --git a/src/emulator.cpp b/src/emulator.cpp
index 56e555c7..a404e19c 100644
--- a/src/emulator.cpp
+++ b/src/emulator.cpp
@@ -36,10 +36,45 @@ void Emulator::run() {
 
         SDL_Event event;
         while (SDL_PollEvent(&event)) {
-            if (event.type == SDL_QUIT) {
+            switch (event.type) {
+            case SDL_QUIT:
                 printf("Bye :(\n");
                 running = false;
                 return;
+            case SDL_KEYDOWN:
+                switch (event.key.keysym.sym) {
+                case SDLK_z:        kernel.pressKey(1 << 0);        break;
+                case SDLK_RIGHT:    kernel.pressKey(1 << 4);        break;
+                case SDLK_LEFT:     kernel.pressKey(1 << 5);        break;
+                case SDLK_UP:       kernel.pressKey(1 << 6);        break;
+                case SDLK_DOWN:     kernel.pressKey(1 << 7);        break;
+                case SDLK_w:        kernel.setCirclepadY(0x9C);     break;
+                case SDLK_a:        kernel.setCirclepadX(-0x9C);    break;
+                case SDLK_s:        kernel.setCirclepadY(-0x9C);    break;
+                case SDLK_d:        kernel.setCirclepadX(0x9C);     break;
+                case SDLK_j:        kernel.pressKey(1 << 1);        break;
+                case SDLK_k:        kernel.pressKey(1 << 10);       break;
+                case SDLK_l:        kernel.pressKey(1 << 11);       break;
+                case SDLK_r:        kernel.pressKey(1 << 8);        break;
+                }
+                break;
+            case SDL_KEYUP:
+                switch (event.key.keysym.sym) {
+                case SDLK_z:        kernel.releaseKey(1 << 0);  break;
+                case SDLK_RIGHT:    kernel.releaseKey(1 << 4);  break;
+                case SDLK_LEFT:     kernel.releaseKey(1 << 5);  break;
+                case SDLK_UP:       kernel.releaseKey(1 << 6);  break;
+                case SDLK_DOWN:     kernel.releaseKey(1 << 7);  break;
+                case SDLK_w:        kernel.setCirclepadY(0);    break;
+                case SDLK_a:        kernel.setCirclepadX(0);    break;
+                case SDLK_s:        kernel.setCirclepadY(0);    break;
+                case SDLK_d:        kernel.setCirclepadX(0);    break;
+                case SDLK_j:        kernel.releaseKey(1 << 1);  break;
+                case SDLK_k:        kernel.releaseKey(1 << 10); break;
+                case SDLK_l:        kernel.releaseKey(1 << 11); break;
+                case SDLK_r:        kernel.releaseKey(1 << 8);  break;
+                }
+                break;
             }
         }