Browse Source

Send keyboard and focus events to VST3 UIs as needed

Signed-off-by: falkTX <falktx@falktx.com>
tags/v2.4.1
falkTX 9 months ago
parent
commit
bc7deaab69
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
6 changed files with 284 additions and 43 deletions
  1. +11
    -7
      .github/workflows/irc.yml
  2. +9
    -4
      source/backend/plugin/CarlaPluginJuce.cpp
  3. +5
    -0
      source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp
  4. +1
    -0
      source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp
  5. +5
    -0
      source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h
  6. +253
    -32
      source/utils/JucePluginWindow.hpp

+ 11
- 7
.github/workflows/irc.yml View File

@@ -7,10 +7,14 @@ jobs:
runs-on: ubuntu-latest
name: IRC notification
steps:
- name: IRC notification
uses: Gottox/irc-message-action@v2
with:
channel: '#kxstudio'
nickname: kxstudio-bot
message: |-
${{ github.actor }} pushed ${{ github.event.head_commit.message }} ${{ github.event.compare }}
- name: Format message
id: message
run: |
message="${{ github.actor }} pushed $(echo '${{ github.event.commits[0].message }}' | head -n 1) ${{ github.event.commits[0].url }}"
echo ::set-output name=message::"${message}"
- name: IRC notification
uses: Gottox/irc-message-action@v2
with:
channel: '#kxstudio'
nickname: kxstudio-bot
message: ${{ steps.message.outputs.message }}

+ 9
- 4
source/backend/plugin/CarlaPluginJuce.cpp View File

@@ -496,11 +496,16 @@ public:
uiName += " (GUI)";
}

AEffect* const effect = fDesc.pluginFormatName == "VST" || fDesc.pluginFormatName == "VST2"
? (AEffect*)fInstance->getPlatformSpecificData()
: nullptr;
AEffect* const vst2effect = fDesc.pluginFormatName == "VST" || fDesc.pluginFormatName == "VST2"
? (AEffect*)fInstance->getPlatformSpecificData()
: nullptr;

fWindow = new JucePluginWindow(opts.frontendWinId, opts.pluginsAreStandalone, effect);
v3_plugin_view** const vst3view = fDesc.pluginFormatName == "VST3"
? (v3_plugin_view**)editor->getPlatformSpecificData()
: nullptr;

fWindow = new JucePluginWindow(opts.frontendWinId, opts.pluginsAreStandalone,
vst2effect, vst3view);
fWindow->setName(uiName);
}



+ 5
- 0
source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp View File

@@ -1305,6 +1305,11 @@ struct VST3PluginWindow : public AudioProcessorEditor,
view = nullptr;
}
void* getPlatformSpecificData()
{
return view;
}
#if JUCE_LINUX
Steinberg::tresult PLUGIN_API queryInterface (const Steinberg::TUID iid, void** obj) override
{


+ 1
- 0
source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp View File

@@ -46,6 +46,7 @@ AudioProcessorEditor::~AudioProcessorEditor()
removeComponentListener (resizeListener.get());
}
void* AudioProcessorEditor::getPlatformSpecificData() { return nullptr; }
void AudioProcessorEditor::setControlHighlight (ParameterControlHighlightInfo) {}
int AudioProcessorEditor::getControlParameterIndex (Component&) { return -1; }


+ 5
- 0
source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h View File

@@ -55,6 +55,11 @@ public:
~AudioProcessorEditor() override;
/** Returns a pointer to some kind of platform-specific data about the plugin.
E.g. For a VST3, this value can be cast to an IPlugView*.
*/
virtual void* getPlatformSpecificData();
//==============================================================================
/** The AudioProcessor that this editor represents. */
AudioProcessor& processor;


+ 253
- 32
source/utils/JucePluginWindow.hpp View File

@@ -20,6 +20,7 @@

#include "CarlaJuceUtils.hpp"
#include "CarlaVst2Utils.hpp"
#include "CarlaVst3Utils.hpp"

#include "AppConfig.h"
#include "juce_gui_basics/juce_gui_basics.h"
@@ -43,17 +44,18 @@ namespace juce {
class JucePluginWindow : public DialogWindow
{
public:
JucePluginWindow(const uintptr_t parentId, const bool isStandalone, AEffect* const vstEffect)
JucePluginWindow(const uintptr_t parentId, const bool isStandalone,
AEffect* const vst2effect, v3_plugin_view** const vst3view)
: DialogWindow("JucePluginWindow", Colour(50, 50, 200), true, false),
fIsStandalone(isStandalone),
fClosed(false),
fShown(false),
fTransientId(parentId),
fLastKeyIndex(0),
fLastKeyValue(0),
fLastModifiers(),
fVstEffect(vstEffect)
fLastKeys(),
fVst2Effect(vst2effect),
fVst3View(vst3view)
{
carla_zeroStruct(fLastKeys);
setVisible(false);
setOpaque(true);
setResizable(false, false);
@@ -88,7 +90,7 @@ public:
if (DialogWindow::keyPressed (key))
return true;

if (fVstEffect != nullptr)
if (fVst2Effect != nullptr)
{
const int juceKeyCode = key.getKeyCode();
int vstKeyIndex = 0;
@@ -179,11 +181,150 @@ public:
else vstKeyIndex = juceKeyCode;
} while (false);

fLastKeyIndex = vstKeyIndex;
fLastKeyValue = vstKeyValue;
return fVstEffect->dispatcher (fVstEffect, effEditKeyDown,
vstKeyIndex, vstKeyValue,
nullptr, 0.0f) != 0;
fLastKeys.vst2.index = vstKeyIndex;
fLastKeys.vst2.value = vstKeyValue;
return fVst2Effect->dispatcher (fVst2Effect, effEditKeyDown, vstKeyIndex, vstKeyValue, nullptr, 0.0f) != 0;
}

if (fVst3View != nullptr)
{
const int juceKeyCode = key.getKeyCode();
const int juceKeyMods = key.getModifiers().getRawFlags();
int16_t vst3KeyChar = 0;
int16_t vst3KeyCode = 0;
int16_t vst3KeyMods = 0;

// KEY_NEXT 8
// KEY_SELECT 17
// KEY_SELECT 18
// KEY_SNAPSHOT 20
// KEY_HELP 23
// KEY_NUMLOCK 52
// KEY_SCROLL 53
// KEY_VOLUME_UP 63
// KEY_VOLUME_DOWN 64

do {
/**/ if (juceKeyCode == KeyPress::spaceKey)
{
vst3KeyChar = ' ';
vst3KeyCode = 7;
}
else if (juceKeyCode == KeyPress::escapeKey)
{
vst3KeyCode = 6;
}
else if (juceKeyCode == KeyPress::returnKey)
{
vst3KeyChar = '\n';
vst3KeyCode = 19; // NOTE: 4 is '\r' while 19 is '\n'
}
else if (juceKeyCode == KeyPress::tabKey)
{
vst3KeyChar = '\t';
vst3KeyCode = 2;
}

else if (juceKeyCode == KeyPress::deleteKey) vst3KeyCode = 22;
else if (juceKeyCode == KeyPress::backspaceKey) vst3KeyCode = 1;
else if (juceKeyCode == KeyPress::insertKey) vst3KeyCode = 21;

else if (juceKeyCode == KeyPress::upKey) vst3KeyCode = 12;
else if (juceKeyCode == KeyPress::downKey) vst3KeyCode = 14;
else if (juceKeyCode == KeyPress::leftKey) vst3KeyCode = 11;
else if (juceKeyCode == KeyPress::rightKey) vst3KeyCode = 13;
else if (juceKeyCode == KeyPress::pageUpKey) vst3KeyCode = 15;
else if (juceKeyCode == KeyPress::pageDownKey) vst3KeyCode = 16;
else if (juceKeyCode == KeyPress::homeKey) vst3KeyCode = 10;
else if (juceKeyCode == KeyPress::endKey) vst3KeyCode = 9;

else if (juceKeyCode == KeyPress::F1Key) vst3KeyCode = 40;
else if (juceKeyCode == KeyPress::F2Key) vst3KeyCode = 41;
else if (juceKeyCode == KeyPress::F3Key) vst3KeyCode = 42;
else if (juceKeyCode == KeyPress::F4Key) vst3KeyCode = 43;
else if (juceKeyCode == KeyPress::F5Key) vst3KeyCode = 44;
else if (juceKeyCode == KeyPress::F6Key) vst3KeyCode = 45;
else if (juceKeyCode == KeyPress::F7Key) vst3KeyCode = 46;
else if (juceKeyCode == KeyPress::F8Key) vst3KeyCode = 47;
else if (juceKeyCode == KeyPress::F9Key) vst3KeyCode = 48;
else if (juceKeyCode == KeyPress::F10Key) vst3KeyCode = 49;
else if (juceKeyCode == KeyPress::F11Key) vst3KeyCode = 50;
else if (juceKeyCode == KeyPress::F12Key) vst3KeyCode = 51;

else if (juceKeyCode == KeyPress::F13Key) vst3KeyCode = 65;
else if (juceKeyCode == KeyPress::F14Key) vst3KeyCode = 66;
else if (juceKeyCode == KeyPress::F15Key) vst3KeyCode = 67;
else if (juceKeyCode == KeyPress::F16Key) vst3KeyCode = 68;
else if (juceKeyCode == KeyPress::F17Key) vst3KeyCode = 69;
else if (juceKeyCode == KeyPress::F18Key) vst3KeyCode = 70;
else if (juceKeyCode == KeyPress::F19Key) vst3KeyCode = 71;
else if (juceKeyCode == KeyPress::F20Key) break;
else if (juceKeyCode == KeyPress::F21Key) break;
else if (juceKeyCode == KeyPress::F22Key) break;
else if (juceKeyCode == KeyPress::F23Key) break;
else if (juceKeyCode == KeyPress::F24Key) break;
else if (juceKeyCode == KeyPress::F25Key) break;
else if (juceKeyCode == KeyPress::F26Key) break;
else if (juceKeyCode == KeyPress::F27Key) break;
else if (juceKeyCode == KeyPress::F28Key) break;
else if (juceKeyCode == KeyPress::F29Key) break;
else if (juceKeyCode == KeyPress::F30Key) break;
else if (juceKeyCode == KeyPress::F31Key) break;
else if (juceKeyCode == KeyPress::F32Key) break;
else if (juceKeyCode == KeyPress::F33Key) break;
else if (juceKeyCode == KeyPress::F34Key) break;
else if (juceKeyCode == KeyPress::F35Key) break;

else if (juceKeyCode == KeyPress::numberPad0) vst3KeyCode = 24;
else if (juceKeyCode == KeyPress::numberPad1) vst3KeyCode = 25;
else if (juceKeyCode == KeyPress::numberPad2) vst3KeyCode = 26;
else if (juceKeyCode == KeyPress::numberPad3) vst3KeyCode = 27;
else if (juceKeyCode == KeyPress::numberPad4) vst3KeyCode = 28;
else if (juceKeyCode == KeyPress::numberPad5) vst3KeyCode = 29;
else if (juceKeyCode == KeyPress::numberPad6) vst3KeyCode = 30;
else if (juceKeyCode == KeyPress::numberPad7) vst3KeyCode = 31;
else if (juceKeyCode == KeyPress::numberPad8) vst3KeyCode = 32;
else if (juceKeyCode == KeyPress::numberPad9) vst3KeyCode = 33;

else if (juceKeyCode == KeyPress::numberPadAdd) vst3KeyCode = 35;
else if (juceKeyCode == KeyPress::numberPadSubtract) vst3KeyCode = 37;
else if (juceKeyCode == KeyPress::numberPadMultiply) vst3KeyCode = 34;
else if (juceKeyCode == KeyPress::numberPadDivide) vst3KeyCode = 39;
else if (juceKeyCode == KeyPress::numberPadSeparator) vst3KeyCode = 36;
else if (juceKeyCode == KeyPress::numberPadDecimalPoint) vst3KeyCode = 38;
else if (juceKeyCode == KeyPress::numberPadEquals) vst3KeyCode = 57;

else if (juceKeyCode == KeyPress::numberPadDelete) break;

else if (juceKeyCode == KeyPress::playKey) vst3KeyCode = 59;
else if (juceKeyCode == KeyPress::stopKey) vst3KeyCode = 60;
else if (juceKeyCode == KeyPress::fastForwardKey) vst3KeyCode = 62;
else if (juceKeyCode == KeyPress::rewindKey) vst3KeyCode = 61;

else
{
vst3KeyChar = static_cast<int16_t>(juceKeyCode);

if ((juceKeyCode >= 0x30 && juceKeyCode <= 0x39) || (juceKeyCode >= 0x41 && juceKeyCode <= 0x5A))
vst3KeyCode = static_cast<int16_t>(juceKeyCode - 0x30 + 128);
}
} while (false);

if (juceKeyMods & ModifierKeys::shiftModifier)
vst3KeyMods |= 1 << 0;
if (juceKeyMods & ModifierKeys::altModifier)
vst3KeyMods |= 1 << 1;
if (juceKeyMods & ModifierKeys::commandModifier)
vst3KeyMods |= 1 << 2;
#if JUCE_MAC || JUCE_IOS
if (juceKeyMods & ModifierKeys::ctrlModifier)
vst3KeyMods |= 1 << 3;
#endif

fLastKeys.vst3.keychar = vst3KeyChar;
fLastKeys.vst3.keycode = vst3KeyCode;
fLastKeys.vst3.keymods = vst3KeyMods;
return v3_cpp_obj(fVst3View)->on_key_down (fVst3View, vst3KeyChar, vst3KeyCode, vst3KeyMods) == V3_TRUE;
}

if (Component* const comp = getContentComponent())
@@ -197,14 +338,21 @@ public:
if (DialogWindow::keyStateChanged (isKeyDown))
return true;

if (fVstEffect != nullptr && (fLastKeyIndex != 0 || fLastKeyValue != 0) && ! isKeyDown)
if (fVst2Effect != nullptr && (fLastKeys.vst2.index != 0 || fLastKeys.vst2.value != 0) && ! isKeyDown)
{
const int vstKeyIndex = fLastKeyIndex;
const int vstKeyValue = fLastKeyValue;
fLastKeyIndex = fLastKeyValue = 0;
return fVstEffect->dispatcher (fVstEffect, effEditKeyUp,
vstKeyIndex, vstKeyValue,
nullptr, 0.0f) != 0;
const int vstKeyIndex = fLastKeys.vst2.index;
const int vstKeyValue = fLastKeys.vst2.value;
fLastKeys.vst2.index = fLastKeys.vst2.value = 0;
return fVst2Effect->dispatcher (fVst2Effect, effEditKeyUp, vstKeyIndex, vstKeyValue, nullptr, 0.0f) != 0;
}

if (fVst3View != nullptr && (fLastKeys.vst3.keychar != 0 || fLastKeys.vst3.keycode != 0) && ! isKeyDown)
{
const int16_t vst3KeyChar = fLastKeys.vst3.keychar;
const int16_t vst3KeyCode = fLastKeys.vst3.keycode;
const int16_t vst3KeyMods = fLastKeys.vst3.keymods;
fLastKeys.vst3.keychar = fLastKeys.vst3.keycode = fLastKeys.vst3.keymods = 0;
return v3_cpp_obj(fVst3View)->on_key_up (fVst3View, vst3KeyChar, vst3KeyCode, vst3KeyMods) == V3_TRUE;
}

if (Component* const comp = getContentComponent())
@@ -217,37 +365,97 @@ public:
{
DialogWindow::modifierKeysChanged (modifiers);

if (fVstEffect != nullptr)
if (fVst2Effect != nullptr)
{
const int oldRawFlags = fLastKeys.vst2.rmods;
const int newRawFlags = modifiers.getRawFlags();

if ((oldRawFlags & ModifierKeys::shiftModifier) != (newRawFlags & ModifierKeys::shiftModifier))
{
fVst2Effect->dispatcher (fVst2Effect,
(newRawFlags & ModifierKeys::shiftModifier) ? effEditKeyDown : effEditKeyUp,
0, 54, nullptr, 0.0f);
}

if ((oldRawFlags & ModifierKeys::ctrlModifier) != (newRawFlags & ModifierKeys::ctrlModifier))
{
fVst2Effect->dispatcher (fVst2Effect,
(newRawFlags & ModifierKeys::ctrlModifier) ? effEditKeyDown : effEditKeyUp,
0, 55, nullptr, 0.0f);
}

if ((oldRawFlags & ModifierKeys::altModifier) != (newRawFlags & ModifierKeys::altModifier))
{
fVst2Effect->dispatcher (fVst2Effect,
(newRawFlags & ModifierKeys::altModifier) ? effEditKeyDown : effEditKeyUp,
0, 56, nullptr, 0.0f);
}

if ((oldRawFlags & ModifierKeys::popupMenuClickModifier) != (newRawFlags & ModifierKeys::popupMenuClickModifier))
{
fVst2Effect->dispatcher (fVst2Effect,
(newRawFlags & ModifierKeys::popupMenuClickModifier) ? effEditKeyDown : effEditKeyUp,
0, 58, nullptr, 0.0f);
}

fLastKeys.vst2.rmods = newRawFlags;
}

if (fVst3View != nullptr)
{
const int oldRawFlags = fLastModifiers.getRawFlags();
const int oldRawFlags = fLastKeys.vst3.rmods;
const int newRawFlags = modifiers.getRawFlags();

if ((oldRawFlags & ModifierKeys::shiftModifier) != (newRawFlags & ModifierKeys::shiftModifier))
{
fVstEffect->dispatcher (fVstEffect, (newRawFlags & ModifierKeys::shiftModifier) ? effEditKeyDown : effEditKeyUp, 0,
54, nullptr, 0.0f);
if (newRawFlags & ModifierKeys::shiftModifier)
v3_cpp_obj(fVst3View)->on_key_down (fVst3View, 0, 54, fLastKeys.vst3.keymods);
else
v3_cpp_obj(fVst3View)->on_key_up (fVst3View, 0, 54, fLastKeys.vst3.keymods);
}

if ((oldRawFlags & ModifierKeys::ctrlModifier) != (newRawFlags & ModifierKeys::ctrlModifier))
{
fVstEffect->dispatcher (fVstEffect, (newRawFlags & ModifierKeys::ctrlModifier) ? effEditKeyDown : effEditKeyUp, 0,
55, nullptr, 0.0f);
if (newRawFlags & ModifierKeys::ctrlModifier)
v3_cpp_obj(fVst3View)->on_key_down (fVst3View, 0, 55, fLastKeys.vst3.keymods);
else
v3_cpp_obj(fVst3View)->on_key_up (fVst3View, 0, 55, fLastKeys.vst3.keymods);
}

if ((oldRawFlags & ModifierKeys::altModifier) != (newRawFlags & ModifierKeys::altModifier))
{
fVstEffect->dispatcher (fVstEffect, (newRawFlags & ModifierKeys::altModifier) ? effEditKeyDown : effEditKeyUp, 0,
56, nullptr, 0.0f);
if (newRawFlags & ModifierKeys::altModifier)
v3_cpp_obj(fVst3View)->on_key_down (fVst3View, 0, 56, fLastKeys.vst3.keymods);
else
v3_cpp_obj(fVst3View)->on_key_up (fVst3View, 0, 56, fLastKeys.vst3.keymods);
}

if ((oldRawFlags & ModifierKeys::popupMenuClickModifier) != (newRawFlags & ModifierKeys::popupMenuClickModifier))
{
fVstEffect->dispatcher (fVstEffect, (newRawFlags & ModifierKeys::popupMenuClickModifier) ? effEditKeyDown : effEditKeyUp, 0,
58, nullptr, 0.0f);
if (newRawFlags & ModifierKeys::popupMenuClickModifier)
v3_cpp_obj(fVst3View)->on_key_down (fVst3View, 0, 58, fLastKeys.vst3.keymods);
else
v3_cpp_obj(fVst3View)->on_key_up (fVst3View, 0, 58, fLastKeys.vst3.keymods);
}

fLastKeys.vst3.rmods = newRawFlags;
}
}

void focusGained (const FocusChangeType cause) override
{
DialogWindow::focusGained (cause);

if (fVst3View != nullptr)
v3_cpp_obj(fVst3View)->on_focus (fVst3View, true);
}

void focusLost (const FocusChangeType cause)
{
if (fVst3View != nullptr)
v3_cpp_obj(fVst3View)->on_focus (fVst3View, false);

fLastModifiers = modifiers;
DialogWindow::focusLost (cause);
}

void hide()
@@ -306,9 +514,22 @@ private:
volatile bool fClosed;
bool fShown;
const uintptr_t fTransientId;
int fLastKeyIndex, fLastKeyValue;
ModifierKeys fLastModifiers;
AEffect* const fVstEffect;
union {
struct {
int index;
int value;
int rmods;
} vst2;

struct {
int16_t keychar;
int16_t keycode;
int16_t keymods;
int rmods;
} vst3;
} fLastKeys;
AEffect* const fVst2Effect;
v3_plugin_view** const fVst3View;

void setTransient()
{


Loading…
Cancel
Save