|
|
|
10-13-2018, 02:32 PM
|
#1
|
Human being with feelings
Join Date: Jul 2009
Posts: 3,714
|
js_ReaScriptAPI extension
I have uploaded a new extension that may be of interest to other scripters: "js_ReaScriptAPI".
It can be installed via ReaPack (if ReaTeam/Extensions is not listed among your default repositories, you can add the repository manually with this URL), or via direct download (copy the file to REAPER's /UserPlugins directory).
The idea behind this extension is to make all the useful and powerful functions that are available to C++ extensions available to ReaScripts too. (The resulting ReaScript API is therefore not the result of my own amazing programming skills, but is mostly just an interface to existing C++ functions.)
The online documentation for the corresponding C++ functions is probably the best place to learn how to use these functions. For example, Window messages and Drawing with GDI.
I have tried to make most functions cross-platform applicable, but I am not able to test the extension on MacOS, so let me know if anything doesn't work as expected.
Many thanks to cfillion, Xenakios and nofish, who helped me a *lot* to figure out the esoteric and undocumented mysteries of REAPER extensions.
Here are a few examples:
Attach "pin on top" button to script GUIs
FR: add 'always on top' pin for EEL script GUI's
Code:
w = reaper.JS_Window_Find("MIDI Inspector", true)
if w then reaper.JS_Window_AttachTopmostPin(w) end
Drawing inside REAPER windows
FR: Lasso Select for midi notes
Load custom cursors
FR: ReaScript: Allow scripts to change mouse cursor
Code:
-- Load REAPER's native "arpeggiate" cursor
reaper.JS_Mouse_SetCursor(reaper.JS_Mouse_LoadCursor(502))
-- Prevent REAPER from changing cursor back, by intercepting "SETCURSOR" messages
reaper.JS_WindowMessage_Intercept(window, "WM_SETCURSOR", false)
Take control of mouse clicks and mousewheel
By intercepting mouse and mousewheel messages, scripts can be controlled with the mouse, without activating REAPER's own mouse modifier actions.
For example, in my own "Mouse editing" CC scripts, I use code like the following to block the mouse from interacting with the piano roll while the script is running:
Code:
tIntercepts = { WM_LBUTTONDOWN = false,
WM_LBUTTONUP = false,
WM_LBUTTONDBLCLK = false,
WM_MBUTTONDOWN = false,
WM_MBUTTONUP = false,
WM_MBUTTONDBLCLK = false,
WM_RBUTTONDOWN = false,
WM_RBUTTONUP = false,
WM_RBUTTONDBLCLK = false,
WM_MOUSEWHEEL = false,
WM_MOUSEHWHEEL = false,
WM_MOUSEMOVE = false,
WM_SETCURSOR = false
}
midiview = reaper.JS_Window_FromPoint(reaper.GetMousePosition())
for key, value in pairs(tIntercepts) do
OK = reaper.JS_WindowMessage_Intercept(midiview, key, value)
end
The scripts can then use JS_WindowMessage_Peek to track mouse events while running:
Code:
peekOK, _, time, keys, rotate, x, y = reaper.JS_WindowMessage_Peek(midiview, "WM_MOUSEWHEEL")
if peekOK and time ~= prevTime then
-- mousewheel has moved since last defer cycle
end
peekOK, _, time, keys, _, x, y = reaper.JS_WindowMessage_Peek(midiview, "WM_LBUTTONDOWN")
if peekOK and time ~= prevTime then
-- Left button has been pressed
end
Trigger REAPER actions for any window
Send commands to any window, similar to Main_OnCommand and MIDIEditor_OnCommand:
Code:
-- Action 1011 = Autoplay: Toggle on/off
me = reaper.JS_Window_Find("Media Explorer", true)
reaper.JS_Window_OnCommand(me, commandID)
Keep the Mixer window out of the way
FR: Plugin windows always on top, Mixer window always behind
The API offers several functions for getting and setting the Z order and focus of windows, so one possible solution for the FR is discussed here:
Move Mixer out of the way: example of Win32/SWELL in ReaScript.
Track mouse events outside script GUI
FR: Exposure of mouse state-functions for non gfx.ini-created windows
In addition to the WindowMessage functions, which are specific to a single target window, the mouse can be tracked using JS_Mouse_GetState:
Code:
-- Flag 0b00000001+0b00010000 = left mouse button + alt key
if reaper.JS_Mouse_GetState(0x0011) = 0x0011 then
--...
end
Frameless script GUIs
FR: Stylish ReaScript GUIs: Transparent backgrounds and no titlebars:
Using JS_Window_SetStyle, or when creating new windows:
Last edited by juliansader; 12-13-2019 at 01:08 PM.
|
|
|
10-13-2018, 02:35 PM
|
#2
|
Human being with feelings
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 4,079
|
Interesting, looks cool!
|
|
|
10-13-2018, 03:08 PM
|
#3
|
Human being with feelings
Join Date: Oct 2017
Location: Black Forest
Posts: 5,130
|
Holy cow, didn't see THAT coming! Mouse lasso, always on top... Geez Julian, you never cease to amaze me!
|
|
|
10-13-2018, 03:56 PM
|
#4
|
Human being with feelings
Join Date: Apr 2013
Location: France
Posts: 10,088
|
Many thx ! This may bring a lot of useful things !
C++ function were recently exposed in SWS but because pull request are very long to be merged, having your extension will definitly be useful
Though I dont see the function for getting bitdepth, which is accessible for C++ and was wating for mege in SWS, is it missing ?
Ill try to add your functions in my reascript doc.
|
|
|
10-13-2018, 03:59 PM
|
#5
|
Human being with feelings
Join Date: Oct 2017
Location: Black Forest
Posts: 5,130
|
Quote:
Originally Posted by X-Raym
Ill try to add your functions in my reascript doc.
|
Merci X-Raym!!!
|
|
|
10-13-2018, 04:31 PM
|
#6
|
Human being with feelings
Join Date: Apr 2011
Posts: 3,547
|
AMAZING!!! :O
Well done! A lot of useful stuff in there opening great possibilities!
|
|
|
10-13-2018, 05:37 PM
|
#7
|
Human being with feelings
Join Date: Apr 2013
Location: France
Posts: 10,088
|
js_function v0.93 added to my ReaScript doc !
@_Stevie_
:P
|
|
|
10-13-2018, 07:48 PM
|
#8
|
Human being with feelings
Join Date: Oct 2017
Location: Black Forest
Posts: 5,130
|
Wow that was fast X-Raym, formidable!!! This is like Xmas in October!
|
|
|
10-13-2018, 08:01 PM
|
#9
|
Human being with feelings
Join Date: Oct 2017
Location: Black Forest
Posts: 5,130
|
@Julian: haven't tried it yet, but is it possible to show/hide dockers with your window function? Would love to independently show/hide the left and right docker.
|
|
|
10-13-2018, 09:49 PM
|
#10
|
Human being with feelings
Join Date: Dec 2014
Posts: 417
|
WOW!!!
Last edited by NextLevel; 10-13-2018 at 10:16 PM.
|
|
|
10-13-2018, 11:21 PM
|
#11
|
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 15,726
|
AMAZING !
Can (some of) this also be used with JSFX ?
-Michael
|
|
|
10-14-2018, 02:42 AM
|
#12
|
Human being with feelings
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
|
Quote:
Originally Posted by mschnell
Can (some of) this also be used with JSFX ?
|
JSFX do not have support for 3rd party extensions.
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.
|
|
|
10-14-2018, 03:33 AM
|
#13
|
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 15,726
|
That is rather sad
-Michael
|
|
|
10-14-2018, 03:57 AM
|
#14
|
Human being with feelings
Join Date: Jun 2017
Posts: 187
|
Cool,
I wonder if you could extend it a little bit?
Writing in some languages sucks or does not offer as much performance.
Could you potentially extend your plugin to load other plugin compiled in other languages(such as c++/d/haskell/etc)?
The idea is this:
1. You have a context variable that allows any plugin to use to access the methods and variables(an interface basically).
2. You compile the source code when it changes by monitoring any changes and recompiling and loading(this might work only when restarting reaper without some special hot plugging capabilities). You just run a compile string on the code.
3. You load the code, run any setup routines(similar to dll loading). Run some main function(possibly in another thread) and pass it the context.
This then makes it much easier to write programs and even debug them(e.g., with windows one could use VS to debug the program while it is in reaper).
It would allow for much more freedom than using reapers built in scripting, which isn't bad but isn't great(mainly the dev part such as using IDE's and such).
It would also make writing plugins easier in some ways.
Most of the work shouldn't be too difficult(it can be done easily but might be hard to do well).
|
|
|
10-14-2018, 04:46 AM
|
#15
|
Human being with feelings
Join Date: Dec 2014
Posts: 417
|
@juliansader,
Noticed a little typo in the "MediaExplorer_OnCommand" example.
The line "m = reaper.JS_Window_Find("Media Explorer", true)"
should be "me = reaper.JS_Window_Find("Media Explorer", true)"
This extension is going to open up some nice possibilities, so thank you so much!
Just added your "pin to top" example to Lokasenna's Radial Menu.., yea!!!
|
|
|
10-14-2018, 04:50 AM
|
#16
|
Human being with feelings
Join Date: Apr 2013
Location: France
Posts: 10,088
|
Quote:
Could you potentially extend your plugin to load other plugin compiled in other languages(such as c++/d/haskell/etc)?
|
ReaScript already supports Lua and Python, I don't think there is a lot of demand for other languages.
Quote:
Most of the work shouldn't be too difficult
|
You seems to have a lot of knowledge about programming, so why no you take a try to do this ?
Juliansader extension is open source, you can work from there.
|
|
|
10-14-2018, 05:13 AM
|
#17
|
Human being with feelings
Join Date: Apr 2011
Posts: 3,547
|
Quote:
Originally Posted by X-Raym
|
Where are they? I can't find them
|
|
|
10-14-2018, 05:16 AM
|
#18
|
Human being with feelings
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
|
In case someone has been confused : "js" here comes from "Julian Sader", it has nothing to do with JesuSonic or JavaScript...
The extension plugin adds new API functions that can be used with ReaScript, no new features visible for the end user are added by only installing the plugin.
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.
|
|
|
10-14-2018, 06:38 AM
|
#19
|
Human being with feelings
Join Date: Dec 2014
Posts: 417
|
Is there a way to set mouse position relative to a specific window?
Meaning that even if the window is in a different position each time the script is executed it will always set the mouse to the same position within that window.
|
|
|
10-14-2018, 06:54 AM
|
#20
|
Human being with feelings
Join Date: Oct 2007
Location: home is where the heart is
Posts: 12,203
|
Amazing. Kudos for the work you've put into this!
Quote:
Originally Posted by juliansader
|
I'd tend to suggest all ReaScripters having scripts with GUI's to update their scripts to add the 'always on top' pin.
Last edited by nofish; 10-14-2018 at 07:36 AM.
|
|
|
10-14-2018, 07:10 AM
|
#21
|
Human being with feelings
Join Date: Oct 2007
Location: home is where the heart is
Posts: 12,203
|
Quote:
Originally Posted by X-Raym
Though I dont see the function for getting bitdepth, which is accessible for C++ and was wating for mege in SWS, is it missing ?
|
This came from cfillion and is still waiting for merge in SWS.
https://github.com/reaper-oss/sws/pull/1011
|
|
|
10-14-2018, 08:31 AM
|
#22
|
Human being with feelings
Join Date: Oct 2007
Location: home is where the heart is
Posts: 12,203
|
Quote:
Originally Posted by amagalma
Where are they? I can't find them
|
|
|
|
10-14-2018, 09:21 AM
|
#23
|
Human being with feelings
Join Date: Jul 2009
Posts: 3,714
|
Updated to v0.94 with new WAV writer functions by Xenakios, and a bugfix in JS_Window_GetRelated.
Quote:
Originally Posted by NextLevel
Is there a way to set mouse position relative to a specific window?
Meaning that even if the window is in a different position each time the script is executed it will always set the mouse to the same position within that window.
|
Sure: Get the window's screen coordinates using JS_Window_GetRect or JS_Window_GetClientRect, and then move the mouse using JS_Mouse_SetPosition.
Quote:
Originally Posted by _Stevie_
@Julian: haven't tried it yet, but is it possible to show/hide dockers with your window function? Would love to independently show/hide the left and right docker.
|
I'll have to check -- I have never tried this before via scripts.
|
|
|
10-14-2018, 09:48 AM
|
#24
|
Human being with feelings
Join Date: Oct 2017
Location: Black Forest
Posts: 5,130
|
@Julian
The problem seems, that Reaper does not differentiate between lower, upper, left or right docker.
https://forum.cockos.com/showpost.ph...9&postcount=19
But I will give it a shot, when I got a bit more time!
|
|
|
10-14-2018, 09:58 AM
|
#25
|
Human being with feelings
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
|
Quote:
Originally Posted by juliansader
Updated to v0.94 with new WAV writer functions by Xenakios,
|
I will post a Lua ReaScript example for using this soon somewhere.
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.
|
|
|
10-14-2018, 10:34 AM
|
#26
|
Human being with feelings
Join Date: Apr 2011
Posts: 3,547
|
Strange... Here the page opens with v5.95 without the js functions.. I wonder why...
Quote:
Originally Posted by nofish
|
Cleaning the history and re-opening the browser, fixed it Well-done X-Raym!
|
|
|
10-14-2018, 10:46 AM
|
#27
|
Human being with feelings
Join Date: Jul 2009
Posts: 3,714
|
Quote:
Originally Posted by _Stevie_
|
As Breeder noted, "under the hood", REAPER does distinguish between the dockers and they have different window HWNDs, so it should be possible to selectively access them.
Two other useful remarks that I noticed in the other thread:
Quote:
Originally Posted by Garrick
So as it stands, the only way a dock position is hidden is if it contains no tabs.
|
Quote:
Originally Posted by Breeder
and exists even if you don't use it, it's just hidden...windows are called "REAPER_dock", have a look yourself if you don't believe me
|
So I guess you can find specific dockers in at least two ways:
1) Find all the windows named "REAPER_dock", get their coordinates, and check which are positioned at the edges of the main window.
2) If specific windows (such as Actions) are always docked in specific dockers (such as the left docker), you can instead find the window, then find the REAPER_dock that is its parent.
To hide the docker, you can't destroy the docker itself (or its necessary child windows), but must instead destroy the tabs.
I checked the docker's child windows, and it seems that its frame is named "Custom" something.
The following code seems to work to close the docker under the mouse:
Code:
w = reaper.JS_Window_FromPoint(reaper.GetMousePosition())
::getParentDock::
if not w then return end
t = reaper.JS_Window_GetTitle(w, "")
if t == "REAPER_dock" then goto gotDock end
w = reaper.JS_Window_GetParent(w)
goto getParentDock
::gotDock::
a = reaper.new_array({}, 100)
reaper.JS_Window_ArrayAllChild(w, a)
tHandles = a.table()
tTitles = {}
for i = 1, #tHandles do
tHandles[i] = reaper.JS_Window_HandleFromAddress(tHandles[i])
tTitles[i] = reaper.JS_Window_GetTitle(tHandles[i], "")
end
for i = 1, #tHandles do
if not tTitles[i]:match("Custom") then reaper.JS_Window_Destroy(tHandles[i]) end
end
* Alternatively, you can probably JS_WindowMessage_Send some WM_COMMAND message to simulate the menu item "Close all windows in dock".
* JS_Window_Show(dockerHWND, "HIDE") can hide the docker and JS_Window_Show(dockerHWND, "SHOW") can show it again, but the track view doesn't expand after hiding the docker, so these functions alone aren't enough.
We will have to experiment some more...
Last edited by juliansader; 10-14-2018 at 12:29 PM.
|
|
|
10-14-2018, 02:21 PM
|
#28
|
Human being with feelings
Join Date: May 2017
Location: Leipzig
Posts: 6,707
|
This! Is! Awesome!
Thank you for your work
Under which license do you release the Plugin? Opensource-MIT-license or something similar? Couldn't find a reference to it in the sources.
Do you intend to expose the OSC-related functions as well?
And is there a chance for adding the pending API-SWS-functions from nf or cf to this plugin as well?
And a small little request: Could you add a "GetJSReaScriptAPIVersion()"-function? So I can check, whether a version of your plugin is supported by my script.
Again..fantastic work
Last edited by Meo-Ada Mespotine; 10-14-2018 at 02:27 PM.
|
|
|
10-14-2018, 04:47 PM
|
#29
|
Human being with feelings
Join Date: Oct 2007
Location: home is where the heart is
Posts: 12,203
|
Quote:
Originally Posted by mespotine
And a small little request: Could you add a "GetJSReaScriptAPIVersion()"-function?
|
https://www.extremraym.com/cloud/rea...iptAPI_Version
|
|
|
10-14-2018, 05:06 PM
|
#30
|
Human being with feelings
Join Date: Apr 2011
Posts: 3,547
|
I didn't have the time yet to try things.. But is it possible now to get somehow what is selected?
|
|
|
10-14-2018, 07:27 PM
|
#31
|
Human being with feelings
Join Date: Dec 2014
Posts: 417
|
Quote:
Originally Posted by juliansader
Sure: Get the window's screen coordinates using JS_Window_GetRect or JS_Window_GetClientRect, and then move the mouse using JS_Mouse_SetPosition.
|
Awesome, thank you.
|
|
|
10-15-2018, 12:38 AM
|
#32
|
Human being with feelings
Join Date: Apr 2014
Posts: 4,178
|
Just WOW!! Thank you - I'll be looking into this soon.
Before I've managed to have a detailed look - is there a way of telling if the extension is installed or not to know whether a script can use the new available functions? I guess this would need to be a native Reaper function.
I like the look of Window_Resize and Move - does this mean a script can resize it's own GUI window?
EDIT: Oooh - just also notice MOUSE_SetPosition - one I've been wanting for a loooong time
Thank you again! This is going to be massively useful!
Last edited by lb0; 10-15-2018 at 12:51 AM.
|
|
|
10-15-2018, 02:30 AM
|
#33
|
Human being with feelings
Join Date: May 2015
Location: Québec, Canada
Posts: 5,154
|
Quote:
Originally Posted by lb0
Before I've managed to have a detailed look - is there a way of telling if the extension is installed or not to know whether a script can use the new available functions? I guess this would need to be a native Reaper function.
|
Nonexistent API functions evaluate to nil (also there's APIExists).
|
|
|
10-15-2018, 03:18 AM
|
#34
|
Human being with feelings
Join Date: Apr 2014
Posts: 4,178
|
Quote:
Originally Posted by cfillion
Nonexistent API functions evaluate to nil (also there's APIExists).
|
Aha - of course! Thank you. Remind me to wake up properly and engage brain before asking questions. I knew about and use the API_Exists function already - but did not know about the evaluate to nil - so have learned something
|
|
|
10-15-2018, 04:24 AM
|
#35
|
Human being with feelings
Join Date: Dec 2014
Posts: 417
|
Just did an experiment and found that Parameter Modulation windows can be made to have a "pin to top" added.., how awesome is that?!!!
I always hated having those windows get lost behind other windows.
Now, perhaps someone with better reascript skills than myself could find a way to aggregate any open Param. Mod. windows and add a "pin to top" to all at once?
|
|
|
10-15-2018, 05:01 AM
|
#36
|
Human being with feelings
Join Date: Jul 2009
Posts: 3,714
|
Quote:
Originally Posted by lb0
I like the look of Window_Resize and Move - does this mean a script can resize it's own GUI window?
|
Yep.
Besides checking and resetting window size and position in each defer cycle, you can prevent a user from changing the size or position of the window by dragging on the frame by blocking "WM_NCLBUTTONDOWN" mouse events:
Code:
iOK = reaper.JS_WindowMessage_Intercept(window, "WM_NCLBUTTONDOWN", false)
If you block these messages, you will probably have to check for clicks on the "Close" button yourself.
(There may be other, better ways to prevent resizing that I am not familiar with. Unfortunately, window frame styles don't seem to be cross-platform applicable.)
Last edited by juliansader; 10-15-2018 at 05:17 AM.
|
|
|
10-15-2018, 05:06 AM
|
#37
|
Human being with feelings
Join Date: Apr 2013
Location: France
Posts: 10,088
|
Quote:
Now, perhaps someone with better reascript skills than myself could find a way to aggregate any open Param. Mod. windows and add a "pin to top" to all at once?
|
This really should be handle by REAPER natively IMHO, we will end up with a looooot of defer background scripts and start up actions if we start adding small things like that ^^
|
|
|
10-15-2018, 05:31 AM
|
#38
|
Human being with feelings
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
|
Quote:
Originally Posted by X-Raym
This really should be handle by REAPER natively IMHO, we will end up with a looooot of defer background scripts and start up actions if we start adding small things like that ^^
|
Yeah, one should not go crazy with the background scripts. They run in the GUI thread with a timer and will eat up GUI CPU cycles from Reaper and audio plugins...
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.
|
|
|
10-15-2018, 05:56 AM
|
#39
|
Human being with feelings
Join Date: Dec 2014
Posts: 417
|
Quote:
Originally Posted by X-Raym
This really should be handle by REAPER natively IMHO, we will end up with a looooot of defer background scripts and start up actions if we start adding small things like that ^^
|
It wouldn't need to be a deferred script, it would just run once and gather a list of all open Param. Mod. windows then add a pin to them, the script would then end. Obviously if you close any of them and reopen you lose the pin and have to rerun the script, but that's no big deal.
Anyone want to give it a shot?
|
|
|
10-15-2018, 08:35 AM
|
#40
|
Human being with feelings
Join Date: May 2017
Location: Leipzig
Posts: 6,707
|
@nofish
Thnx, missed that one amog the 100+functions
@JS
I found some issues yesterday while experimenting, but I'm still not sure, whether it's me not getting it or a bug.
Some of the functions want "void" as datatype in their functions(at least, the error-message tells that), I found that with several functions that want HDCs or HWNDs as parameters.
They should return as error-message the type they actually want, even if it's called "Identifier" or something to make debugging easier.
Will check that more in detail to give you a more detailed report.
JS_LICE_Blit()
When passing a HWND as parameter destBitmap, the script crashes Lua, and I can't restart the script anymore, that includes that faulty line, until I restart Reaper.
Maybe it would be a good idea to include a check, if the parameter is a valid bitmap, to prevent such things.
Is there a way to remove the pin from a window again?
Is there a chance to include another function, that returns keyboard inputs, maybe for UNICODe characters and for multiple keys as well? The gfx.getchar doesn't support multikey-inputs and has big problems with UNICODE-stuff
And is there a documentation on how to build it on Win and Mac? I would love to attempt adding some more functions myself but want to check the builds before submitting any commits...
|
|
|
Thread Tools |
|
Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -7. The time now is 07:20 PM.
|