| @@ -13,7 +13,7 @@ const int GAMEPAD_DRIVER = -10; | |||
| struct GamepadInputDevice : MidiInputDevice { | |||
| int deviceId; | |||
| std::vector<uint8_t> ccs; | |||
| std::vector<bool> notes; | |||
| std::vector<bool> states; | |||
| void step(); | |||
| }; | |||
| @@ -0,0 +1,33 @@ | |||
| #pragma once | |||
| #include "util/common.hpp" | |||
| #include "midi.hpp" | |||
| namespace rack { | |||
| const int KEYBOARD_DRIVER = -11; | |||
| struct KeyboardInputDevice : MidiInputDevice { | |||
| int octave = 5; | |||
| void processKey(int key, bool released); | |||
| }; | |||
| struct KeyboardInputDriver : MidiInputDriver { | |||
| KeyboardInputDevice device; | |||
| std::vector<int> getDeviceIds() override; | |||
| std::string getDeviceName(int deviceId) override; | |||
| MidiInputDevice *getDevice(int deviceId) override; | |||
| }; | |||
| void keyboardPress(int key); | |||
| void keyboardRelease(int key); | |||
| KeyboardInputDriver *keyboardGetInputDriver(); | |||
| } // namespace rack | |||
| @@ -1,5 +1,4 @@ | |||
| #include "gamepad.hpp" | |||
| #include "util/common.hpp" | |||
| #include <GLFW/glfw3.h> | |||
| @@ -34,14 +33,14 @@ void GamepadInputDevice::step() { | |||
| } | |||
| // Convert buttons to MIDI notes | |||
| notes.resize(numButtons); | |||
| states.resize(numButtons); | |||
| for (int i = 0; i < numButtons; i++) { | |||
| bool note = !!buttons[i]; | |||
| if (note != notes[i]) { | |||
| notes[i] = note; | |||
| bool state = !!buttons[i]; | |||
| if (state != states[i]) { | |||
| states[i] = state; | |||
| MidiMessage msg; | |||
| msg.cmd = ((note ? 0x9 : 0x8) << 4); | |||
| msg.cmd = ((state ? 0x9 : 0x8) << 4); | |||
| msg.data1 = i; | |||
| msg.data2 = 127; | |||
| onMessage(msg); | |||
| @@ -0,0 +1,115 @@ | |||
| #include "keyboard.hpp" | |||
| #include <GLFW/glfw3.h> | |||
| namespace rack { | |||
| void KeyboardInputDevice::processKey(int key, bool released) { | |||
| int note = -1; | |||
| switch (key) { | |||
| case GLFW_KEY_Z: note = 0; break; | |||
| case GLFW_KEY_S: note = 1; break; | |||
| case GLFW_KEY_X: note = 2; break; | |||
| case GLFW_KEY_D: note = 3; break; | |||
| case GLFW_KEY_C: note = 4; break; | |||
| case GLFW_KEY_V: note = 5; break; | |||
| case GLFW_KEY_G: note = 6; break; | |||
| case GLFW_KEY_B: note = 7; break; | |||
| case GLFW_KEY_H: note = 8; break; | |||
| case GLFW_KEY_N: note = 9; break; | |||
| case GLFW_KEY_J: note = 10; break; | |||
| case GLFW_KEY_M: note = 11; break; | |||
| case GLFW_KEY_COMMA: note = 12; break; | |||
| case GLFW_KEY_L: note = 13; break; | |||
| case GLFW_KEY_PERIOD: note = 14; break; | |||
| case GLFW_KEY_SEMICOLON: note = 15; break; | |||
| case GLFW_KEY_SLASH: note = 16; break; | |||
| case GLFW_KEY_Q: note = 12; break; | |||
| case GLFW_KEY_2: note = 13; break; | |||
| case GLFW_KEY_W: note = 14; break; | |||
| case GLFW_KEY_3: note = 15; break; | |||
| case GLFW_KEY_E: note = 16; break; | |||
| case GLFW_KEY_R: note = 17; break; | |||
| case GLFW_KEY_5: note = 18; break; | |||
| case GLFW_KEY_T: note = 19; break; | |||
| case GLFW_KEY_6: note = 20; break; | |||
| case GLFW_KEY_Y: note = 21; break; | |||
| case GLFW_KEY_7: note = 22; break; | |||
| case GLFW_KEY_U: note = 23; break; | |||
| case GLFW_KEY_I: note = 24; break; | |||
| case GLFW_KEY_9: note = 25; break; | |||
| case GLFW_KEY_O: note = 26; break; | |||
| case GLFW_KEY_0: note = 27; break; | |||
| case GLFW_KEY_P: note = 28; break; | |||
| case GLFW_KEY_LEFT_BRACKET: note = 29; break; | |||
| case GLFW_KEY_EQUAL: note = 30; break; | |||
| case GLFW_KEY_RIGHT_BRACKET: note = 31; break; | |||
| case GLFW_KEY_GRAVE_ACCENT: { | |||
| if (!released) | |||
| octave--; | |||
| } break; | |||
| case GLFW_KEY_1: { | |||
| if (!released) | |||
| octave++; | |||
| } break; | |||
| default: break; | |||
| } | |||
| octave = clamp(octave, 0, 9); | |||
| if (note < 0) | |||
| return; | |||
| note += 12 * octave; | |||
| if (note > 127) | |||
| return; | |||
| MidiMessage msg; | |||
| msg.cmd = ((!released ? 0x9 : 0x8) << 4); | |||
| msg.data1 = note; | |||
| msg.data2 = 127; | |||
| onMessage(msg); | |||
| } | |||
| std::vector<int> KeyboardInputDriver::getDeviceIds() { | |||
| return {0}; | |||
| } | |||
| std::string KeyboardInputDriver::getDeviceName(int deviceId) { | |||
| if (deviceId == 0) | |||
| return "QWERTY keyboard (US)"; | |||
| return ""; | |||
| } | |||
| MidiInputDevice *KeyboardInputDriver::getDevice(int deviceId) { | |||
| return &device; | |||
| } | |||
| static KeyboardInputDriver *driver = NULL; | |||
| void keyboardPress(int key) { | |||
| if (!driver) | |||
| return; | |||
| driver->device.processKey(key, false); | |||
| } | |||
| void keyboardRelease(int key) { | |||
| if (!driver) | |||
| return; | |||
| driver->device.processKey(key, true); | |||
| } | |||
| KeyboardInputDriver *keyboardGetInputDriver() { | |||
| // Lazily create driver | |||
| if (!driver) { | |||
| driver = new KeyboardInputDriver(); | |||
| } | |||
| return driver; | |||
| } | |||
| } // namespace rack | |||
| @@ -2,6 +2,7 @@ | |||
| #include "rtmidi.hpp" | |||
| #include "bridge.hpp" | |||
| #include "gamepad.hpp" | |||
| #include "keyboard.hpp" | |||
| namespace rack { | |||
| @@ -45,6 +46,7 @@ std::vector<int> MidiIO::getDriverIds() { | |||
| // Add custom driverIds | |||
| driverIds.push_back(BRIDGE_DRIVER); | |||
| driverIds.push_back(GAMEPAD_DRIVER); | |||
| driverIds.push_back(KEYBOARD_DRIVER); | |||
| return driverIds; | |||
| } | |||
| @@ -59,6 +61,7 @@ std::string MidiIO::getDriverName(int driverId) { | |||
| case RtMidi::RTMIDI_DUMMY: return "Dummy MIDI"; | |||
| case BRIDGE_DRIVER: return "Bridge"; | |||
| case GAMEPAD_DRIVER: return "Gamepad"; | |||
| case KEYBOARD_DRIVER: return "Computer keyboard"; | |||
| default: return "Unknown"; | |||
| } | |||
| } | |||
| @@ -132,6 +135,9 @@ void MidiInput::setDriverId(int driverId) { | |||
| else if (driverId == GAMEPAD_DRIVER) { | |||
| driver = gamepadGetInputDriver(); | |||
| } | |||
| else if (driverId == KEYBOARD_DRIVER) { | |||
| driver = keyboardGetInputDriver(); | |||
| } | |||
| // Set driverId | |||
| if (driver) { | |||
| @@ -2,6 +2,7 @@ | |||
| #include "app.hpp" | |||
| #include "asset.hpp" | |||
| #include "gamepad.hpp" | |||
| #include "keyboard.hpp" | |||
| #include "util/color.hpp" | |||
| #include <map> | |||
| @@ -262,6 +263,16 @@ void charCallback(GLFWwindow *window, unsigned int codepoint) { | |||
| } | |||
| void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) { | |||
| // Keyboard MIDI driver | |||
| if (1 || glfwGetInputMode(gWindow, GLFW_LOCK_KEY_MODS) & GLFW_MOD_CAPS_LOCK) { | |||
| if (action == GLFW_PRESS) { | |||
| keyboardPress(key); | |||
| } | |||
| else if (action == GLFW_RELEASE) { | |||
| keyboardRelease(key); | |||
| } | |||
| } | |||
| if (action == GLFW_PRESS || action == GLFW_REPEAT) { | |||
| if (gFocusedWidget) { | |||
| // onKey | |||