| @@ -13,7 +13,7 @@ const int GAMEPAD_DRIVER = -10; | |||||
| struct GamepadInputDevice : MidiInputDevice { | struct GamepadInputDevice : MidiInputDevice { | ||||
| int deviceId; | int deviceId; | ||||
| std::vector<uint8_t> ccs; | std::vector<uint8_t> ccs; | ||||
| std::vector<bool> notes; | |||||
| std::vector<bool> states; | |||||
| void step(); | 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 "gamepad.hpp" | ||||
| #include "util/common.hpp" | |||||
| #include <GLFW/glfw3.h> | #include <GLFW/glfw3.h> | ||||
| @@ -34,14 +33,14 @@ void GamepadInputDevice::step() { | |||||
| } | } | ||||
| // Convert buttons to MIDI notes | // Convert buttons to MIDI notes | ||||
| notes.resize(numButtons); | |||||
| states.resize(numButtons); | |||||
| for (int i = 0; i < numButtons; i++) { | 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; | MidiMessage msg; | ||||
| msg.cmd = ((note ? 0x9 : 0x8) << 4); | |||||
| msg.cmd = ((state ? 0x9 : 0x8) << 4); | |||||
| msg.data1 = i; | msg.data1 = i; | ||||
| msg.data2 = 127; | msg.data2 = 127; | ||||
| onMessage(msg); | 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 "rtmidi.hpp" | ||||
| #include "bridge.hpp" | #include "bridge.hpp" | ||||
| #include "gamepad.hpp" | #include "gamepad.hpp" | ||||
| #include "keyboard.hpp" | |||||
| namespace rack { | namespace rack { | ||||
| @@ -45,6 +46,7 @@ std::vector<int> MidiIO::getDriverIds() { | |||||
| // Add custom driverIds | // Add custom driverIds | ||||
| driverIds.push_back(BRIDGE_DRIVER); | driverIds.push_back(BRIDGE_DRIVER); | ||||
| driverIds.push_back(GAMEPAD_DRIVER); | driverIds.push_back(GAMEPAD_DRIVER); | ||||
| driverIds.push_back(KEYBOARD_DRIVER); | |||||
| return driverIds; | return driverIds; | ||||
| } | } | ||||
| @@ -59,6 +61,7 @@ std::string MidiIO::getDriverName(int driverId) { | |||||
| case RtMidi::RTMIDI_DUMMY: return "Dummy MIDI"; | case RtMidi::RTMIDI_DUMMY: return "Dummy MIDI"; | ||||
| case BRIDGE_DRIVER: return "Bridge"; | case BRIDGE_DRIVER: return "Bridge"; | ||||
| case GAMEPAD_DRIVER: return "Gamepad"; | case GAMEPAD_DRIVER: return "Gamepad"; | ||||
| case KEYBOARD_DRIVER: return "Computer keyboard"; | |||||
| default: return "Unknown"; | default: return "Unknown"; | ||||
| } | } | ||||
| } | } | ||||
| @@ -132,6 +135,9 @@ void MidiInput::setDriverId(int driverId) { | |||||
| else if (driverId == GAMEPAD_DRIVER) { | else if (driverId == GAMEPAD_DRIVER) { | ||||
| driver = gamepadGetInputDriver(); | driver = gamepadGetInputDriver(); | ||||
| } | } | ||||
| else if (driverId == KEYBOARD_DRIVER) { | |||||
| driver = keyboardGetInputDriver(); | |||||
| } | |||||
| // Set driverId | // Set driverId | ||||
| if (driver) { | if (driver) { | ||||
| @@ -2,6 +2,7 @@ | |||||
| #include "app.hpp" | #include "app.hpp" | ||||
| #include "asset.hpp" | #include "asset.hpp" | ||||
| #include "gamepad.hpp" | #include "gamepad.hpp" | ||||
| #include "keyboard.hpp" | |||||
| #include "util/color.hpp" | #include "util/color.hpp" | ||||
| #include <map> | #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) { | 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 (action == GLFW_PRESS || action == GLFW_REPEAT) { | ||||
| if (gFocusedWidget) { | if (gFocusedWidget) { | ||||
| // onKey | // onKey | ||||