Old 08-19-2021, 04:50 AM   #1601
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,164
Default

I managed to answer my own question. It's not even necessary to move the mouse, you can just send a 'WM_MOUSEFIRST' message and the time selection will show immediately (in the same defer cycle).

Here's the resulting function for anyone interested:

Code:
function MediaExplorer_GetTimeSelection()
    local mx_title = reaper.JS_Localize('Media Explorer', 'common')
    local mx = reaper.JS_Window_Find(mx_title, true)
    if not mx then return false end

    -- Simulate mouse event on waveform to read out time selection
    local x, y = reaper.GetMousePosition()
    local wave_hwnd = reaper.JS_Window_FindChildByID(mx, 1046)
    local c_x, c_y = reaper.JS_Window_ScreenToClient(wave_hwnd, x, y)
    reaper.JS_WindowMessage_Send(wave_hwnd, 'WM_MOUSEFIRST', c_y, 0, c_x, 0)

    -- If a time selection exists, it will be shown in the wave info window
    local wave_info_hwnd = reaper.JS_Window_FindChildByID(mx, 1014)
    local wave_info = reaper.JS_Window_GetTitle(wave_info_hwnd)
    local pattern = ': ([^%s]+) .-: ([^%s]+)'
    local start_timecode, end_timecode = wave_info:match(pattern)

    if not start_timecode then return false end

    -- Convert timecode to seconds
    local start_mins, start_secs = start_timecode:match('^(.-):(.-)$')
    start_secs = tonumber(start_secs) + tonumber(start_mins) * 60

    local end_mins, end_secs = end_timecode:match('^(.-):(.-)$')
    end_secs = tonumber(end_secs) + tonumber(end_mins) * 60

    -- Note: When no media file is loaded, start and end are both 0
    return start_secs ~= end_secs, start_secs, end_secs
end
__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi

Last edited by FeedTheCat; 08-19-2021 at 05:16 AM.
FeedTheCat is online now   Reply With Quote
Old 08-19-2021, 02:55 PM   #1602
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 3,714
Default

Quote:
Originally Posted by FeedTheCat View Post
I managed to answer my own question. It's not even necessary to move the mouse, you can just send a 'WM_MOUSEFIRST' message and the time selection will show immediately (in the same defer cycle).
Cool! Thanks for letting us know about this trick.
juliansader is offline   Reply With Quote
Old 08-23-2021, 03:43 PM   #1603
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 3,714
Default

Quote:
Originally Posted by euxebio View Post
Very interesting..it's possible a exemple to understand how to construct the C++ struct in a Lua string, store it using JS_Mem_Alloc and JS_Mem_FromString, and then pass the malloc address as an argument of JS_WindowMessage_Send?

I don't understand how do that.
Are you familiar with how to do this in C++?
juliansader is offline   Reply With Quote
Old 08-23-2021, 06:32 PM   #1604
amagalma
Human being with feelings
 
amagalma's Avatar
 
Join Date: Apr 2011
Posts: 3,451
Default

Quote:
Originally Posted by FeedTheCat View Post
I managed to answer my own question. It's not even necessary to move the mouse, you can just send a 'WM_MOUSEFIRST' message and the time selection will show immediately (in the same defer cycle).

Here's the resulting function for anyone interested:

Code:
function MediaExplorer_GetTimeSelection()
    local mx_title = reaper.JS_Localize('Media Explorer', 'common')
    local mx = reaper.JS_Window_Find(mx_title, true)
    if not mx then return false end

    -- Simulate mouse event on waveform to read out time selection
    local x, y = reaper.GetMousePosition()
    local wave_hwnd = reaper.JS_Window_FindChildByID(mx, 1046)
    local c_x, c_y = reaper.JS_Window_ScreenToClient(wave_hwnd, x, y)
    reaper.JS_WindowMessage_Send(wave_hwnd, 'WM_MOUSEFIRST', c_y, 0, c_x, 0)

    -- If a time selection exists, it will be shown in the wave info window
    local wave_info_hwnd = reaper.JS_Window_FindChildByID(mx, 1014)
    local wave_info = reaper.JS_Window_GetTitle(wave_info_hwnd)
    local pattern = ': ([^%s]+) .-: ([^%s]+)'
    local start_timecode, end_timecode = wave_info:match(pattern)

    if not start_timecode then return false end

    -- Convert timecode to seconds
    local start_mins, start_secs = start_timecode:match('^(.-):(.-)$')
    start_secs = tonumber(start_secs) + tonumber(start_mins) * 60

    local end_mins, end_secs = end_timecode:match('^(.-):(.-)$')
    end_secs = tonumber(end_secs) + tonumber(end_mins) * 60

    -- Note: When no media file is loaded, start and end are both 0
    return start_secs ~= end_secs, start_secs, end_secs
end

WM_MOUSEFIRST = WM_MOUSEMOVE = 512
__________________
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 08-23-2021, 06:36 PM   #1605
amagalma
Human being with feelings
 
amagalma's Avatar
 
Join Date: Apr 2011
Posts: 3,451
Default

Quote:
Originally Posted by juliansader View Post
Are you familiar with how to do this in C++?

I think he is not as I am not .. This was a question of mine initially, so I am interested in this too.


I had tried to do it but didn't succeed so I gave up. I think one must know how C++ structs are stored in memory and how to properly align things etc etc.. If you do know and could give us an example in reascript, it would be really great!
__________________
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 08-24-2021, 06:47 AM   #1606
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 3,714
Default

I quickly checked how the relevant structs are stored in memory (in my Windows 10 x64 bit system), and I think the following may work. (I haven't tested it myself, however, since I don't know what exactly you are trying to do with the HDM_LAYOUT message.)

The HDM_LAYOUT message requires a pointer to a HDLAYOUT structure as argument. This HDLAYOUT struct is simple, 16 bytes containing two 64bit pointers:
Code:
typedef struct _HD_LAYOUT {
  RECT      *prc;
  WINDOWPOS *pwpos;
} HDLAYOUT
So to create the HDLAYOUT struct via Lua, you can try this:
Code:
HDLAYOUT = string.pack("<i8i8", RECT_address, WINDOWPOS_address)
HDLAYOUT_handle = reaper.JS_Mem_Alloc(16)
reaper.JS_Mem_FromString(HDLAYOUT_handle, 0, HDLAYOUT, #HDLAYOUT)

The first component in HDLAYOUT points to a RECT structure, which is 16 bytes containing four 32-bit signed integers:
Code:
typedef struct tagRECT {
  LONG left;
  LONG top;
  LONG right;
  LONG bottom;
} RECT
To create a RECT, try this:
Code:
RECT = string.pack("<i4i4i4i4", left, top, right, bottom)
RECT_handle = reaper.JS_Mem_Alloc(16)
reaper.JS_Mem_FromString(RECT_handle, 0, RECT, #RECT)

The WINDOWPOS structure is a bit more complex:
Code:
typedef struct tagWINDOWPOS {
  HWND hwnd;
  HWND hwndInsertAfter;
  int  x;
  int  y;
  int  cx;
  int  cy;
  UINT flags;
} WINDOWPOS
On my Windows 10 x64 system, it uses 4 bytes of padding at the end to get the total size to 40 bytes:
Code:
WINDOWPOS = string.pack("<i8i8i4i4i4i4I4xxxx", hwnd, hwndInsertAfter, x, y, cx, cy, flags)
WINDOWPOS_handle = reaper.JS_Mem_Alloc(40)
reaper.JS_Mem_FromString(WINDOWPOS_handle, 0, WINDOWPOS, #WINDOWPOS)

So putting it all together, you get something like this:
(If you prefer, you can pack everything into a single 72-byte string with a single string.pack, Mem_Alloc and Mem_Free.)
Code:
hwnd = reaper.JS_Window_Find("My Window", true)
hwnd_address = reaper.JS_Window_AddressFromHandle(hwnd)

left, top, right, bottom = 100, 100, 300, 300
x, y, width, height, flags = 0, 0, 200, 200, 0x020
hwndInsertAfter = 0

RECT = string.pack("<i4i4i4i4", left, top, right, bottom)
RECT_handle = reaper.JS_Mem_Alloc(16)
RECT_address = reaper.JS_Window_AddressFromHandle(RECT_handle)
reaper.JS_Mem_FromString(RECT_handle, 0, RECT, #RECT)

WINDOWPOS = string.pack("<i8i8i4i4i4i4I4xxxx", hwnd_address, hwndInsertAfter, x, y, width, height, flags)
WINDOWPOS_handle = reaper.JS_Mem_Alloc(40)
WINDOWPOS_address = reaper.JS_Window_AddressFromHandle(WINDOWPOS_handle)
reaper.JS_Mem_FromString(WINDOWPOS_handle, 0, WINDOWPOS, #WINDOWPOS)

HDLAYOUT = string.pack("<i8i8", RECT_address, WINDOWPOS_address)
HDLAYOUT_handle = reaper.JS_Mem_Alloc(16)
HDLAYOUT_address = reaper.JS_Window_AddressFromHandle(HDLAYOUT_handle)
reaper.JS_Mem_FromString(HDLAYOUT_address, 0, HDLAYOUT, #HDLAYOUT)

reaper.JS_WindowMessage_Send(hwnd, "0x1205", HDLAYOUT_address, 0, 0, 0)

reaper.JS_Mem_Free(HDLAYOUT_handle)
reaper.JS_Mem_Free(RECT_handle)
reaper.JS_Mem_Free(WINDOWPOS_handle)

Last edited by juliansader; 08-24-2021 at 07:39 AM.
juliansader is offline   Reply With Quote
Old 08-25-2021, 08:06 AM   #1607
amagalma
Human being with feelings
 
amagalma's Avatar
 
Join Date: Apr 2011
Posts: 3,451
Default

Thank you very much for your help julian!! I am going to try it again now. I wanted this in order to make preset sizes of the ReaScript IDE window.
__________________
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 08-25-2021, 11:53 AM   #1608
euxebio
Human being with feelings
 
euxebio's Avatar
 
Join Date: Apr 2020
Location: Italy
Posts: 22
Default

Quote:
Originally Posted by juliansader View Post
Are you familiar with how to do this in C++?
To better understand what I mean go to the link

https://forum.cockos.com/showthread.php?t=256629

If you can help me, you do me a great favor

Thanks a lot
euxebio is offline   Reply With Quote
Old 08-25-2021, 02:13 PM   #1609
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 3,714
Default

I will answer in the other thread.

Last edited by juliansader; 08-25-2021 at 02:27 PM.
juliansader is offline   Reply With Quote
Old 08-28-2021, 11:38 AM   #1610
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,913
Default

I guess JS_ListView_SetItemState doesn't work on MAC? (see thread & post #5 for scripts,).
Or I using the functions incorrectly?
MAC doesn't support these functions?
Its all REAPER's fault?


Quote:
Originally Posted by Edgemeal View Post
Cool!
Whats the correct way to select/unselect LV items? This was the only way I could get it to work (Win10_x64), but doesn't seem to be what the doc is saying.

Last edited by Edgemeal; 12-09-2021 at 02:48 PM.
Edgemeal is offline   Reply With Quote
Old 08-28-2021, 02:26 PM   #1611
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 3,714
Default

Quote:
Originally Posted by Edgemeal View Post
I guess JS_ListView_SetItemState doesn't work on MAC? (see thread & post #5 for scripts,).
Or I using the functions incorrectly?
MAC doesn't support these functions?
Its all REAPER's fault?
Whoops, there is an error in my documentation for ListView_Get/SetItemState: Focused and Selected should be 1 and 2, respectively (from the Win32 definitions: #define LVIS_FOCUSED 0x0001 #define LVIS_SELECTED 0x0002)
juliansader is offline   Reply With Quote
Old 08-29-2021, 07:14 AM   #1612
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,913
Default

Quote:
Originally Posted by juliansader View Post
Whoops, there is an error in my documentation for ListView_Get/SetItemState: Focused and Selected should be 1 and 2, respectively (from the Win32 definitions: #define LVIS_FOCUSED 0x0001 #define LVIS_SELECTED 0x0002)
Not sure I follow the documentation and param settings, looked at code in my Windows app, maybe this is the correct way to use your function then?
Code:
reaper.JS_ListView_SetItemState(hwnd, index, 0xF, 0x2) -- select item @ index
reaper.JS_ListView_SetItemState(hwnd, -1,    0xF, 0x2) -- select all items
reaper.JS_ListView_SetItemState(hwnd, index, 0x0, 0x2) -- unselect item @ index
reaper.JS_ListView_SetItemState(hwnd, -1,    0x0, 0x2) -- unselect all items
Any feedback would be appreciated.
Edgemeal is offline   Reply With Quote
Old 08-29-2021, 12:38 PM   #1613
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 3,714
Default

That should be correct, yes.
juliansader is offline   Reply With Quote
Old 09-15-2021, 04:50 AM   #1614
amagalma
Human being with feelings
 
amagalma's Avatar
 
Join Date: Apr 2011
Posts: 3,451
Default

Could JS_Dialog_BrowseForFolder be made to allow multiple selection of folders?
__________________
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 09-16-2021, 06:14 AM   #1615
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 3,714
Default

Quote:
Originally Posted by amagalma View Post
Could JS_Dialog_BrowseForFolder be made to allow multiple selection of folders?
Unfortunately not, AFAIK.
juliansader is offline   Reply With Quote
Old 09-16-2021, 07:36 AM   #1616
heda
Human being with feelings
 
heda's Avatar
 
Join Date: Jun 2012
Location: Spain
Posts: 7,239
Default

I direct downloaded reaper_js_ReaScriptAPI64.so from https://github.com/juliansader/ReaEx...riptAPI/v1.220
copied to UserPlugins directory, but it doesn't work on Linux... can't see any JS_ function on the reaper reascript documentation generated page either.. Previous version 1.10 I think it was, worked well. I'll try again later with all versions maybe I did something wrong
heda is offline   Reply With Quote
Old 09-16-2021, 01:29 PM   #1617
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 3,714
Default

Please check out these posts for a possible solution. I hope it was simply a download problem.
juliansader is offline   Reply With Quote
Old 09-16-2021, 03:08 PM   #1618
heda
Human being with feelings
 
heda's Avatar
 
Join Date: Jun 2012
Location: Spain
Posts: 7,239
Default

Quote:
Originally Posted by juliansader View Post
Please check out these posts for a possible solution. I hope it was simply a download problem.
Just tried it again... it doesn't give any error but the JS_ functions are not there. I used the "Download" button and also tried Save link as... on the View Raw link... same result.

so I tried previous versions and 1.215 works. so strange.

v1.220 no
v1.217 no
v1.215 works
heda is offline   Reply With Quote
Old 09-19-2021, 06:18 AM   #1619
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 3,714
Default

Could you please try this new build? reaper_js_ReaScriptAPI64.so
juliansader is offline   Reply With Quote
Old 09-19-2021, 04:07 PM   #1620
heda
Human being with feelings
 
heda's Avatar
 
Join Date: Jun 2012
Location: Spain
Posts: 7,239
Default

Quote:
Originally Posted by juliansader View Post
Could you please try this new build? reaper_js_ReaScriptAPI64.so
yay! it works! Thank you. I hope it was easy to fix

to discard that I got a corrupted download on the old 1.220 one
Code:
this one SHA256 is:
fc8f426feade478ba6e78508e7d43bc0184675a896d604cd83d81707d52adb8b


and the old one SHA256: 
7e567a95a478df853f01d7d700a36ed9b35e842ef6afeada47616bef9a2f98d4
heda is offline   Reply With Quote
Old 10-12-2021, 02:34 AM   #1621
dangguidan
Human being with feelings
 
Join Date: Jan 2019
Location: China
Posts: 654
Default

reaper.JS_VKeys_GetState
Can I mask when entering text?
For example, when I enter track name.
dangguidan is offline   Reply With Quote
Old 10-12-2021, 04:33 AM   #1622
cohler
Banned
 
Join Date: Dec 2018
Posts: 642
Default Setting secondary record path

Is there any way to SET the secondary recording path using js_ReaScriptAPI?

Yes, I know you can set it manually in the Project Settings dialog.

Yes, I know you can read it from the RPP file.

Yes, I know you could rewrite the RPP file and reload the RPP file from scratch.

I'm wondering if there is a way to SET it directly in memory from a script as the primary recording path (RECORD_PATH) can be set using
Code:
reaper.GetSetProjectInfo_String
but this function doesn't include any parameter for the secondary recording path.
cohler is offline   Reply With Quote
Old 10-20-2021, 12:15 AM   #1623
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 3,714
Default

Unfortunately not that I know of. It would probably be best to submit a FR for GetSetProjectInfo_String.
juliansader is offline   Reply With Quote
Old 10-20-2021, 04:21 AM   #1624
cohler
Banned
 
Join Date: Dec 2018
Posts: 642
Default

Thank you Julian.
cohler is offline   Reply With Quote
Old 10-21-2021, 02:01 PM   #1625
cohler
Banned
 
Join Date: Dec 2018
Posts: 642
Default JS_WindowMessage_Send, and JS_Window_FindChildByID

Does JS_WindowMessage_Send not work on Mac?

Does JS_Window_FindChildByID not work on Mac?
cohler is offline   Reply With Quote
Old 10-21-2021, 05:40 PM   #1626
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 3,714
Default

Both should work fine. Are you encountering any problems?

BTW, RECORD_PATH_SECONDARY has now been implemented for GetSetProjectInfo_String in the dev version.
juliansader is offline   Reply With Quote
Old 10-21-2021, 06:43 PM   #1627
cohler
Banned
 
Join Date: Dec 2018
Posts: 642
Default

Sending either button clicks or keystrokes using the standard windows messages to the Project Settings window doesn't produce any response.

And using FindChildByID on the Project Settings window doesn't work.

Thanks for the info on the new dev version!
cohler is offline   Reply With Quote
Old 10-22-2021, 05:26 AM   #1628
cohler
Banned
 
Join Date: Dec 2018
Posts: 642
Default

Quote:
Originally Posted by cohler View Post
Sending either button clicks or keystrokes using the standard windows messages to the Project Settings window doesn't produce any response.

And using FindChildByID on the Project Settings window doesn't work.
To be more specific, I used the WM_KEYDOWN, WM_KEYUP messages as follows to send the SPACE character to the OK button. "win" below is the validated handle of the OK button (I confirmed this by successfully modifying the "OK" title of the window using JS_Window_SetTitle to "FOO" for example, and that works, but the following code does not activate the button, while manually typing a space does):
Code:
reaper.JS_WindowMessageSend(win,"WM_KEYDOWN",0x20,0,1,0x002C)
reaper.JS_WindowMessageSend(win,"WM_KEYUP",0x20,0,1,0xC02C)
I also tried "clicking" the OK button with the following code and nothing happens while manually clicking it works fine:
Code:
reaper.JS_WindowMessageSend(win,"WM_LBUTTONDOWN",1,0,0,0)
reaper.JS_WindowMessageSend(win,"WM_LBUTTONUP",0,0,0,0)
I know that the Project Settings window is a modal window. So obviously my script access to it is not from the same process that opened the window--which would be impossible--but rather from another independent process running simultaneously in the background using reaper.defer.

As for FindChildByID, the following code returns nil (also run from the separate process):
Code:
reaper.JS_Window_FindChildByID(win,1702)
where win is again the handle of the Project Settings window and 1702 is the ID (obtained with reaper.JS_Window_GetLong) of the primary record path child window.

Thanks for your help on this!
cohler is offline   Reply With Quote
Old 10-22-2021, 10:37 AM   #1629
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,913
Default

Quote:
Originally Posted by cohler View Post
As for FindChildByID, the following code returns nil (also run from the separate process):
Code:
reaper.JS_Window_FindChildByID(win,1702)
where win is again the handle of the Project Settings window and 1702 is the ID (obtained with reaper.JS_Window_GetLong) of the primary record path child window.
Are you sure you have the correct parent handle? Here on Win10 each Tab is a separate container child control of the main window. Only the buttons near the very bottom are on the main window.


On Windows we could use FindWindowEx with classname ('#32770') to identify which Tab the control we want is on, but I don't think MAC uses classnames? (I'm a Windows only guy )

So if there is only one child control with the ID of 1072 (or the one you want is the very first one) then you could probably just loop thru the child controls to find it?,..
Code:
  main_hwnd = reaper.JS_Window_FindTop("Project Settings", true)
  if not main_hwnd then return end

  -- loop thru all children on main window
  arr = reaper.new_array({}, 1024)
  reaper.JS_Window_ArrayAllChild(main_hwnd, arr)
  childs = arr.table()
  -- find first child with Command ID of 1072 and set text
  for j = 1, #childs do
    hwnd = reaper.JS_Window_HandleFromAddress(childs[j])
    primary_path_hwnd = reaper.JS_Window_FindChildByID(hwnd, 1702) 
    if primary_path_hwnd then
      reaper.JS_Window_SetTitle(primary_path_hwnd,"Path_Text_Goes_Here")
      break
    end 
  end
FWIW, one way I'd probably do it in Windows in case anyone is interested See SPY++ image above.
Code:
function Main()
  -- get main window ("Project Settings")
  main_hwnd = reaper.JS_Window_FindTop("Project Settings", true)
  if not main_hwnd then return end -- exit if not found!
  -- get handle of the tabpage we want, then the controls on that tabpage
  tabpage1 = reaper.JS_Window_FindEx(main_hwnd, main_hwnd, '#32770', '' ) -- 1st child with clasname '#32770' (1st tab)
  tabpage2 = reaper.JS_Window_FindEx(main_hwnd, tabpage1, '#32770', '' )  -- 2nd '#32770' child ('Media' / 2nd tab)
  primary_path_hwnd = reaper.JS_Window_FindChildByID(tabpage2, 1702)      -- hwnd for primary path (edit control)
  secondary_path_hwnd = reaper.JS_Window_FindChildByID(tabpage2, 1703)    -- hwnd for secondary path (edit control)
  -- Set text for paths
  reaper.JS_Window_SetTitle(primary_path_hwnd,"E:\\Primary_Path")
  reaper.JS_Window_SetTitle(secondary_path_hwnd,"E:\\Secondary_Path") 
  -- click the OK button near bottom of window
  OK_button = reaper.JS_Window_FindChildByID(main_hwnd, 1)
  reaper.JS_WindowMessage_Send(OK_button, "0xF5", 0, 0, 0, 0)
end

Last edited by Edgemeal; 10-23-2021 at 09:35 AM.
Edgemeal is offline   Reply With Quote
Old 10-22-2021, 10:44 AM   #1630
cohler
Banned
 
Join Date: Dec 2018
Posts: 642
Default

As I said, yes, I am sure I have the correct window handle and ID, because I was able to modify the window title from "OK" to "FOO" or whatever.

Furthermore, I obtained the window ID using reaper.JS_Window_GetLong(win,"ID") as I also noted.
cohler is offline   Reply With Quote
Old 10-22-2021, 10:46 AM   #1631
cohler
Banned
 
Join Date: Dec 2018
Posts: 642
Default

reaper.JS_Window_FindChildByID exists precisely to avoid ugly and cumbersome loops of code just to access a window for which we already know the ID.
cohler is offline   Reply With Quote
Old 10-22-2021, 11:57 AM   #1632
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,913
Default

Your button example works because it is on the main window handle and you are passing that handle to the function, But that primary path textbox is on Tab2 which is a container on the main window and has its own handle! To find a child by ID on Tab2 you'd need to pass the Tab2 handle to JS_Window_FindChildByID() function.

FWIW, FindChildByID does not enumerate, it only looks for a child on the parent handle you pass to it, so when I try this it will return NIL as expected since that textbox (ID 1702) is NOT on the main window!
Code:
  main_hwnd = reaper.JS_Window_FindTop("Project Settings", true)
  primary_path_hwnd = reaper.JS_Window_FindChildByID(main_hwnd, 1702)
All this is based on how it works in Windows.

If I'm wrong (since I don't use MAC) PLEASE post your code so others can help.
Edgemeal is offline   Reply With Quote
Old 10-22-2021, 12:18 PM   #1633
cohler
Banned
 
Join Date: Dec 2018
Posts: 642
Default

I see! Thank you @Edgemeal. I will try that and let you know...
cohler is offline   Reply With Quote
Old 10-22-2021, 12:37 PM   #1634
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,621
Default

Instead of using hacks, why not testing the last few dev? Had been added recently.
__________________
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 10-22-2021, 02:29 PM   #1635
cohler
Banned
 
Join Date: Dec 2018
Posts: 642
Default

Quote:
Originally Posted by Meo-Ada Mespotine View Post
Instead of using hacks, why not testing the last few dev? Had been added recently.
Nothing we do here is a "hack". I am aware of what was recently added in the last couple of devs and have already implemented that.

Writing programs that improve REAPER's user interface is not a "hack" as you say. We sell only quality, bug-free software, written using REAPER's publicly available API (Application Programming Interface).
cohler is offline   Reply With Quote
Old 10-22-2021, 05:26 PM   #1636
cohler
Banned
 
Join Date: Dec 2018
Posts: 642
Default

Quote:
Originally Posted by Edgemeal View Post
Your button example works because it is on the main window handle and you are passing that handle to the function, But that primary path textbox is on Tab2 which is a container on the main window and has its own handle! To find a child by ID on Tab2 you'd need to pass the Tab2 handle to JS_Window_FindChildByID() function.

FWIW, FindChildByID does not enumerate, it only looks for a child on the parent handle you pass to it, so when I try this it will return NIL as expected since that textbox (ID 1702) is NOT on the main window!
Code:
  main_hwnd = reaper.JS_Window_FindTop("Project Settings", true)
  primary_path_hwnd = reaper.JS_Window_FindChildByID(main_hwnd, 1702)
All this is based on how it works in Windows.

If I'm wrong (since I don't use MAC) PLEASE post your code so others can help.
I've investigated and it doesn't work the same on the Mac. I've got it working to the point where I know I have the correct window handles, because I can change the text of the child window IDs 1702 and 1703 using JS_Window_SetTitle and that works.

But the JS_WindowMessage_Send does not work. And I've tried using WM_LBUTTONDOWN/WM_LBUTTONUP, and WM_KEYDOWN/WM_KEYUP. The example given above uses BM_CLICK, but that message is not supported by swell.

Any ideas? Is the fact that it is a modal window somehow blocking key and mouse click messages from independent processes?
cohler is offline   Reply With Quote
Old 10-22-2021, 05:47 PM   #1637
cohler
Banned
 
Join Date: Dec 2018
Posts: 642
Default

Here is the code I am using:
Code:
_c=require("Cohler")
_=reaper

local ps

found = function()
  local r2w = _c.mychildbyid(ps,1703)
  _.JS_Window_SetTitle(r2w,"Scooby do")
  local OK = _c.mychildbyid(ps, 1)
  _.JS_Window_SetTitle(OK,"FOO")
  
  _.JS_WindowMessage_Send(OK, "WM_KEYDOWN", 0x20,0,0,0x2C)
  _.JS_WindowMessage_Send(OK, "WM_KEYUP", 0x20,0,1,0xC02C)
end

test = function()
  _.ShowConsoleMsg("Checking\n")
  ps =_.JS_Window_FindTop("Project Settings",true)
  return not not ps
end

_c.Wait(found,test,1)
_c.mychildbyid is my own routine to find the child window by ID because reaper.JS_Window_FindChildByID doesn't work on this modal window I guess. Clearly, this routine is working correctly, because the title updates work as expected.

_c.Wait is a routine that executes reaper.defer(test) every 1 second and executes function found when test returns true.

Everything else is standard REAPER.

To run the test, you run the code above, which creates the background process that is waiting for the Project Settings window to be opened (and thereby created). The background process prints "Checking" every one second in the Console, so you know that it is alive.

Then you go to the Action list and double click on Command ID 40934 ("Project recording settings") which opens/creates the Project Settings window with the Media tab already selected.

When you do that, the background process terminates, and succeeds in updating the title of child window 1703 and the text of the OK button to FOO.

But the click of the OK button (by the two JS_WindowMessage_Send calls) doesn't work. So the Project Settings window remains open.

(In the example above, I am sending a SPACE to the OK button, because that also clicks the button on Mac. I have also tried mouse click and button up/down etc, and none of them succeed in clicking the OK button and closing the window.)
cohler is offline   Reply With Quote
Old 10-23-2021, 08:49 AM   #1638
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,913
Default

Quote:
Originally Posted by cohler View Post
Nothing we do here is a "hack". I am aware of what was recently added in the last couple of devs and have already implemented that.

Writing programs that improve REAPER's user interface is not a "hack" as you say. We sell only quality, bug-free software, written using REAPER's publicly available API (Application Programming Interface).
Ya but Julian's API is an extension, things like in these last few posts are hacks IMO. The REAPER devs could change controls and/or their Command IDs at anytime and these scripts will no longer work as expected, whereas its very unlikely REAPERs own API functions will stop working so it really is best to use the REAPER API functions if when/where possible.

Speaking of hacks, when launching actions that open a modal window that stop a script from continuing its code, you can usually get around that by launching the action using PostMessage. Post does not wait for a return, so a defer loop will most likely be required to detect the window the action just opened, at least on Windows this trick/hack works great,..
Code:
function Main()  
  main_hwnd = reaper.JS_Window_FindTop("Project Settings", true) 
  if main_hwnd then   
    --  Do stuff once the window is found ---
    reaper.ShowConsoleMsg('Window found!' .. '\n')
  else
    reaper.ShowConsoleMsg('Window not yet found, trying again\n')    
    reaper.defer(Main)
  end 
end

-- Run action "File: Project settings..." without blocking this script,
reaper.JS_WindowMessage_Post(reaper.GetMainHwnd(), "WM_COMMAND", 40021,0,0,0)
Main()
Edgemeal is offline   Reply With Quote
Old 10-23-2021, 09:12 AM   #1639
cohler
Banned
 
Join Date: Dec 2018
Posts: 642
Default

Quote:
Originally Posted by Edgemeal View Post
when launching actions that open a modal window that stop a script from continuing its code, you can usually get around that by launching the action using PostMessage. Post does not wait for a return, so a defer loop will most likely be required to detect the window the action just opened, at least on Windows this trick/hack works great,..
Code:
function Main()  
  main_hwnd = reaper.JS_Window_FindTop("Project Settings", true) 
  if main_hwnd then   
    --  Do stuff once the window is found ---
    reaper.ShowConsoleMsg('Window found!' .. '\n')
  else
    reaper.ShowConsoleMsg('Window not yet found, trying again\n')    
    reaper.defer(Main)
  end 
end

-- Run action "File: Project settings..." without blocking this script,
reaper.JS_WindowMessage_Post(reaper.GetMainHwnd(), "WM_COMMAND", 40021,0,0,0)
Main()
Nice! Thanks for that. I was in essence doing the reverse of that, but that is also a helpful tool.
cohler is offline   Reply With Quote
Old 10-24-2021, 02:57 PM   #1640
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,913
Default

Quote:
Originally Posted by cohler View Post
Nice! Thanks for that. I was in essence doing the reverse of that, but that is also a helpful tool.
So what about the OK button? You still can't click it? Sending left mouse down/up messages on Mac should work...

Code:
function ClickWindow(hwnd)
  reaper.JS_WindowMessage_Send(hwnd, "WM_LBUTTONDOWN", 1, 0, 0, 0)
  reaper.JS_WindowMessage_Send(hwnd, "WM_LBUTTONUP", 0, 0, 0, 0)
end

function Main()  
  main_hwnd = reaper.JS_Window_FindTop("Project Settings", true) 
  if main_hwnd then   
    --  Do stuff once the window is found ---
    reaper.ShowConsoleMsg('Window found!\n')
    -- find & click the OK button
    OK_button = reaper.JS_Window_FindChildByID(main_hwnd, 1)
    if OK_button then
      reaper.ShowConsoleMsg('OK button found, Clicking OK button\n')
      ClickWindow(OK_button) 
    end 
  else
    reaper.ShowConsoleMsg('Window not yet found, trying again\n')    
    reaper.defer(Main)
  end 
end

-- Run action "File: Project settings..." without blocking this script,
reaper.JS_WindowMessage_Post(reaper.GetMainHwnd(), "WM_COMMAND", 40021,0,0,0)
Main()
Edgemeal 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 12:30 PM.


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