Old 12-06-2018, 06:05 AM   #121
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 4,909
Default

Just tested and it works here, though I get a leading null byte which isn't there on Windows. Are you're using the IDE or ShowConsoleMsg? They won't show anything past a null byte.



Windows (only the first path is absolute?):



(Also can't seem to make it accept all or no file extensions on macOS the same way that works on Windows).

Last edited by cfillion; 12-06-2018 at 07:04 AM.
cfillion is offline   Reply With Quote
Old 12-06-2018, 07:18 AM   #122
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 3,714
Default

Quote:
Originally Posted by mespotine View Post
How do I separate the multiple filenames(in the get-files-functions) from each other in Lua?
Code:
for file in files:gmatch("[^\0]+") do

Last edited by juliansader; 12-08-2018 at 04:41 AM.
juliansader is offline   Reply With Quote
Old 12-07-2018, 07:26 AM   #123
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,612
Default

@JulianSaders @cfillion

Thanx, using \0 to pattern match was probably too obvious for me to see. With that, it works like a charm
__________________
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 12-07-2018, 08:54 AM   #124
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,903
Default

Quote:
Originally Posted by juliansader View Post
Code:
for file in files:gmatch("[^\0]") do
When I use that (on Win7) I only get one char per loop.

EDIT: OK,it works if I add a '+' to the end of it,
Code:
for file in files:gmatch("[^\0]+") do
I guess that'll work.

Last edited by Edgemeal; 12-07-2018 at 12:23 PM.
Edgemeal is offline   Reply With Quote
Old 12-08-2018, 04:36 AM   #125
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,612
Default

I'll post a function tomorrow(forgot to put it on my USB-stick today), that'll deal with that conveniently and return the filenames as array.
__________________
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 12-08-2018, 04:40 AM   #126
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 3,714
Default

Quote:
Originally Posted by Edgemeal View Post
OK,it works if I add a '+' to the end of it,
Oops! Corrected.
juliansader is offline   Reply With Quote
Old 12-11-2018, 02:13 AM   #127
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 3,714
Default

I neglected to include a description of the "extensionList" parameter of the open/save file dialogs in the API help.

This parameter uses the same format as the standard C++ functions GetOpenFileName and GetSaveFileName:

This string is terminated by *double* \0 characters, and contains a list of filter substrings, each terminated by a single \0.

The filter substrings are arranged in pairs: The first substring in each pair describes the filter and is displayed to the user in the dialog; the second substring in the pair specifies the filter pattern that the operating system must use. For example, "Lua scripts (*.lua)\0*.lua"\0.

To specify multiple filter patterns for a single display string, use a semicolon to separate the patterns (for example, "*.lua;*.eel\0").

Warning: in Windows, the filter doesn't require the * filename wildcard in front of the extension, but it appears to be required in Linux. (I'm not sure about macOS.)

So, for example, to include a filter for either all files or just lua scripts, this string can be used:
Code:
"All files (*.*)\0*.*\0Lua scripts (.lua)\0*.lua\0\0"
juliansader is offline   Reply With Quote
Old 12-12-2018, 10:06 AM   #128
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,612
Default

For the JS_Dialog_BrowseForOpenFiles-function, you can use the following code, to separate the filenames and path:

Code:
function SplitFilenameStringAtNULLBytes(splitstring)
--  if type(splitstring)~=nil 
  -- add a NULL-Byte at the end, helps us finding the end of the string later
  splitstring=splitstring.."\0"
  local count=0
  local filenames={}
  local temp, offset
  
  -- let's get the path
  local path, offset=splitstring:match("(.-)()\0")
  splitstring=splitstring:sub(offset+1,-1)
  
  -- let's get the filenames
  while splitstring~=nil do
    -- find the next filename
    temp,offset=splitstring:match("(.-)()\0")
    
    if temp~=nil then 
      -- if the next filename isn't nil, then add it fo filenames-array and count+1
      count=count+1 
      filenames[count]=temp
      splitstring=splitstring:sub(offset+1,-1)
    else 
      -- if filename is nil, the string is probably finished splitting
      break 
    end
  end
  return count, path, filenames
end
__________________
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 12-12-2018, 10:51 AM   #129
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 3,714
Default

Perhaps something simpler?

The following should give you the path in t[1] and the file names in the rest of the table:
(Except if #t == 1, in which case the entire path and filename is in t[1].)
Code:
t = {}
for file in files:gmatch("[^\0]*")
    t[#t+1] = file
end

Last edited by juliansader; 03-21-2019 at 05:13 AM.
juliansader is offline   Reply With Quote
Old 12-15-2018, 04:34 AM   #130
reapero
Human being with feelings
 
Join Date: Aug 2011
Posts: 508
Default

Hey i am just curious..are there some scripts out there already using this API?
reapero is offline   Reply With Quote
Old 12-15-2018, 05:44 AM   #131
lb0
Human being with feelings
 
Join Date: Apr 2014
Posts: 4,171
Default

Quote:
Originally Posted by reapero View Post
Hey i am just curious..are there some scripts out there already using this API?
I have one in progress that uses certain functions from this API. This API has really opened up a whole new world to scripting in Reaper.
__________________
Projects - Reascripts - Lua:
Smart Knobs 2 | LBX Stripper | LBX Floating FX Positioner
Donate via Paypal | LBX Tools Website
lb0 is offline   Reply With Quote
Old 12-15-2018, 06:07 AM   #132
reapero
Human being with feelings
 
Join Date: Aug 2011
Posts: 508
Default

Yeah..looks like it. I with i has the skills to use it
reapero is offline   Reply With Quote
Old 12-15-2018, 11:44 AM   #133
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,903
Default Main Action Command ID Code Generator

Quote:
Originally Posted by reapero View Post
Hey i am just curious..are there some scripts out there already using this API?
I have one to reset vertical Vu meters, and just made this..

If you call actions from a lua script its a hassle to copy their Text, ID/convert IDs, etc. Using this script you just highlight the action(s) you want and call this script from a shortcut and it generates the code for you (for Main section).

EDIT: Update v1.00 - Show command ID column if not visible.

Code:
-- Command ID Code Generator v1.00 --
function Main()
  local show_id_column = 41170      -- toggle command id column
  -- local show_path_column = 41387 -- toggle script paths column
 
  local actions = reaper.JS_Window_Find("Actions", true)
  if actions == nil then reaper.MB("Please open the Actions list!", app_name, 0) return end  
  
  local hWnd_LV = reaper.JS_Window_FindChildByID(actions, 1323)
  local sel_count, sel_indexes = reaper.JS_ListView_ListAllSelItems(hWnd_LV)
  if sel_count == 0 then reaper.MB("Please select one or more actions.", app_name, 0) return end   
  
  local lv_header = reaper.JS_Window_HandleFromAddress(reaper.JS_WindowMessage_Send(hWnd_LV, "0x101F", 0,0,0,0)) -- 0x101F = LVM_GETHEADER
  local lv_column_count = reaper.JS_WindowMessage_Send(lv_header, "0x1200" ,0,0,0,0) -- 0x1200 = HDM_GETITEMCOUNT
  
  -- Show Command ID column if not visible,
  -- thanks to amagalma, https://forum.cockos.com/showpost.php?p=2270516&postcount=1
  local third_item = reaper.JS_ListView_GetItemText(hWnd_LV, 0, 3)
  if lv_column_count < 4 or third_item == "" or third_item:find("[\\/:]") then
    reaper.JS_WindowMessage_Send(actions, "WM_COMMAND", show_id_column, 0, 0, 0) -- show Command ID column
  end
  
  -- generate code lines for *Main*
  local code = ''
  for ndx in string.gmatch(sel_indexes, '[^,]+') do
    local index = tonumber(ndx)
    local desc = reaper.JS_ListView_GetItemText(hWnd_LV, index, 1)
    local cmd = reaper.JS_ListView_GetItemText(hWnd_LV, index, 3)
    if tonumber(cmd) ~= nil then -- reaper action
      code = code .. "reaper.Main_OnCommand(" .. cmd .. ", 0) -- " .. desc .. '\r\n'
    else -- custom scripts require a lookup
      code = code .. "reaper.Main_OnCommand(reaper.NamedCommandLookup('" .. cmd .. "'), 0) -- " .. desc .. '\r\n'
    end
  end -- for ndx
  
  reaper.CF_SetClipboard(code) -- copy generated code to clipboard
  
  -- OPTIONAL: Paste text in IDE if open. *Requires special shortcut!
  -- * Shortcut must use the ControlKey+key (e.g., Control+F12).
  -- See, https://forum.cockos.com/showpost.php?p=2073502&postcount=165
  local ide = reaper.JS_Window_Find(" - ReaScript Development Environment", false)
  if ide then
    local wdl = reaper.JS_Window_FindChildByID(ide, 1106) 
    reaper.JS_Window_SetFocus(wdl)
    reaper.JS_WindowMessage_Post(wdl, "WM_KEYDOWN", 0x0056, 0, 0, 0) -- V key (+ control key is down, so paste!)
    reaper.JS_WindowMessage_Post(wdl, "WM_KEYUP", 0x0056, 0, 0, 0)
  end
  
end -- end Main function

app_name = "Cmd_ID Code Gen" 
Main()
reaper.defer(function () end)

Last edited by Edgemeal; 04-17-2020 at 03:08 PM. Reason: v1.00
Edgemeal is offline   Reply With Quote
Old 12-15-2018, 02:48 PM   #134
reapero
Human being with feelings
 
Join Date: Aug 2011
Posts: 508
Default

So you use a script to actually write code? Jesuschrist..you guys are just too smart
reapero is offline   Reply With Quote
Old 12-15-2018, 03:41 PM   #135
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 3,714
Default

Quote:
Originally Posted by cfillion View Post
Just tested and it works here, though I get a leading null byte which isn't there on Windows. Are you're using the IDE or ShowConsoleMsg? They won't show anything past a null byte.



Windows (only the first path is absolute?):

The WDL/swell function is supposed to return the path in the first substring, and the filename (without path) in the following substrings. On Linux, it works correctly. I wonder if there is a bug in the macOS swell function? Perhaps the leading null byte is the terminator of an empty path substring?


Quote:
Originally Posted by cfillion View Post
(Also can't seem to make it accept all or no file extensions on macOS the same way that works on Windows).
Could you explain what you mean by "all or no file extensions"?

If the user gives no extension filter, the function should automatically add a *.* filter, so that the filter dropdown menu isn't just blank.

Last edited by juliansader; 12-16-2018 at 04:30 AM.
juliansader is offline   Reply With Quote
Old 12-16-2018, 03:36 AM   #136
amagalma
Human being with feelings
 
amagalma's Avatar
 
Join Date: Apr 2011
Posts: 3,450
Default

Quote:
Originally Posted by Edgemeal View Post
I have one to reset vertical Vu meters, and just made this..

If you call actions from a lua script its a hassle to copy their ID/convert IDs, etc. Using this script you just highlight the action(s) you want and call this script from a shortcut and it generates the code for you, at least I hope it does.

Code:
-- Command ID Code Generator v0.04 --
-- Testing: x64, Windows 7, REAPER v5.963+dev1213, js_ReaScriptAPI v0.961.
-- v0.04 - Support multiple selected LV items.

local app_name = "Cmd_ID Code Gen"
local code = ""

local hWnd_action = reaper.JS_Window_Find("Actions", true)
if hWnd_action == nil then
  reaper.MB("Please open the Actions list!", app_name, 0)
  return
end  

local hWnd_LV = reaper.JS_Window_FindChildByID(hWnd_action, 1323)
if reaper.JS_ListView_GetItemText(hWnd_LV, 0, 3) == "" then
  reaper.MB("Please enable 'Show action IDs' in Actions list!", app_name, 0)
  return
end

-- get selected count & selected indexes
sel_count, sel_indexes = reaper.JS_ListView_ListAllSelItems(hWnd_LV)
if sel_count == 0 then
  reaper.MB("Please select one or more actions.", app_name, 0)
  return
end 

-- generate code lines for *Main*
for index in string.gmatch(sel_indexes, '[^,]+') do 
  local desc = reaper.JS_ListView_GetItemText(hWnd_LV, tonumber(index), 1)
  local cmd = reaper.JS_ListView_GetItemText(hWnd_LV, tonumber(index), 3)
  if tonumber(cmd) ~= nil then -- reaper action
    code = code .. "reaper.Main_OnCommand(" .. cmd .. ", 0) -- " .. desc .. '\r\n'
  else -- custom scripts require a lookup
    code = code .. "reaper.Main_OnCommand(reaper.NamedCommandLookup('" .. cmd .. "'), 0) -- " .. desc .. '\r\n'
  end
end -- for index

reaper.CF_SetClipboard(code)-- copy generated code to clipboard
Brilliant! Thanks!
__________________
Most of my scripts can be found in ReaPack.
If you find them useful, a donation would be greatly appreciated! Thank you! :)
amagalma is offline   Reply With Quote
Old 12-16-2018, 05:11 AM   #137
amagalma
Human being with feelings
 
amagalma's Avatar
 
Join Date: Apr 2011
Posts: 3,450
Default

How could I paste the text in the clipboard to a focused window?
For example, with Spy++ I get this code when pasting into a window:
Code:
<000001> 00250490 P WM_CHAR chCharCode:'22' (22) cRepeat:1 ScanCode:2F fExtended:0 fAltDown:0 fRepeat:0 fUp:0 [wParam:00000016 lParam:002F0001]
I have tried this but it does not work:
Code:
reaper.JS_WindowMessage_Send( windowHWND, "WM_CHAR", 0x0016, 0x0000, 0x0001, 0x002F)
Any ideas?
__________________
Most of my scripts can be found in ReaPack.
If you find them useful, a donation would be greatly appreciated! Thank you! :)

Last edited by amagalma; 12-16-2018 at 06:30 AM.
amagalma is offline   Reply With Quote
Old 12-16-2018, 10:08 AM   #138
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,903
Default

EDIT
You got me wondering about sending text and clicking buttons now.
Since there is no support for "BM_CLICK" or "WM_SETTEXT"

EDIT 2
This seems OK for "BM_CLICK" on Windows..
Code:
-- Send button click message, a.k.a. "BM_CLICK".
reaper.JS_WindowMessage_Send(button_hWnd, "0x00F5", 0, 0, 0, 0)
CODE REMOVED! TRY AGAIN!

Last edited by Edgemeal; 01-02-2019 at 07:22 PM. Reason: EDIT 2
Edgemeal is offline   Reply With Quote
Old 12-17-2018, 04:24 AM   #139
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 9,866
Default

Do you think we can get selected media files from Media Explorer and start doing some Media Explorer script ? :P
X-Raym is offline   Reply With Quote
Old 12-17-2018, 05:03 AM   #140
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,903
Default

Quote:
Originally Posted by X-Raym View Post
Do you think we can get selected media files from Media Explorer and start doing some Media Explorer script ? :P
Heres one way, I'd prefer using JS_Window_FindEx() to get the handle to the file Listview, the container its in seems to be the only control with an ID of 0, so tested like this,...

Code:
-- Testing: x64, Windows 7, REAPER v5.963+dev1213, js_ReaScriptAPI v0.961.

function print(str)
  reaper.ShowConsoleMsg(tostring(str) .. "\n") -- console
end

local hWnd = reaper.JS_Window_Find("Media Explorer", true)
if hWnd == nil then return end  

local container = reaper.JS_Window_FindChildByID(hWnd, 0)
local file_LV = reaper.JS_Window_FindChildByID(container, 1000)

sel_count, sel_indexes = reaper.JS_ListView_ListAllSelItems(file_LV)
if sel_count == 0 then return end 

for ndx in string.gmatch(sel_indexes, '[^,]+') do 
  index = tonumber(ndx)
  local fname = reaper.JS_ListView_GetItemText(file_LV, index, 0)
  local size = reaper.JS_ListView_GetItemText(file_LV, index, 1)
  local date = reaper.JS_ListView_GetItemText(file_LV, index, 2)
  local ftype = reaper.JS_ListView_GetItemText(file_LV, index, 3)
  print(fname .. ', ' .. size .. ', ' .. date .. ', ' .. ftype) 
end

-- get selected path  from edit control inside combobox
local combo = reaper.JS_Window_FindChildByID(hWnd, 1002)
local edit = reaper.JS_Window_FindChildByID(combo, 1001)
local path = reaper.JS_Window_GetTitle(edit, "", 255)
print(path)

Last edited by Edgemeal; 12-17-2018 at 05:42 AM. Reason: get more column data
Edgemeal is offline   Reply With Quote
Old 12-17-2018, 05:25 AM   #141
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 3,714
Default

Quote:
Originally Posted by X-Raym View Post
Do you think we can get selected media files from Media Explorer and start doing some Media Explorer script ? :P
As Edgemeal answered, yes you can! (I am actually using some myself.)

Three remarks:

* You can open the Media Explorer (and get its HWND) using reaper.OpenMediaExplorer("", false).

* You can run any action from the Actions list's Media Explorer context (or even any item from the ME's menu), using JS_Window_OnCommand.

* If you are publishing a script that searches for any of REAPER's standard windows, such as the Media Explorer, use JS_Localize to get the translated title.
juliansader is offline   Reply With Quote
Old 12-17-2018, 05:39 AM   #142
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 9,866
Default

@edgemeal
This is awesome !


We can finally make a Rename from media explorer action !


Only problem is that the last clicked selected items in media explorer is in read-only mode. The trick is to close and re-open the media explorer using the native actions (or API functions) which will also refresh the media explorer (a trick I used in some databases scripts I made).

But I wonder is there is any more clever js_extension trick now ? for both release read-only mode and for refreshing the media explorer ?


@juliansader
This script really open new possibilities to scripting ! Cool it is part to default reateam repos.
X-Raym is offline   Reply With Quote
Old 12-17-2018, 05:59 AM   #143
amagalma
Human being with feelings
 
amagalma's Avatar
 
Join Date: Apr 2011
Posts: 3,450
Default

Quote:
Originally Posted by Edgemeal View Post
This seems to work OK, tho not sure its actually correct.

Code:
local hWnd_action = reaper.JS_Window_Find("Actions", true)
if hWnd_action ~= nil then
  -- Get handle to Filter editbox in Actions window,
  local hWnd_filter = reaper.JS_Window_FindChildByID(hWnd_action, 1324)
  -- send it an "A" Char
  ret = reaper.JS_WindowMessage_Post(hWnd_filter, "WM_CHAR", string.byte("A"), 0,0,0) 
end

Yes, simple characters work, but Ctrl+V etc do not.



Quote:
Code:
function JS_Send_Text(hWnd, str)
  for char in string.gmatch(str, "%U") do 
    ret = reaper.JS_WindowMessage_Post(hWnd, "WM_CHAR", string.byte(char), 0, 0, 0) 
    if ret ~= true then break end -- something went wrong?, abort loop!
  end
end

For some reason, this works up to 64 characters. If they are more than 64, it truncates the start.
__________________
Most of my scripts can be found in ReaPack.
If you find them useful, a donation would be greatly appreciated! Thank you! :)
amagalma is offline   Reply With Quote
Old 12-17-2018, 06:46 AM   #144
_Stevie_
Human being with feelings
 
_Stevie_'s Avatar
 
Join Date: Oct 2017
Location: Black Forest
Posts: 5,048
Default

0.961 is not listed in the repo, yet, right? We have to download manually. Or did I miss something?
__________________
My Reascripts forum thread | My Reascripts on GitHub
If you like or use my scripts, please support the Ukraine: Ukraine Crisis Relief Fund | DirectRelief | Save The Children | Razom
_Stevie_ is offline   Reply With Quote
Old 12-17-2018, 03:02 PM   #145
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,903
Default

Quote:
Originally Posted by amagalma View Post
For some reason, this works up to 64 characters. If they are more than 64, it truncates the start.
It could be a char limit set by the target control. Yesterday that code worked flawless, today acting weird, ok lets try something diff...

EDIT New test...
Code:
local hWnd_action = reaper.JS_Window_Find("Actions", true)
if hWnd_action ~= nil then
  filter_editbox = reaper.JS_Window_FindChildByID(hWnd_action, 1324)
  reaper.JS_Window_SetTitle(filter_editbox, "tracks unselect all") -- set text of Actions Filter
end
Get Top-Level Control IDs Under Mouse (For Windows only)

Last edited by Edgemeal; 12-17-2018 at 04:05 PM.
Edgemeal is offline   Reply With Quote
Old 12-18-2018, 04:16 AM   #146
amagalma
Human being with feelings
 
amagalma's Avatar
 
Join Date: Apr 2011
Posts: 3,450
Default

Quote:
Originally Posted by Edgemeal View Post
EDIT New test...
Code:
local hWnd_action = reaper.JS_Window_Find("Actions", true)
if hWnd_action ~= nil then
  filter_editbox = reaper.JS_Window_FindChildByID(hWnd_action, 1324)
  reaper.JS_Window_SetTitle(filter_editbox, "tracks unselect all") -- set text of Actions Filter
end
Get Top-Level Control IDs Under Mouse (For Windows only)

No, this still doesn't work.. Strangely, it works for the Action List but it doesn't in all the other windows. For example, open Notepad and try this:
Code:
hWnd_action = reaper.JS_Window_Find(" - Notepad", false)
if hWnd_action ~= nil then
  child = reaper.JS_Window_FindChildByID(hWnd_action, 15)
  reaper.JS_Window_SetTitle(child, "This is a test")
end

Nothing happens.. I tried to mimic the press of Ctrl+V in order to paste the text I have in the clipboard, but again no luck:
Code:
  reaper.JS_WindowMessage_Post( child, "WM_KEYDOWN", 0x0011, 0x0000, 0x0001, 0x001D) -- Ctrl
  reaper.JS_WindowMessage_Post( child, "WM_KEYDOWN", 0x0011, 0x0000, 0x0001, 0x401D)
  reaper.JS_WindowMessage_Post( child, "WM_KEYDOWN", 0x0056, 0x0000, 0x0001, 0x002F) -- V
  reaper.JS_WindowMessage_Post( child, "WM_CHAR", 0x0016, 0x0000, 0x0001, 0x002F)
  reaper.JS_WindowMessage_Post( child, "WM_KEYUP", 0x0056, 0x0000, 0x0001, 0xC02F)
  reaper.JS_WindowMessage_Post( child, "WM_KEYUP", 0x0011, 0x0000, 0x0001, 0xC01D)

P.S. Your exe for getting the Control IDs is very handy! Thanks!
__________________
Most of my scripts can be found in ReaPack.
If you find them useful, a donation would be greatly appreciated! Thank you! :)
amagalma is offline   Reply With Quote
Old 12-18-2018, 07:14 AM   #147
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,903
Default

Quote:
Originally Posted by amagalma View Post
No, this still doesn't work.. Strangely, it works for the Action List but it doesn't in all the other windows. For example, open Notepad and try this:
Looking at the source code 'JS_Window_SetTitle' is calling the 'SetWindowText' API which is used to change the text of a window's title bar, I'm not sure why it works on Edit controls in REAPER, but was the last thing I tried.

TEST, change title bar text of notepad...
Code:
hWnd = reaper.JS_Window_Find("Untitled - Notepad", true)
if hWnd ~= nil then
 reaper.JS_Window_SetTitle(hWnd, "This is a test")
end
Could of sworn I saw WM_SETTEXT in one of the JS source flles, but I think it was commented out so can't be used.

Last edited by Edgemeal; 12-22-2018 at 12:17 AM.
Edgemeal is offline   Reply With Quote
Old 12-18-2018, 08:16 AM   #148
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,612
Default

Quote:
Originally Posted by _Stevie_ View Post
0.961 is not listed in the repo, yet, right? We have to download manually. Or did I miss something?
It works with pre-releases of Reaper only, for the moment.
Though I hope, Reaper 5.964 contains the stuff needed for an "official release".
__________________
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 12-18-2018, 03:23 PM   #149
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 4,909
Default

Quote:
Originally Posted by Edgemeal View Post
Looking at the source code 'JS_Window_SetTitle' is calling the 'SetWindowText' API which is used to change the text of a window's title bar, I'm not sure why it works on Edit controls in REAPER, but was the last thing I tried.
https://docs.microsoft.com/en-us/win...setwindowtextw

Quote:
Changes the text of the specified window's title bar (if it has one). If the specified window is a control, the text of the control is changed. However, SetWindowText cannot change the text of a control in another application.

[...]

If the target window is owned by the current process, SetWindowText causes a WM_SETTEXT message to be sent to the specified window or control.
cfillion is offline   Reply With Quote
Old 12-18-2018, 05:36 PM   #150
amagalma
Human being with feelings
 
amagalma's Avatar
 
Join Date: Apr 2011
Posts: 3,450
Default

Shouldn't it work to send text to the Reascript IDE window?

I can change the title of the window but I can't send text to it
__________________
Most of my scripts can be found in ReaPack.
If you find them useful, a donation would be greatly appreciated! Thank you! :)
amagalma is offline   Reply With Quote
Old 12-18-2018, 06:32 PM   #151
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 4,909
Default

No. Here's the IDE window's message handler: https://github.com/justinfrankel/WDL...win32.cpp#L292.

Last edited by cfillion; 12-18-2018 at 06:41 PM.
cfillion is offline   Reply With Quote
Old 12-19-2018, 02:08 AM   #152
amagalma
Human being with feelings
 
amagalma's Avatar
 
Join Date: Apr 2011
Posts: 3,450
Default

Does this mean that the IDE window is considered a different application, like Notepad?
__________________
Most of my scripts can be found in ReaPack.
If you find them useful, a donation would be greatly appreciated! Thank you! :)
amagalma is offline   Reply With Quote
Old 12-19-2018, 03:00 AM   #153
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 4,909
Default

The IDE just doesn't implement WM_SETTEXT. (A different application would mean another process visible in the task manager.)

The curses control receives input through WM_CHAR and keyboard shortcuts through WM_KEYDOWN. However modifier keys (Shift/Control/Alt/Meta) are tested with GetAsyncKeyState which can't be simulated using messages (maybe SendInput?).

Code:
-- likely Windows only (fails to find the curses control on macOS, didn't investigate)

local ide = reaper.JS_Window_Find("test.lua", false)
local curses = reaper.JS_Window_FindChildByID(ide, 0x452)

for c in ("Hello world"):gmatch('.') do
  reaper.JS_WindowMessage_Post(curses, "WM_CHAR", string.byte(c), 0, 1, 0)
end
(Looks like C++ would be able to send anything including shortcuts with modifiers. But bad things will happen if REAPER is built using a different curses.h than the extension.)

Last edited by cfillion; 12-19-2018 at 05:23 AM.
cfillion is offline   Reply With Quote
Old 12-19-2018, 03:57 AM   #154
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 3,714
Default

If you are on Windows, if you would like to paste something, try sending a WM_PASTE command.

WDL/swell has not implemented this message type on Linux or macOS (AFAIK?), so the extension will not recognize the name, but on Windows you can use the message value, 0x0302:
Code:
reaper.JS_WindowMessage_Post(filterHWND, "0x0302", 0, 0, 0, 0)
I quickly checked, and it works fine in the Action list's filter editbox.


Quote:
Originally Posted by Edgemeal View Post
Could of sworn I saw WM_SETTEXT in one of the JS source flles, but I think it was commented out so can't be used.
WM_SETTEXT has also not been implemented on macOS, so I haven't included it in the list of message names that the extension will recognize.

Last edited by juliansader; 12-19-2018 at 04:21 AM.
juliansader is offline   Reply With Quote
Old 12-19-2018, 04:13 AM   #155
amagalma
Human being with feelings
 
amagalma's Avatar
 
Join Date: Apr 2011
Posts: 3,450
Default

Quote:
Originally Posted by cfillion View Post
Code:
-- likely Windows only (fails to find the curses control on macOS, didn't investigate)

local ide = reaper.JS_Window_Find("test.lua", false)
local curses = reaper.JS_Window_FindChildByID(ide, 0x452)

for c in ("Hello world"):gmatch('.') do
  reaper.JS_WindowMessage_Post(curses, "WM_CHAR", string.byte(c), 0, 1, 0)
end
(Looks like C++ would be able to send anything including shortcuts with modifiers. But bad things will happen if REAPER is built using a different curses.h than the extension.)

Yes, this method works as Edgemeal had already showed, but it has a limit of 64 characters.


Quote:
Originally Posted by juliansader View Post
Code:
reaper.JS_WindowMessage_Post(filterHWND, "0x0302", 0, 0, 0, 0)
I quickly checked, and it works fine in the Action list's filter editbox.

WM_SETTEXT has also not been implemented on macOS, so I haven't included it in the list of message names that the extension will recognize.

This does not work in the IDE window, where I am interested in.
__________________
Most of my scripts can be found in ReaPack.
If you find them useful, a donation would be greatly appreciated! Thank you! :)
amagalma is offline   Reply With Quote
Old 12-19-2018, 05:02 AM   #156
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 4,909
Default

Quote:
Originally Posted by amagalma View Post
Yes, this method works as Edgemeal had already showed, but it has a limit of 64 characters.
Ah yes, the IDE's keyboard queue is 64 characters big and (up to) 16 chars are read from it per timer cycle. This works but is of course slow(er), fragile and not cleanly undoable:

Code:
-- just for fun, shouldn't be used in a proper script...
function writeInIDE(file, content)
  local CHUNK_SIZE = 16

  local ide = reaper.JS_Window_Find(file, false)
  local curses = reaper.JS_Window_FindChildByID(ide, 0x452)
  local chunkStart = 1
  
  function sendChunk()
    local chunkEnd = chunkStart + CHUNK_SIZE - 1

    for c in content:sub(chunkStart, chunkEnd):gmatch('.') do
      reaper.JS_WindowMessage_Post(curses, "WM_CHAR", string.byte(c), 0, 1, 0)
    end
    
    chunkStart = chunkEnd + 1

    if chunkStart < #content then
      reaper.defer(sendChunk)
    end
  end

 sendChunk()
end

writeInIDE('test.lua', string.rep('abcdefghijklmnopqrstuvwxyz', 8))
What's the end goal for which pasting in the IDE is needed? Perhaps there's a better solution than this sort of hacks...

Last edited by cfillion; 12-19-2018 at 05:16 AM.
cfillion is offline   Reply With Quote
Old 12-19-2018, 05:17 AM   #157
amagalma
Human being with feelings
 
amagalma's Avatar
 
Join Date: Apr 2011
Posts: 3,450
Default

Quote:
Originally Posted by Edgemeal View Post
If you call actions from a lua script its a hassle to copy their ID/convert IDs, etc. Using this script you just highlight the action(s) you want and call this script from a shortcut and it generates the code for you, at least I hope it does.

Code:
-- Command ID Code Generator v0.04 --
-- Testing: x64, Windows 7, REAPER v5.963+dev1213, js_ReaScriptAPI v0.961.
-- v0.04 - Support multiple selected LV items.

local app_name = "Cmd_ID Code Gen"
local code = ""

local hWnd_action = reaper.JS_Window_Find("Actions", true)
if hWnd_action == nil then
  reaper.MB("Please open the Actions list!", app_name, 0)
  return
end  

local hWnd_LV = reaper.JS_Window_FindChildByID(hWnd_action, 1323)
if reaper.JS_ListView_GetItemText(hWnd_LV, 0, 3) == "" then
  reaper.MB("Please enable 'Show action IDs' in Actions list!", app_name, 0)
  return
end

-- get selected count & selected indexes
sel_count, sel_indexes = reaper.JS_ListView_ListAllSelItems(hWnd_LV)
if sel_count == 0 then
  reaper.MB("Please select one or more actions.", app_name, 0)
  return
end 

-- generate code lines for *Main*
for index in string.gmatch(sel_indexes, '[^,]+') do 
  local desc = reaper.JS_ListView_GetItemText(hWnd_LV, tonumber(index), 1)
  local cmd = reaper.JS_ListView_GetItemText(hWnd_LV, tonumber(index), 3)
  if tonumber(cmd) ~= nil then -- reaper action
    code = code .. "reaper.Main_OnCommand(" .. cmd .. ", 0) -- " .. desc .. '\r\n'
  else -- custom scripts require a lookup
    code = code .. "reaper.Main_OnCommand(reaper.NamedCommandLookup('" .. cmd .. "'), 0) -- " .. desc .. '\r\n'
  end
end -- for index

reaper.CF_SetClipboard(code)-- copy generated code to clipboard

I wanted to combine it with this script of Edgemeal so that the action gets automatically typed in the open IDE window.


Your code works and now I can achieve it. Thank you! The only problem is the messed up undo (an undo point for each character), which makes it not practical.. So, I 'll just use the script in Edgemeal's original version, and do the pasting manually.
__________________
Most of my scripts can be found in ReaPack.
If you find them useful, a donation would be greatly appreciated! Thank you! :)
amagalma is offline   Reply With Quote
Old 12-19-2018, 10:37 AM   #158
amagalma
Human being with feelings
 
amagalma's Avatar
 
Join Date: Apr 2011
Posts: 3,450
Default

On another note, it is great that with the latest additions we can now get the selected FX in a visible Chain :



Code:
function GetSelectedFXinChain()
  local FX_win = reaper.JS_Window_Find("FX: ", false )
  local sel_FX = {}
  if FX_win then
    local title = reaper.JS_Window_GetTitle( FX_win, "" )
    if title:match("FX: Track ") or title:match("FX: Master Track") or title:match("FX: Item ") then
      local list = reaper.JS_Window_FindChildByID(FX_win, 1076)
      local _, sel_fx = reaper.JS_ListView_ListAllSelItems(list)
      local a = 0
      for i in sel_fx:gmatch("%d+") do
        sel_FX[a+1] = {id = tonumber(i), name = reaper.JS_ListView_GetItemText(list, tonumber(i), 0)}
        a = a + 1
      end
    end
  end
  return sel_FX
end

-- TEST CODE -- 
local fx = GetSelectedFXinChain()
if #fx == 0 then return end
reaper.ClearConsole()
reaper.ShowConsoleMsg("The selected FX in the visible FX chain are:\n\n")
for i = 1, #fx do
  reaper.ShowConsoleMsg(i .. ") " .. fx[i].name .. "   - - -   fxid: " .. fx[i].id .. "\n\n")
end
local w = reaper.JS_Window_Find("ReaScript console output", true )
reaper.JS_Window_SetFocus( reaper.JS_Window_FindChildByID(w, 3) )
reaper.defer(function () end )
And do this :

__________________
Most of my scripts can be found in ReaPack.
If you find them useful, a donation would be greatly appreciated! Thank you! :)

Last edited by amagalma; 12-24-2018 at 02:06 PM.
amagalma is offline   Reply With Quote
Old 12-21-2018, 02:02 PM   #159
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,903
Default

v0.962 by juliansader – December 21 2018
* New functions: Browse for files and folders.
* New functions: Various ListView.
* New function: FindChildByID.
* Changed functions: Functions that previously stored strings in ExtStates, now return the strings directly.
* Requirements: On Windows OS, C++ redistributable not required anymore.
* Requirements: REAPER v5.965 or later.
Edgemeal is offline   Reply With Quote
Old 12-21-2018, 05:10 PM   #160
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 9,866
Default

Updated my ReaScript doc page with REAPER v5.965 and js_Extension v0.962 :P
(link in signature)
X-Raym 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 07:32 PM.


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