Register new action from C++ CSurf plugin - Cockos

tutorialdaw-reaper

Register new action from C++/CSurf plugin? - Cockos Incorporated Forums

Register new action from C++/CSurf plugin?

04-29-2024, 02:44 PM

  #1

Reaktor:[Dave]

Human being with feelings

 

 

Join Date: Jun 2010

Location: Berlin

Posts: 600

Register new action from C++/CSurf plugin?

Is there a concise example of how a C++ REAPER SDK control surface plugin can register a new action in REAPER’s action list?

Also, what is the best strategy to ensure that the new action can target a specific instance? The idea is to change an instance setting via an action.

 

04-29-2024, 03:28 PM

  #2

cfillion

Human being with feelings

 

 

Join Date: May 2015

Location: Québec, Canada

Posts: 5,174

Code:

constexpr int SECTION_MAIN { 0 }; static int actionId; static custom_action_register_t actionReg { SECTION_MAIN, “MYEXT_ACTIONID”, “My extension: Description of the action”}; static bool commandHook(const int id, maybe_unused const int flag) { if(id == actionId) { runTheAction(); return true; } return false; } // global setup plugin_register(“hookcommand”, reinterpret_cast<void *>(&commandHook)); // action setup actionId = plugin_register(“custom_action”, &actionReg); // action teardown plugin_register(“-custom_action”, &actionReg); // global teardown plugin_register(“-hookcommand”, reinterpret_cast<void *>(&commandHook));

As for the ‘targeting a specific instance’, maybe register one action per instance and identify it by the action ID?

(The custom_action_register_t doesn’t need to be global. I only did that to simplify the example.)


💖 Donate (PayPal) | Sponsor (GitHub) | The Endless Journey (Keyboard Ensemble) ReaPack, a package manager for REAPER | SWS 2.14 is now available in ReaPack [new!] Developer tools: Lua profiler | Interactive ReaScript | ReaPack Editor | ReaImGui

Last edited by cfillion; 04-29-2024 at 03:34 PM.

 

05-15-2024, 07:26 AM

  #3

Reaktor:[Dave]

Human being with feelings

 

 

Join Date: Jun 2010

Location: Berlin

Posts: 600

Thank you so much for your help!

I’m getting an entry in the action list when doing it like you suggested, but when I press on “Run” with the action selected, I’m not receiving a call from REAPER.

Here’s a breakdown of how I implemented it:

Code:

// mycontrollerplugin.h class mycontrollerplugin : public IReaperControlSurface { static constexpr int SECTION_MAIN { 0 }; static int actionId; custom_action_register_t actionReg { SECTION_MAIN, “MYEXT_ACTIONID”, “My extension: Description of the action” }; static bool commandHook(const int id, maybe_unused const int flag); } // mycontrollerplugin.cpp bool mycontrollerplugin::commandHook(const int id, const int flag) { if (id == actionId) { // runTheAction(); return true; } return false; } int mycontrollerplugin::actionId = 0; mycontrollerplugin::mycontrollerplugin( int size, int indev, int outdev, int* errStats) { Plugin_Register(“hookcommand”, reinterpret_cast<void *>(&commandHook)); actionId = Plugin_Register(“custom_action”, &actionReg); } mycontrollerplugin::~mycontrollerplugin() { Plugin_Register(“-custom_action”, &actionReg); Plugin_Register(“-hookcommand”, reinterpret_cast<void *>(&commandHook)); }

I’d expect REAPER to call mycontrollerplugin::commandHook() with the parameter “id” set to the actionId that REAPER returned in the class constructor when I run the registered action from the action list. But it never calls that function. Only when quitting REAPER, it’ll call mycontrollerplugin::commandHook().

Any idea what I’m doing wrong here?

 

05-18-2024, 01:51 AM

  #4

Reaktor:[Dave]

Human being with feelings

 

 

Join Date: Jun 2010

Location: Berlin

Posts: 600

I debugged this a bit more.

  1. Registering the hookcommand in the constructor returns an int value of 1. I guess that means success? It’s not defined in reaper_plugin.h

  2. Registering the custom action returns an int (59001 in my case) that can be used to identify the registered action later when hookcommand is called. Does that seem alright?

  3. While the registered static function commandHook is never called when running the new action from the action list, the function gets called on other events:

  • opening the action list window (id 40605)
  • creating a new track (id 40001)
  • closing the project right before the save-on-exit-dialog (40004)

This implies that the registration of the command hook was successful. Maybe there was an issue when registering the new action?

 

05-18-2024, 02:07 AM

  #5

cfillion

Human being with feelings

 

 

Join Date: May 2015

Location: Québec, Canada

Posts: 5,174

Oops, actions registered with custom_action only run hookcommand2. hookcommand gets called for native main section actions or extension actions registered with command_id+gaccel.

Code:

bool hookCommand2(KbdSectionInfo *sec, int command, int val, int val2, int relmode, HWND hwnd);

For reference, the command_id+gaccel way is pretty similar, except it’s main section only, can specify a default shortcut and the gaccel_register_t’s lifetime must be as long as the action is registered (custom_action_t may be temporary).

Code:

static gaccel_register_t cmd; cmd.accel.cmd = plugin_register(“command_id”, “ACTION_ID”); cmd.desc = “Description of the action”; plugin_register(“gaccel”, &cmd);


💖 Donate (PayPal) | Sponsor (GitHub) | The Endless Journey (Keyboard Ensemble) ReaPack, a package manager for REAPER | SWS 2.14 is now available in ReaPack [new!] Developer tools: Lua profiler | Interactive ReaScript | ReaPack Editor | ReaImGui

Last edited by cfillion; 05-18-2024 at 02:13 AM.

 

05-18-2024, 02:24 PM

  #6

Reaktor:[Dave]

Human being with feelings

 

 

Join Date: Jun 2010

Location: Berlin

Posts: 600

Ah, that makes it all work! Thank you so much!

Here’s how to make my previous example work:

Code:

// mycontrollerplugin.h class mycontrollerplugin : public IReaperControlSurface { static constexpr int SECTION_MAIN { 0 }; static int actionId; custom_action_register_t actionReg { SECTION_MAIN, “MYEXT_ACTIONID”, “My extension: Description of the action” }; static bool commandHook2(KbdSectionInfo *sec, int command, int val, int val2, int relmode, HWND hwnd); } // mycontrollerplugin.cpp bool mycontrollerplugin::commandHook2(KbdSectionInfo sec, int command, int val, int val2, int relmode, HWND hwnd) { if (command == actionId) { // runTheAction(); return true; } return false; } int mycontrollerplugin::actionId = 0; mycontrollerplugin::mycontrollerplugin( int size, int indev, int outdev, int errStats) { Plugin_Register(“hookcommand2”, reinterpret_cast<void *>(&commandHook2)); actionId = Plugin_Register(“custom_action”, &actionReg); } mycontrollerplugin::~mycontrollerplugin() { Plugin_Register(“-custom_action”, &actionReg); Plugin_Register(“-hookcommand”, reinterpret_cast<void *>(&commandHook2)); }

Targeting specific instances can be done as suggested previously, by doing the action setup per instance and storing the return value from Plugin_Register(“custom_action”, …) in a static map with the corresponding function pointer.

Last edited by Reaktor:[Dave]; 05-19-2024 at 04:54 AM.