No internet connection
  1. Home
  2. How to

Double click and modifiers on SD

By Diego Gat @Diego_Gat
    2020-03-18 19:05:02.242Z

    Hi there!
    I wonder if there's a way to make Stream Deck keys trigger a different script if I double click on them.
    Also, if one of the Stream Deck is conigured as an option or shift key, all other keys can have a second function. Maybe, while holding down the "shift" key, all SD buttons that support a second funciton can change to reflect that (I mean their screens), and back to normal when "shift" is released.
    It would be helpful and fast to operate, avoiding the use of nested decks and a "back" button.

    Solved in post #16, click to view
    • 22 replies

    There are 22 replies. Estimated reading time: 14 minutes

    1. We don't have built in support for designing decks differently based on modifier keys, but you can control it more manually from scripts.

      This thread provides some details:
      https://forum.soundflow.org/-1173/how-to-change-decks-on-stream-deck-based-on-modifier-keys-held

      The code in that thread will change the entire Deck based on what modifier keys you're holding down - and also which app is active. So it would be a custom replacement for Application Triggers more or less.

      I know that @JesperA is also doing stuff with double clicks.

      In other words - yes it's possible to do what you have envisioned, but it's not yet as "native" to do as just designing it in our Deck designer.

      1. In reply toDiego_Gat:

        Hey Diego.

        About modifier keys. Correct me if I'm wrong @chrscheuer but we can't read if a streamdeck key is pressed down or when it's release currently, so you can't use it as a modifier key. Would be a neat thing to have at some point for sure though.
        But you can use your regular keyboard in combination with the streamdeck. This is very powerfull. The commands need to be script based and not Macros. To implement that have this code

        var modifiers = event.keyboardState.asString;
        
        if (modifiers.match('cmd')){
              // the functions you want to happen if cmd is pressed down at all, also if cmd and shift is pressed.
        }
        else if (modifier == 'shift'){
              // the functions you want to happen if only shift is pressed down
        }
        else {
              // what the script will execute in all other cases. 
        }
        

        You will have to specify more precisely if you wanna use multiple modifier keys. You can read what the modifier string is like by putting this in a script and run it while holding down some modifiers:

        var modifiers = event.keyboardState.asString;
        log(modifiers)
        

        About double clicks
        So it's possible fairly easy to implement double clicks for a streamdeck if your command is a scripts. Use this code:

        var now = Date.now() - 0;
        if (now - globalState.lastTime < 1000) {
            log('doubleClick')
            throw 0;
        }
        globalState.lastTime = now;
        

        This will do the action if you double click within 1 second (1000ms).
        If there's an action for single click, and you have that before this small snippet of code it will do the first action twice. If you have it after this code, it will only do it once.
        A way to get around that would be:

        var now = Date.now() - 0;
        var doubleClickSpeed = 1000
        globalState.ifDoubleClick = false
        
        if (now - globalState.lastTime < doubleClickSpeed) {
            globalState.ifDoubleClick = true
            log('doubleClick')
            throw 0;
        } else {
            globalState.lastTime = now;
            sf.wait({ intervalMs: doubleClickSpeed, executionMode: 'Background' })
            if (!globalState.ifDoubleClick)
                log('singleClick')
        }
        

        Cool thing is this could even be applied to regular key strokes or other inputs.
        One thing to note is about the globalState especially the lastTime I have above. If the same globalState is used in multiple scripts, for instance two different commands on two different streamdeck keys, and you press the two different SD keys within 1000ms, the second one will run the double click. So you could consider making specific globalState names for different script for the lastTime globalState.

        Best

        1. Oh I see - I thought Diego wanted the normal modifier keys on the keyboard to be the modifiers..

          1. Not sure, I'm just reading between the lines a bit, as I've had that idea myself of being able to combine streamdeck keys :)

            1. Diego Gat @Diego_Gat
                2020-03-19 05:50:41.435Z

                Thank you guys for your responses. I’ll play with the code as soon as I have some more time off, which might be unfortunately pretty soon.

                My idea was that the modifier key was one of the SD keys, since I might not be close to the computer keyboard while mixing.

                But, would it work to program a certain SD key to do something, and something else with shift down... and have another SD key emulate a keyboard shift down?

                Thanks again!

                1. Jesper Ankarfeldt @JesperA2020-03-19 05:58:59.932Z2020-03-19 08:43:27.815Z

                  Yes, you could just have 1 SD key set a globalState (which can work across multiple scripts) as an shift down /shift up type of thing.
                  So you would have a script for the "modifier" SD key with this code:

                  if (globalState.setAlternativeKeys === undefined) globalState.setAlternativeKeys = false // this sets the globalState if it hasn't been used before
                  
                  globalState.setAlternativeKeys = !globalState.setAlternativeKeys // this set the globalState to the oppersite of before 
                  log('Is alternative keys active:', globalState.setAlternativeKeys) // this just logs the state so you can see what's going on.
                  

                  And then you would have on your scripts for your other SD keys with functions:

                  if (globalState.setAlternativeKeys){
                        // what the script will execute if you've set the "modulation" SD key to be true. 
                  }
                  else 
                        // what the script will execute if you haven't pressed it or if you've set it to be false.
                  }
                  
                  1. Jesper's solution is probably the simplest way to get something like you wish for. Just be aware that the modifiers will be "sticky" because we right now don't have support for Key Up/Down messages being interpreted independently.

                    1. Diego Gat @Diego_Gat
                        2020-03-19 14:49:46.384Z

                        So, will it have to be pressed again to toggle it out of “shift” mode? Is this what “sticky” means?
                        How about an automatic 500ms timeout? Or... all SD keys turn the shift state to false. This way we’ll reset the shift state every time.

                        Forgive me if what I say doesn’t make a lot of sense, I’m more brainstorming than providing actual solutions at his point. I’ll learn one day.

                        Thanks again!

                        1. So, will it have to be pressed again to toggle it out of “shift” mode? Is this what “sticky” means?

                          Yes exactly - that's what I meant.

                          all SD keys turn the shift state to false. This way we’ll reset the shift state every time.

                          This would be the easiest thing to implement. It would mimic how the Shift key works on iPhones for example.

              • In reply toJesperA:
                Diego Gat @Diego_Gat
                  2020-03-20 18:38:29.306Z

                  I can't seem to malke this last script work. It's giving me single clicks every time. Tried both with SD and Xkeys, same result. Am I missing something?
                  Thanks!

                  1. In reply toJesperA:
                    Diego Gat @Diego_Gat
                      2020-03-20 23:26:03.160Z2020-03-20 23:27:28.259Z

                      For example:
                      I'm trying to consolidate some commands. If single click, select between markers. If double click, select between markers and zoom to selection.

                      I'm trying this: (also how do I paste code that looks like code??)

                      var now = Date.now() - 0;
                      var doubleClickSpeed = 1000
                      globalState.ifDoubleClick = false
                      
                      if (now - globalState.lastTime < doubleClickSpeed) {
                          globalState.ifDoubleClick = true
                          log('doubleClick')
                          sf.ui.proTools.memoryLocationsGotoDelta({
                              delta: -1,
                          });
                      // something that allows me to zoom to selection, like opt+F
                          });
                          throw 0;
                      } else {
                          globalState.lastTime = now;
                          sf.wait({ intervalMs: doubleClickSpeed, executionMode: 'Background' })
                          if (!globalState.ifDoubleClick)
                              log('singleClick')
                          sf.ui.proTools.memoryLocationsGotoDelta({
                              delta: -1,
                          });
                      }
                      

                      With no success. Can you help me see what' I'm doing wrong?
                      Thanks!

                      1. To format code, insert an otherwise empty line with 3 backticks before and after your code - like this: ```. I'll edit your post to reflect this - to see how it's done, you can edit yours.

                        1. Diego Gat @Diego_Gat
                            2020-03-20 23:29:09.193Z

                            thanks Chris! Please be patient, I'm learning!

                            1. Haha :) You're doing great!! Very fast :)

                              1. Try this - it works a little more stable for me:
                                Your code to do stuff based on single or double clicks goes to the first two functions.

                                
                                function onSingleClick() {
                                    log('single click');
                                }
                                
                                function onDoubleClick() {
                                    log('double click');
                                }
                                
                                function singleOrDoubleClick({
                                    onSingleClick,
                                    onDoubleClick,
                                    doubleClickSpeed = 500
                                }) {
                                    var name = event.trigger.commandId.replace(/:/, '_');
                                    var prefix = '_singleOrDoubleClick_' + name;
                                    var now = Date.now() - 0;
                                    globalState[prefix + '_isDoubleClick'] = false;
                                
                                    if (now - globalState[prefix + '_lastTime'] < doubleClickSpeed) {
                                        globalState[prefix + '_isDoubleClick'] = true;
                                        onDoubleClick();
                                    } else {
                                        globalState[prefix + '_lastTime'] = now;
                                        var isSingleClick = false;
                                        sf.engine.runInBackground(() => {
                                            sf.wait({ intervalMs: doubleClickSpeed, executionMode: 'Background' });
                                            isSingleClick = !globalState[prefix + '_isDoubleClick'];
                                        });
                                        if (isSingleClick)
                                            onSingleClick();
                                    }
                                }
                                
                                singleOrDoubleClick({
                                    onSingleClick,
                                    onDoubleClick,
                                });
                                
                                Reply3 LikesSolution
                                1. Diego Gat @Diego_Gat
                                    2020-03-20 23:51:44.692Z

                                    Awesome Chris! The single/double click part works perfect!

                                    1. In reply tochrscheuer:

                                      Nice script. A bit more thorough then mine :P
                                      Makes so much sense that it's an if else function. Also to create a globalState based on the command ID makes so much sense.
                                      Will update my own script with this script too.

                                      1. In reply tochrscheuer:
                                        NNevio Siragusa @Nevio_Siragusa
                                          2023-11-08 08:40:04.836Z

                                          Hi! I know I'm a bit late to the conversation, but I found this on Google and really want to know.

                                          I'm pretty new to this - how (and where) exactly do I need to apply/"install" this script to be able to assign two different funtions, depending if i single- or doubleclick, to a StreamDeck button?

                                          Thanks for your help! 😁

                                          1. Hi. First you need to use SoundFlow (and not the streamdeck app).
                                            Are you doing this?

                                            If not, you should go to the soundflow main page to read about it.

                                            If you are using soundflow, you just need to create a script.

                                            1. NNevio Siragusa @Nevio_Siragusa
                                                2023-11-08 09:09:15.611Z

                                                I was searching in the streamdeck app. 😆😆
                                                Is there a way to run soundflow on windows? From what I can see there is no official way to do it 🫤

                                                1. Yes that was what I kinda read between the lines from your first message 😄

                                                  Unfortunately no windows version at this current moment.

                                                  1. NNevio Siragusa @Nevio_Siragusa
                                                      2023-11-08 09:24:53.747Z

                                                      Haha, I told you that I'm a beginner 😁

                                                      Aw, that's a pity, I was so hyped to have found a solution.
                                                      Thanks for your help though, I really appreciate it!