Creative Communities of the World Forums

The peer to peer support community for media production professionals.

Activity Forums Adobe After Effects Expressions Limit to After Effect Script Hotkeys

  • Tomas Bumbulevičius

    April 6, 2022 at 9:16 am

    Hey Ralph, one potential way could be by adding scripts into custom toolbar – while its not a hotkey, limitation is.. No limitation 😉

  • Constantin Maier

    April 12, 2022 at 3:21 pm

    There’s a workaround, however, I was only able to make it work properly on Windows. If you’re on Windows, here’s what you can do:

    Not sure what you’re doing exactly but you can, for example, create some sort of UI where you let the user define shortcuts for a variety of scripts. Now save the different shortcuts, either to a file or to the AE preferences. Now apply all those shortcuts to a single script that’s located in AE’s scripts folder. Now, every one of those shortcuts will call that script. Within that script, you can read the currently pressed keys via the environment keyboardState variables:

    https://extendscript.docsforadobe.dev/user-interface-tools/environment.html?highlight=environment#keyboard-state-object

    You should read the keys directly at the top of the script. If you have a longer script and you read the keys too far down the script, the user might have already let go of the keys at the time the script execution reaches this point.

    Now you know which keys the user pressed and can match those to the script that you defined earlier and that you can then execute.

    As I said, I only got this to work on Windows. On Mac, it can work too, however, there seems to be some sort of lag between pressing the shortcut and AE executing the script. That often leads to the fact that the keyboardState variables only return an “undefined”. You would have to keep the shortcut pressed for an unusually long time in order for the keyboardState variables to work. Now, if this script is just for you, you might find it still okay. However, if you want to distribute the script, I don’t think it’s acceptable.

    Hope this helps.

    PS: If you find a way to make it work on Mac, please, please let me know! 😀

  • Ralph Moreau

    April 21, 2022 at 4:04 pm

    Both lovely answers. Thank you both! But Constantin very fascinated by your answer, could it be possible to see some logic used like this in context. The javascript used by the codebase is great, but not always predictable when it comes to writing it properly. If I could see an example I would overjoyed. Thank you.

  • Constantin Maier

    April 21, 2022 at 9:52 pm

    Hey, it’s quite a complicated thing, so I can’t give you my full code. It’s very long, interconnected with a bunch of other stuff, and also very specific to the use of this script. It would be too time-consuming to cover everything here but I hope you can figure out the rest yourself.

    So let’s assume you’ve built your UI where people enter shortcuts that are attached to a certain script file. Now you will have to save these shortcuts to a textfile which might look like this:

    My Script 1.jsx = Shift+G
    My Script 2.jsx = Ctrl+Alt+Shift+U
    My Script 3.jsx = Ctrl+R

    Now you also have to write these shortcuts to AE’s shortcut file (and in there to the one script that will execute all other scripts). Get the name of the active shortcut file (= the current “Keyboard Layout Preset” as it’s also called within AE) like this:

    var activeKeyFile;
    if (app.preferences.havePref("General Section", "Shortcut File Location", PREFType.PREF_Type_MACHINE_SPECIFIC)){
    activeKeyFile = app.preferences.getPrefAsString("General Section", "Shortcut File Location", PREFType.PREF_Type_MACHINE_SPECIFIC);
    }

    Now you have the name but you also need the file itself. For this, we first have to determine the OS:

    // Determine Operating System
    var thisOS;
    if ($.os.indexOf("Windows") != -1 || system.osName.indexOf("Windows") != -1){
    thisOS = "Windows";
    } else if ($.os.indexOf("Mac") != -1 || system.osName.indexOf("Mac") != -1){
    thisOS = "Mac";
    }

    Now let’s find the user folder (on Mac the directory is a bit different than on Windows since it’s not directly in the folder that is to be found with “Folder.userData”):

    var userData;
    if (thisOS == "Windows"){
    userData = Folder.userData.fullName;
    else if (thisOS == "Mac"){
    userData = Folder.userData.parent.fullName + "/Preferences";
    }

    Afterwards, we can define the folder in which AE’s shortcut file lives and combine it with the name of the current shortcut file to reference the actual file:

    var aeKeyFolderString = userData + "/Adobe/After Effects/" + app.version.substring(0, 4) + "/aeks";
    var aeKeyFile = File(aeKeyFolderString + "/" + activeKeyFile);

    Now read the file with a basic function like this one for example:

    // FUNCTION: Read File and return Array
    function readFile(fileToRead){
    var fileLineArr = [];
    fileToRead.open("r");
    while (!fileToRead.eof){
    fileLineArr.push(fileToRead.readln().toString());
    }
    fileToRead.close();
    return fileLineArr;
    }
    var aeKeyArray = readFile(aeKeyFile);

    We also need a primary script file that will execute all our other scripts. Let’s say it’s called “00 Primary Script.jsx” and it’s already living in AE’s “Scripts” folder. Now we have to know what its index is within AE’s menu in order to apply shortcuts to it. We can find out the index by calling “app.findMenuCommandId()” and we have to limit it to the third and fourth number in the ID (the other numbers aren’t important to us), so like this:

    var primeScriptID = app.findMenuCommandId("00 Primary Script.jsx");
    var primeScriptIDTrim = primeScriptID.toString().substring(2, 4);

    All script menu items are noted in AE’s shortcut file like this: “ExecuteScriptMenuItem01”, all the way up to “ExecuteScriptMenuItem20”. So the correct name within the shortcut file has to look like this:

    var primeMenuName = "ExecuteScriptMenuItem" + primeScriptIDTrim;

    Now iterate through our aeKeyArray until you find section [“CEggApp”] where all script shortcuts are stored. If our “ExecuteScriptMenuItemXX” already exists, you will have to add our shortcuts to it, otherwise, you will have to create a new line within the section. The formatting will look like this:

    	"ExecuteScriptMenuItem01" = "(Ctrl+Alt+X)(Ctrl+Alt+F1)(Ctrl+Alt+F2)"

    So you will have to save your shortcuts exactly like this into our aeKeyArray. (Unfortunately, the way I did this is kind of scattered around my script and would take too long to collect. I hope you can figure it out yourself.)

    After our line has been added to the aeKeyArray, we will have to save it back to AE’s shortcut file:

    // FUNCTION: Write a String to a File
    function writeStringToFile(toFile, thisString){
    toFile.open("w");
    toFile.write(thisString);
    toFile.close();
    }
    writeStringToFile(aeKeyFile, aeKeyArray.join("\n"));

    Please note that you will have to either restart AE or open up AE’s shortcut panel where the user will have to hit “OK” in order for the new shortcut file to be loaded into AE.

    Woah, ok, now have all we need and we can start combining everything in our “00 Primary Script.jsx”. In there, first read all current keyboard states.

    var pressedShortcut = ScriptUI.environment.keyboardState.keyName;
    var pressedShift = ScriptUI.environment.keyboardState.shiftKey;
    var pressedAlt = ScriptUI.environment.keyboardState.altKey;
    var pressedCtrl = ScriptUI.environment.keyboardState.ctrlKey;

    Then build the shortcut name from those states:

    var shortcutName = "";
    if (pressedShift) { shortcutName = "Shift+" + shortcutName; }
    if (pressedAlt) { shortcutName = "Alt+" + shortcutName; }
    if (pressedCtrl) { shortcutName = "Ctrl+" + shortcutName; }

    There are some conversions that need to happen for the pressedShortcut because AE’s shortcut file uses other names for certain keys than the ScriptUI.environment.keyboardState.keyName variables returns, so we do this (the function should have been written with switch/case but the code is so old and I didn’t know about it back then ;)):

    // FUNCTION: Convert Key to Save Key (espacially convert Special Caracters)
    function convertKeyToSaveKey(existShortcut, nameToConvert){
    if (nameToConvert == "Enter"){ // Convert "Enter" to "Return"
    existShortcut = existShortcut + "Return";
    } else if (nameToConvert == "Delete"){ // Convert "Delete" to "FwdDel"
    existShortcut = existShortcut + "FwdDel";
    } else if (nameToConvert == "Period"){ // Convert "Period" to "."
    existShortcut = existShortcut + ".";
    } else if (nameToConvert == "Minus"){ // Convert "Minus" to "-"
    existShortcut = existShortcut + "-";
    } else if (nameToConvert == "Multiply"){ // Convert "Multiply" to "PadMultiply"
    existShortcut = existShortcut + "PadMultiply";
    } else if (nameToConvert == "Divide"){ // Convert "Divide" to "PadSlash"
    existShortcut = existShortcut + "PadSlash";
    } else if (nameToConvert == "Home"){ // Convert "Home" to "HOME"
    existShortcut = existShortcut + "HOME";
    } else if (nameToConvert == "End"){ // Convert "End" to "END"
    existShortcut = existShortcut + "END";
    } else if (nameToConvert == "PageUp"){ // Convert "PageUp" to "PageUP"
    existShortcut = existShortcut + "PageUP";
    } else if (nameToConvert == "PageDown"){ // Convert "PageDown" to "PageDOWN"
    existShortcut = existShortcut + "PageDOWN";
    } else if (thisOS == "Mac" && nameToConvert == "Backspace"){ // Convert "Backspace" to "Delete" (on Mac only)
    existShortcut = existShortcut + "Delete";
    } else {
    existShortcut = existShortcut + nameToConvert;
    }
    return existShortcut;
    }
    shortcutName = convertKeyToSaveKey(shortcutName, pressedShortcut);

    Alright, we have the exact name of the shortcut that called the “00 Primary Script.jsx” and now we will have to match this shortcut to the script file that we have saved into our text file. (This again is way too scattered around my script so I can’t collect it easily now. But I think if you made it that far, it should be quite straightforward.) If we have the script file that is supposed to be executed, the only thing we have to do now is run the script, for example with $.evalFile().

    Does this make sense? I’m sorry I skipped some stuff but I hope it’s still of some use to you… If there’s something you didn’t get, you can just ask. 🙂

  • Ralph Moreau

    June 1, 2022 at 1:43 pm

    I’m going to take your diligent notes, and make something. Will report back. Thank you, thank you!

We use anonymous cookies to give you the best experience we can.
Our Privacy policy | GDPR Policy