Old 11-07-2021, 12:53 PM   #1
kartalex
Human being with feelings
 
Join Date: Dec 2015
Posts: 172
Default Script Request: add shortcut to run script

Hi, guys!

Is it possible to add keyboard shortcut programmaticaly to run a specific script (or maybe this script itself)

For example, I would place this into the start of the script and it would assign a shortcut to itself after I ran it for the first time in Reaper.
kartalex is offline   Reply With Quote
Old 11-08-2021, 01:06 PM   #2
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,630
Default

Adding shortcuts is possible by adding/replacing them in the reaper-kb.ini directly but that needs a restart of Reaper for it to be accepted as shortcut.
There's no way to do it easily while Reaper is running.

There are possible hacks, but they are not easy to pull off and might fail under certain conditions.
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...
Meo-Ada Mespotine is offline   Reply With Quote
Old 11-08-2021, 03:13 PM   #3
jrk
Human being with feelings
 
Join Date: Aug 2015
Posts: 2,969
Default

Quote:
Originally Posted by kartalex View Post
Is it possible to add keyboard shortcut programmaticaly to run a specific script (or maybe this script itself)

There will be another, easier way to do what you're trying to do. What are you trying to do?

(see also https://en.wikipedia.org/wiki/Fundam...re_engineering)
__________________
it's meant to sound like that...
jrk is offline   Reply With Quote
Old 11-09-2021, 03:32 PM   #4
kartalex
Human being with feelings
 
Join Date: Dec 2015
Posts: 172
Default

Quote:
Originally Posted by jrk View Post
There will be another, easier way to do what you're trying to do. What are you trying to do?

(see also https://en.wikipedia.org/wiki/Fundam...re_engineering)
Thanks for the link, I love to read and learn things.

I wanted the script to make keyboard shortcuts. It may have different uses.

For example: - I write a new script, and I want it to register a shortcut for it automatically.(I hate doing it traditional way, looking for script, pressing Add Shortcut, pressing shortcuts, Are you shure, etc, and if you want to change - doing it again) I always try to optimize things, and making something like

AssignShortcut("ctrl+x", "SomeScript.lua")

would make things easier for me.



Meo-Ada Mespotine, what hacks are possible? Is it makeable via Lua?

Last edited by kartalex; 11-09-2021 at 03:45 PM.
kartalex is offline   Reply With Quote
Old 11-10-2021, 01:41 AM   #5
jrk
Human being with feelings
 
Join Date: Aug 2015
Posts: 2,969
Default

Quote:
Originally Posted by kartalex View Post
Thanks for the link, I love to read and learn things.
That's promising.

So, you want (a script) to add (arbitrary, multiple) shortcuts, bound to scripts specified at the time of execution? Is that right? Just as a sort of general thing, in case it comes in handy, without a particular use-case in mind.

Other than hard-coding it, as above (which has obvious shortcomings), how do you specify the shortcut / script?
I guess you've already dismissed JS_Actions_DoShortcutDialog ?
__________________
it's meant to sound like that...

Last edited by jrk; 11-10-2021 at 02:00 AM.
jrk is offline   Reply With Quote
Old 11-11-2021, 04:52 AM   #6
kartalex
Human being with feelings
 
Join Date: Dec 2015
Posts: 172
Default

Quote:
Originally Posted by jrk View Post
I guess you've already dismissed JS_Actions_DoShortcutDialog ?
Yes, somehow I didn't find it in the Reascript reference, thank you)

But how does it work?

Code:
 reaper.JS_Actions_DeleteShortcut( section, cmdID, shortcutidx )
I guess cmdID is return by 'reaper.get_action_context()', and what is 'shortcutidx'?

Code:
_,_,sectionID,cmdID,_,_,_= reaper.get_action_context()
shortcutidx =  reaper.JS_Actions_CountShortcuts( sectionID, cmdID ) +1
reaper.JS_Actions_DoShortcutDialog( sectionID, cmdID, shortcutidx )
Should it be like that?

Last edited by kartalex; 11-11-2021 at 05:03 AM.
kartalex is offline   Reply With Quote
Old 11-11-2021, 09:13 AM   #7
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,630
Default

It opens the Add Shortcut Dialog, so you can enter the shortcut by hand.

Under certain circumstances, it's possible to send the shortcut via script but this needs a terrible workaround with a backgroundscript, that you need to start before opening the dialog.

Run the backgroundscript, that will send shortcut and set the options of the Add Shortcut-Dialog.
Then the background script needs to wait until the dialog is opened, which is opened by the original script.

Then, in the backgroundscript, you send the shortcut via StuffMidiMessage.
Then you select all options in the dialog using various JS-extension-functions.
Then you send a mouseclick-event to the OK-button and end the background script.

And, if the shortcut is already associated, another window will open asking you, if you want to overwrite the existing shortcut. You need to deal with it the same way you dealt with the Add Shortcut-Dialog.

This all might work, but only, if you start the background-script from a non-background-script, as the dialogs are modal dialogs, that might pause background-scripts.
So your backgroundscript, that sends the shortcut and sets the options in the window might be paused and never execute itself, while the window is open.

It's tedious and not reliable. If it were, I would have added it to my Ultraschall-Api, so you could add shortcuts using a simple function, while my code does the rest for you.
Adding shortcuts is a long standing feature wish by me but all attempts I tried weren't functional under certain circumstances and there's nothing, you can do about it, if you run into it.

You can try anyway, maybe your usecase is one of the usecases, that work reliably. But it's advanced and needs some experience with scripting, backgroundscripts and dealing with ui-elements of dialogs.
And the acceptance, that it still might not work.
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...
Meo-Ada Mespotine is offline   Reply With Quote
Old 11-15-2021, 11:51 PM   #8
jrk
Human being with feelings
 
Join Date: Aug 2015
Posts: 2,969
Default

Well, the only time I've had cause to do anything like this, I used a "dispatcher" script, previously bound to the key-combination of interest, which looks up (via GetExtState) the actual script / action which you want to run. Maybe something like this would work for you.
__________________
it's meant to sound like that...

Last edited by jrk; 11-16-2021 at 12:53 AM.
jrk is offline   Reply With Quote
Old 11-16-2021, 01:46 PM   #9
kartalex
Human being with feelings
 
Join Date: Dec 2015
Posts: 172
Default

Quote:
Originally Posted by jrk View Post
Well, the only time I've had cause to do anything like this, I used a "dispatcher" script, previously bound to the key-combination of interest, which looks up (via GetExtState) the actual script / action which you want to run. Maybe something like this would work for you.
Do you mean, that shortcuts were not reassigned, but scripts? You assign a constant shortcut to a script, which runs another script depending on chosen "mode", but shortcuts themselves are constant?
kartalex is offline   Reply With Quote
Old 11-17-2021, 12:20 AM   #10
jrk
Human being with feelings
 
Join Date: Aug 2015
Posts: 2,969
Default

Yep, that was the idea.
__________________
it's meant to sound like that...
jrk is offline   Reply With Quote
Old 11-17-2021, 02:09 PM   #11
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,630
Default

That's really clever!
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...
Meo-Ada Mespotine is offline   Reply With Quote
Old 11-17-2021, 02:20 PM   #12
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,202
Default

Was thinking about this today. I've previously generated keymap files for new scripts, which can then be imported through the actionlist (via GUI). Maybe it's possible to import a keymap automatically with a bit of JS_ReaScriptAPI magic?
__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi
FeedTheCat is offline   Reply With Quote
Old 11-17-2021, 03:35 PM   #13
TonE
Human being with feelings
 
Join Date: Feb 2009
Location: Reaper HAS send control via midi !!!
Posts: 4,032
Default

Quote:
Originally Posted by kartalex View Post
Do you mean, that shortcuts were not reassigned, but scripts? You assign a constant shortcut to a script, which runs another script depending on chosen "mode", but shortcuts themselves are constant?
Afaik, vimper does just this. Using vi style.
TonE is offline   Reply With Quote
Old 11-22-2021, 12:29 AM   #14
jrk
Human being with feelings
 
Join Date: Aug 2015
Posts: 2,969
Default

So, to clarify, you could do something like... (Examples in EEL)

In a ("despatcher") script which you would bind to the shortcut of interest:
Code:
GetExtState(#retval, "Main", "JRK_MAGIC_CMD_ID");
match("%{command}i", #retval);
Main_OnCommandEx(command, 0, 0);
And then in your script(s) which you want to execute on that shortcut:
Code:
get_action_context(#filename,sectionID,cmdID,mode,resolution,val);
SetExtState("Main", "JRK_MAGIC_CMD_ID", sprintf(#,"%i",cmdID), false);
i.e. the first time the script containing the second fragment runs, it registers its cmdID with SetExtState, and from then on, will be executed (via the despatcher) when you hit the shortcut. Which is more-or-less what the OP was asking for.
__________________
it's meant to sound like that...

Last edited by jrk; 11-22-2021 at 12:50 AM.
jrk is offline   Reply With Quote
Old 01-18-2022, 12:32 PM   #15
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,202
Default

Quote:
Originally Posted by FeedTheCat View Post
Was thinking about this today. I've previously generated keymap files for new scripts, which can then be imported through the actionlist (via GUI). Maybe it's possible to import a keymap automatically with a bit of JS_ReaScriptAPI magic?
Finally managed to do it, so I'll post the code here for anyone interested

Note 1: Couldn't get it working on MacOS (didn't try much though)
Note 2: The code only works for script shortcuts, but can definitely be adjusted to work with build in actions etc.



This is how you end up setting the shortcuts Shift+A, Shift+B, Shift+C.
Code:
local cmd_id = '_RS9af7560ae90e62807501bc6649dca19afddc45b2'
KeyMap_AddShortcut(0, cmd_id, 21, 65)
KeyMap_AddShortcut(0, cmd_id, 21, 66)
KeyMap_AddShortcut(0, cmd_id, 21, 67)
KeyMap_Import()
This is the full code:
Code:
local key_map_name = 'auto_import.ReaperKeyMap'

local function print(msg) reaper.ShowConsoleMsg(tostring(msg) .. '\n') end

function ConcatPath(...) return table.concat({...}, package.config:sub(1, 1)) end

function PostKey(hwnd, vk_code)
    reaper.JS_WindowMessage_Post(hwnd, 'WM_KEYDOWN', vk_code, 0, 0, 0)
    reaper.JS_WindowMessage_Post(hwnd, 'WM_KEYUP', vk_code, 0, 0, 0)
end

function KeyMap_AddShortcut(section, cmd_id, key1, key2)
    -- Remove leading underscore (if present)
    cmd_id = cmd_id:gsub('^_', '')

    -- Look up line where command id is mentioned in reaper-kb.ini
    local res_path = reaper.GetResourcePath()
    local kb_ini_path = ConcatPath(res_path, 'reaper-kb.ini')
    local file = io.open(kb_ini_path, 'r')
    local key = section .. ' ' .. cmd_id .. ' "Custom:'
    local ini_line

    for line in file:lines() do
        if line:match(key) then
            ini_line = line
            break
        end
    end

    if not ini_line then
        local msg = 'Command not found!\nCmdID:%s\nSection:%s\n'
        reaper.ShowConsoleMsg(msg:format(cmd_id, section))
        return
    end

    -- Create content for key map file
    local key = ('\nKEY %s %s _%s %s\n'):format(key1, key2, cmd_id, section)
    local key_map_content = ini_line .. key

    -- Write content to key map file
    local res_path = reaper.GetResourcePath()
    local key_map_path = ConcatPath(res_path, 'KeyMaps', key_map_name)
    local key_map = io.open(key_map_path, 'a')
    key_map:write(key_map_content)
    key_map:close()
end

function CleanUp()
    -- Close action list (if it wasn't open before)
    if not is_action_list_open then
        local actions_hwnd_title = reaper.JS_Localize('Actions', 'common')
        local actions_hwnd = reaper.JS_Window_Find(actions_hwnd_title, true)
        reaper.JS_Window_Destroy(actions_hwnd)
    end
    -- Delete key_map file
    local res_path = reaper.GetResourcePath()
    local key_map_path = ConcatPath(res_path, 'KeyMaps', key_map_name)
    os.remove(key_map_path)
end

function SelectKeyMap()
    local key_map_hwnd_title = reaper.JS_Localize('Choose key map to open:',
                                                  'common')
    local key_map_hwnd = reaper.JS_Window_Find(key_map_hwnd_title, true)
    local is_windows = reaper.GetOS():match('Win')
    local id = is_windows and 1148 or 256
    local key_map_text = reaper.JS_Window_FindChildByID(key_map_hwnd, id)

    -- Insert keymap name into text field
    reaper.JS_Window_SetTitle(key_map_text, key_map_name)

    -- Press key: Enter
    PostKey(key_map_text, 0x0D)
    reaper.defer(CleanUp)
end

function OpenFirstMenuItem()
    local is_windows = reaper.GetOS():match('Win')
    local class_name = is_windows and '#32768' or '__SWELL_MENU'
    local ret, list = reaper.JS_Window_ListAllTop()
    for address in string.gmatch(list .. ',', '[^,]+') do
        local hwnd = reaper.JS_Window_HandleFromAddress(address)
        if reaper.JS_Window_GetClassName(hwnd) == class_name then
            -- Press key: Down arrow
            PostKey(hwnd, 0x28)
            -- Press key: Enter
            PostKey(hwnd, 0x0D)
            reaper.defer(SelectKeyMap)
            return
        end
    end
    if not init_time then init_time = reaper.time_precise() end
    if reaper.time_precise() - init_time > 2 then
        print('Could not find open menu!')
        return
    end
    reaper.defer(OpenFirstMenuItem)
end

function KeyMap_Import()
    -- Ensure action list is open
    local actions_hwnd_title = reaper.JS_Localize('Actions', 'common')
    is_action_list_open = reaper.JS_Window_Find(actions_hwnd_title, true) ~= nil
    if not is_action_list_open then reaper.ShowActionList() end

    -- Press button 'Key map...' to open its menu
    local actions_hwnd_title = reaper.JS_Localize('Actions', 'common')
    local actions_hwnd = reaper.JS_Window_Find(actions_hwnd_title, true)
    local key_map_button = reaper.JS_Window_FindChildByID(actions_hwnd, 6)
    reaper.JS_WindowMessage_Post(key_map_button, 'WM_LBUTTONDOWN', 0, 0, 0, 0)
    reaper.JS_WindowMessage_Post(key_map_button, 'WM_LBUTTONUP', 0, 0, 0, 0)

    reaper.defer(OpenFirstMenuItem)
end

local cmd_id = '_RS9af7560ae90e62807501bc6649dca19afddc45b2'
KeyMap_AddShortcut(0, cmd_id, 21, 65)
KeyMap_AddShortcut(0, cmd_id, 21, 66)
KeyMap_AddShortcut(0, cmd_id, 21, 67)
KeyMap_Import()
__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi
FeedTheCat is offline   Reply With Quote
Old 01-19-2022, 11:40 PM   #16
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,630
Default

Quote:
Originally Posted by FeedTheCat View Post
Finally managed to do it, so I'll post the code here for anyone interested

Note 1: Couldn't get it working on MacOS (didn't try much though)
Note 2: The code only works for script shortcuts, but can definitely be adjusted to work with build in actions etc.



This is how you end up setting the shortcuts Shift+A, Shift+B, Shift+C.
Code:
local cmd_id = '_RS9af7560ae90e62807501bc6649dca19afddc45b2'
KeyMap_AddShortcut(0, cmd_id, 21, 65)
KeyMap_AddShortcut(0, cmd_id, 21, 66)
KeyMap_AddShortcut(0, cmd_id, 21, 67)
KeyMap_Import()
This is the full code:
Code:
local key_map_name = 'auto_import.ReaperKeyMap'

local function print(msg) reaper.ShowConsoleMsg(tostring(msg) .. '\n') end

function ConcatPath(...) return table.concat({...}, package.config:sub(1, 1)) end

function PostKey(hwnd, vk_code)
    reaper.JS_WindowMessage_Post(hwnd, 'WM_KEYDOWN', vk_code, 0, 0, 0)
    reaper.JS_WindowMessage_Post(hwnd, 'WM_KEYUP', vk_code, 0, 0, 0)
end

function KeyMap_AddShortcut(section, cmd_id, key1, key2)
    -- Remove leading underscore (if present)
    cmd_id = cmd_id:gsub('^_', '')

    -- Look up line where command id is mentioned in reaper-kb.ini
    local res_path = reaper.GetResourcePath()
    local kb_ini_path = ConcatPath(res_path, 'reaper-kb.ini')
    local file = io.open(kb_ini_path, 'r')
    local key = section .. ' ' .. cmd_id .. ' "Custom:'
    local ini_line

    for line in file:lines() do
        if line:match(key) then
            ini_line = line
            break
        end
    end

    if not ini_line then
        local msg = 'Command not found!\nCmdID:%s\nSection:%s\n'
        reaper.ShowConsoleMsg(msg:format(cmd_id, section))
        return
    end

    -- Create content for key map file
    local key = ('\nKEY %s %s _%s %s\n'):format(key1, key2, cmd_id, section)
    local key_map_content = ini_line .. key

    -- Write content to key map file
    local res_path = reaper.GetResourcePath()
    local key_map_path = ConcatPath(res_path, 'KeyMaps', key_map_name)
    local key_map = io.open(key_map_path, 'a')
    key_map:write(key_map_content)
    key_map:close()
end

function CleanUp()
    -- Close action list (if it wasn't open before)
    if not is_action_list_open then
        local actions_hwnd_title = reaper.JS_Localize('Actions', 'common')
        local actions_hwnd = reaper.JS_Window_Find(actions_hwnd_title, true)
        reaper.JS_Window_Destroy(actions_hwnd)
    end
    -- Delete key_map file
    local res_path = reaper.GetResourcePath()
    local key_map_path = ConcatPath(res_path, 'KeyMaps', key_map_name)
    os.remove(key_map_path)
end

function SelectKeyMap()
    local key_map_hwnd_title = reaper.JS_Localize('Choose key map to open:',
                                                  'common')
    local key_map_hwnd = reaper.JS_Window_Find(key_map_hwnd_title, true)
    local is_windows = reaper.GetOS():match('Win')
    local id = is_windows and 1148 or 256
    local key_map_text = reaper.JS_Window_FindChildByID(key_map_hwnd, id)

    -- Insert keymap name into text field
    reaper.JS_Window_SetTitle(key_map_text, key_map_name)

    -- Press key: Enter
    PostKey(key_map_text, 0x0D)
    reaper.defer(CleanUp)
end

function OpenFirstMenuItem()
    local is_windows = reaper.GetOS():match('Win')
    local class_name = is_windows and '#32768' or '__SWELL_MENU'
    local ret, list = reaper.JS_Window_ListAllTop()
    for address in string.gmatch(list .. ',', '[^,]+') do
        local hwnd = reaper.JS_Window_HandleFromAddress(address)
        if reaper.JS_Window_GetClassName(hwnd) == class_name then
            -- Press key: Down arrow
            PostKey(hwnd, 0x28)
            -- Press key: Enter
            PostKey(hwnd, 0x0D)
            reaper.defer(SelectKeyMap)
            return
        end
    end
    if not init_time then init_time = reaper.time_precise() end
    if reaper.time_precise() - init_time > 2 then
        print('Could not find open menu!')
        return
    end
    reaper.defer(OpenFirstMenuItem)
end

function KeyMap_Import()
    -- Ensure action list is open
    local actions_hwnd_title = reaper.JS_Localize('Actions', 'common')
    is_action_list_open = reaper.JS_Window_Find(actions_hwnd_title, true) ~= nil
    if not is_action_list_open then reaper.ShowActionList() end

    -- Press button 'Key map...' to open its menu
    local actions_hwnd_title = reaper.JS_Localize('Actions', 'common')
    local actions_hwnd = reaper.JS_Window_Find(actions_hwnd_title, true)
    local key_map_button = reaper.JS_Window_FindChildByID(actions_hwnd, 6)
    reaper.JS_WindowMessage_Post(key_map_button, 'WM_LBUTTONDOWN', 0, 0, 0, 0)
    reaper.JS_WindowMessage_Post(key_map_button, 'WM_LBUTTONUP', 0, 0, 0, 0)

    reaper.defer(OpenFirstMenuItem)
end

local cmd_id = '_RS9af7560ae90e62807501bc6649dca19afddc45b2'
KeyMap_AddShortcut(0, cmd_id, 21, 65)
KeyMap_AddShortcut(0, cmd_id, 21, 66)
KeyMap_AddShortcut(0, cmd_id, 21, 67)
KeyMap_Import()


Wait a sec: do I get it right, that you add a shortcut by just adding the name of it into the Shortcut-field of the accompanying action in the actionlist? O_O
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...

Last edited by Meo-Ada Mespotine; 01-19-2022 at 11:48 PM.
Meo-Ada Mespotine is offline   Reply With Quote
Old 01-20-2022, 02:35 AM   #17
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,202
Default

Quote:
Originally Posted by Meo-Ada Mespotine View Post
Wait a sec: do I get it right, that you add a shortcut by just adding the name of it into the Shortcut-field of the accompanying action in the actionlist? O_O
It was kind of late, so I did a horrible job explaining Let me give it another try:

I'm using two functions.

1. KeyMap_AddShortcut(sectionID, commandID, key1, key2)

Creates a temporary .ReaperKeyMap file and adds shortcuts for scripts based on their sectionID and commandID. The shortcuts are in the form of key1 and key2, which are the cryptic values used in the reaper-kb.ini. You call them ModifierValue and Key_Note_Value in your documentation.

2. KeyMap_Import

Uses js_ReascriptAPI to automatically import the temporary .ReaperKeyMap file and deletes it when it's done.

Edit: It's probably also not clear what I'm doing in the gif... I'm running the test_shortcuts.lua script, which programmatically adds shortcuts to test_shorcuts2.lua
__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi

Last edited by FeedTheCat; 01-20-2022 at 02:43 AM.
FeedTheCat is offline   Reply With Quote
Old 03-19-2024, 11:57 AM   #18
rcook
Human being with feelings
 
Join Date: Jan 2021
Location: Seattle, Washington
Posts: 6
Default

This is great! It works nicely on Windows. Has anybody been able to confirm if it works on macOS? At least for me, the WM_LBUTTONDOWN and WM_LBUTTONUP message do not seem to activate the "Key map..." button on macOS:

Code:
reaper.JS_WindowMessage_Post(key_map_button, 'WM_LBUTTONDOWN', 0, 0, 0, 0)
reaper.JS_WindowMessage_Post(key_map_button, 'WM_LBUTTONUP', 0, 0, 0, 0)

Quote:
Originally Posted by FeedTheCat View Post
Finally managed to do it, so I'll post the code here for anyone interested

Note 1: Couldn't get it working on MacOS (didn't try much though)
Note 2: The code only works for script shortcuts, but can definitely be adjusted to work with build in actions etc.



This is how you end up setting the shortcuts Shift+A, Shift+B, Shift+C.
Code:
local cmd_id = '_RS9af7560ae90e62807501bc6649dca19afddc45b2'
KeyMap_AddShortcut(0, cmd_id, 21, 65)
KeyMap_AddShortcut(0, cmd_id, 21, 66)
KeyMap_AddShortcut(0, cmd_id, 21, 67)
KeyMap_Import()
This is the full code:
Code:
local key_map_name = 'auto_import.ReaperKeyMap'

local function print(msg) reaper.ShowConsoleMsg(tostring(msg) .. '\n') end

function ConcatPath(...) return table.concat({...}, package.config:sub(1, 1)) end

function PostKey(hwnd, vk_code)
    reaper.JS_WindowMessage_Post(hwnd, 'WM_KEYDOWN', vk_code, 0, 0, 0)
    reaper.JS_WindowMessage_Post(hwnd, 'WM_KEYUP', vk_code, 0, 0, 0)
end

function KeyMap_AddShortcut(section, cmd_id, key1, key2)
    -- Remove leading underscore (if present)
    cmd_id = cmd_id:gsub('^_', '')

    -- Look up line where command id is mentioned in reaper-kb.ini
    local res_path = reaper.GetResourcePath()
    local kb_ini_path = ConcatPath(res_path, 'reaper-kb.ini')
    local file = io.open(kb_ini_path, 'r')
    local key = section .. ' ' .. cmd_id .. ' "Custom:'
    local ini_line

    for line in file:lines() do
        if line:match(key) then
            ini_line = line
            break
        end
    end

    if not ini_line then
        local msg = 'Command not found!\nCmdID:%s\nSection:%s\n'
        reaper.ShowConsoleMsg(msg:format(cmd_id, section))
        return
    end

    -- Create content for key map file
    local key = ('\nKEY %s %s _%s %s\n'):format(key1, key2, cmd_id, section)
    local key_map_content = ini_line .. key

    -- Write content to key map file
    local res_path = reaper.GetResourcePath()
    local key_map_path = ConcatPath(res_path, 'KeyMaps', key_map_name)
    local key_map = io.open(key_map_path, 'a')
    key_map:write(key_map_content)
    key_map:close()
end

function CleanUp()
    -- Close action list (if it wasn't open before)
    if not is_action_list_open then
        local actions_hwnd_title = reaper.JS_Localize('Actions', 'common')
        local actions_hwnd = reaper.JS_Window_Find(actions_hwnd_title, true)
        reaper.JS_Window_Destroy(actions_hwnd)
    end
    -- Delete key_map file
    local res_path = reaper.GetResourcePath()
    local key_map_path = ConcatPath(res_path, 'KeyMaps', key_map_name)
    os.remove(key_map_path)
end

function SelectKeyMap()
    local key_map_hwnd_title = reaper.JS_Localize('Choose key map to open:',
                                                  'common')
    local key_map_hwnd = reaper.JS_Window_Find(key_map_hwnd_title, true)
    local is_windows = reaper.GetOS():match('Win')
    local id = is_windows and 1148 or 256
    local key_map_text = reaper.JS_Window_FindChildByID(key_map_hwnd, id)

    -- Insert keymap name into text field
    reaper.JS_Window_SetTitle(key_map_text, key_map_name)

    -- Press key: Enter
    PostKey(key_map_text, 0x0D)
    reaper.defer(CleanUp)
end

function OpenFirstMenuItem()
    local is_windows = reaper.GetOS():match('Win')
    local class_name = is_windows and '#32768' or '__SWELL_MENU'
    local ret, list = reaper.JS_Window_ListAllTop()
    for address in string.gmatch(list .. ',', '[^,]+') do
        local hwnd = reaper.JS_Window_HandleFromAddress(address)
        if reaper.JS_Window_GetClassName(hwnd) == class_name then
            -- Press key: Down arrow
            PostKey(hwnd, 0x28)
            -- Press key: Enter
            PostKey(hwnd, 0x0D)
            reaper.defer(SelectKeyMap)
            return
        end
    end
    if not init_time then init_time = reaper.time_precise() end
    if reaper.time_precise() - init_time > 2 then
        print('Could not find open menu!')
        return
    end
    reaper.defer(OpenFirstMenuItem)
end

function KeyMap_Import()
    -- Ensure action list is open
    local actions_hwnd_title = reaper.JS_Localize('Actions', 'common')
    is_action_list_open = reaper.JS_Window_Find(actions_hwnd_title, true) ~= nil
    if not is_action_list_open then reaper.ShowActionList() end

    -- Press button 'Key map...' to open its menu
    local actions_hwnd_title = reaper.JS_Localize('Actions', 'common')
    local actions_hwnd = reaper.JS_Window_Find(actions_hwnd_title, true)
    local key_map_button = reaper.JS_Window_FindChildByID(actions_hwnd, 6)
    reaper.JS_WindowMessage_Post(key_map_button, 'WM_LBUTTONDOWN', 0, 0, 0, 0)
    reaper.JS_WindowMessage_Post(key_map_button, 'WM_LBUTTONUP', 0, 0, 0, 0)

    reaper.defer(OpenFirstMenuItem)
end

local cmd_id = '_RS9af7560ae90e62807501bc6649dca19afddc45b2'
KeyMap_AddShortcut(0, cmd_id, 21, 65)
KeyMap_AddShortcut(0, cmd_id, 21, 66)
KeyMap_AddShortcut(0, cmd_id, 21, 67)
KeyMap_Import()
rcook is offline   Reply With Quote
Old 03-19-2024, 12:05 PM   #19
MonkeyBars
Human being with feelings
 
MonkeyBars's Avatar
 
Join Date: Feb 2016
Location: Hollyweird
Posts: 2,637
Default

this is naughty and you shouldn't do it lol

or maybe only as part of a whole system as with ReaClassical which uses a command line trigger to effect the shortcut population
MonkeyBars is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 08:37 PM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.