action.shortcut doesn't implement at application startup

Hi Matthias,

I have one .lym file that executes during application startup. That lym file loads a bunch of .rb files that make up all the modules I had developed over the years. The structure of these is always the same: it contains it's own class that sets up a toolsmenu item as well as a toolbar icon which have actions that do all sorts of things. Everything always sets up correctly, but I noticed a peculiarity. I define action.shortcut for a bunch of these, but they don't seem to take when the application starts up (meaning it doesn't trigger the action, and the shortcuts are not written in the menu items, and they are not listed in setup>application>customize menu). If I execute the .lym file again after startup, everything takes, and actions can be triggered with the right shortcuts. Barring that I am doing something non-sensical (class instantiation etc.), is this an expected behavior or do I need to do something else beyond action.shortcut="..." ?
I circumvented the problem for now by physically adding the shortcut to key-bindings, but I suppose that is overkill of some kind ? I call addShortCut() at the end of the menu setup.



    def addShortCut()       
                    config_names               = RBA::Application.instance.get_config_names
                    config_keybindings_str     = RBA::Application.instance.get_config('key-bindings')
                    config_keybindings         = config_keybindings_str.split(';')
                    found_CTRL_SHIFT_H         = false
                    new_config_keybindings_str = ""
                    config_keybindings.each do |keybinding|
                            keybinding_pair = keybinding.split(':')
                            #puts "#{keybinding_pair[0]} - #{keybinding_pair[1].empty?}"
                            thisName = keybinding_pair[0]
                            thisVal  = keybinding_pair[1]
                            isCTRL_SHIFT_H = false
                            if !thisName.gsub("'","").empty?  and  !thisVal.gsub("'","").empty? 
                                    if thisName =~ /.*tools_menu\.highlighter.*/
                                            if thisVal =~ /.*Ctrl\+Shift\+H.*/
                                                  found_CTRL_SHIFT_H = true  
                                                  isCTRL_SHIFT_H = true
                                                  puts "FOUND: #{thisName} - #{thisVal}"
                                    if !isCTRL_SHIFT_H
                                            new_config_keybindings_str += thisName + ":" + thisVal + ";"
                    puts "inspection done"
                    if new_config_keybindings_str.end_with?(";")
                            new_config_keybindings_str +=  "'tools_menu.highlighter':'Ctrl+Shift+H'";
                            new_config_keybindings_str += ";'tools_menu.highlighter':'Ctrl+Shift+H'";
                    RBA::Application.instance.set_config('key-bindings', new_config_keybindings_str)
                    puts "ADDED CTLR-SHIFT-H"


  • Hi Thomas,

    I'm trying the comprehend what's going on. So I understand that you have one top-level .lym file which then loads other modules, i.e. "require", right?

    So how did you make these other files specify a shortcut? Plain .rb files can do so by adding a special comment, but this is only evaluated under certain circumstances. When Ruby loads the file through "require", it does not read these comments and not shortcuts are registered. KLayout will itself scan all "*.rb" files in it's reach (meaning: within "/ruby", "/salt/xyz/ruby" and "/tech/xyz/ruby"). I'm not sure what happens if a file is found twice by Ruby's "require" and by KLayout's scanning. And if there is a conflict, the scan order is important as well.

    You can debug the scanning sequence by using "klayout -d 31". If you see a file being loaded there you should also see the corresponding shortcuts and menu entries.

    In general, I think your top level approach is actually helpful to avoid this kind of confusion. I don't consider this overkill - KLayout's heuristic isn't made for big environments but rather quick integration of small scripts. I'd even try to "hide" all files which are not top-level entry points by putting them into a folder KLayout does not scan (e.g. "rblib" parallel to "ruby"). By using "require_relative" (which I praise the Ruby people for) you can access these files from your top level .lym. So ideally you have a single .lym and do everything from there. This is also a helpful strategy if you want to put everthing into a package later: it helps you to reduce cross-interactions with other packages.

    Best regards,


  • Hi Matthias,

    I use a series of load root + "/.rb" commands to execute the ruby code at the time the lym file runs. If I comment these out, then the rb files are not automatically loaded by KLayout scanning, even though they are in /salt/xyz/macro//. ( Maybe this happens because I dont have the files in a ruby subir ?).

    I like this approach because I can turn these off one by one for troubleshooting. In each file, I have a new class def, and an appropriate invocation for that class. Each executed from the macro env on it's own runs fine and does everything as expected.

    My confusion here is that when the app starts, all rb files seem to be correctly executed because I see my new tools_menu entries, and there are also my toolbar items I defined - with icons and all. The only thing that is missing is the keyboard shortcut - even though it is defined in action via action.shortcut='' in each class in the rb files. The actions still work because I can trigger them via the menu or toolbar. The keyboard shortcut becomes active when I run the lym file again from your macro environment. They are then even listed as text in the tools_menu items I had added.

    Is the KLayout startup sequence maybe such that at the end of all pre-loading (lym + rb) the saved keyboard shortcuts are imported ? Maybe that overwrites what I defined in action.shortcut ? On the other hand, that method addShortCut() above runs right after the action is added to the menu items, and after these new menu items are added to the menu, and that works. Confusing ...

    I ran klayout_app.exe -d 31 but it didn't do anything different...


  • Hi Thomas,

    thanks for trying.

    I assume there is no auto-loading involved. So it's about the execution of Action instantiations.

    How exactly do you run the top-level .lym? Is that autorun oder autorun-early? And maybe you can give a short example how you create the menu actions.



  • HI Matthias,
    to answer your question: the lym file is set to run on startup, but not on early. I was afraid that I'd me messing up things by trying to add items to toolsbar and tools_menu if the main window is not up yet.

    I hunted it down some more though, spent almost the entire day trying to figure this out.

    (1) I uninstalled KLayout
    (2) I reinstalled KLayout
    (3) I copied over only one simple rb file and the loader lym file that loads it. (attached)

    The result is always the same:

    (1) if I use action.shortcut='Ctrl+Shift+H' and not keybindings RBA::Application.instance.set_config('key-bindings', new_config_keybindings_str), then the application starts and reacts to the shortcut. However, when I open the setup GUI, I see that tools_menu.chighlighter has no shortut. If I cancel out, everythign is fine. As soon as I hit ok, the action doesnt react to the shortcut.
    (2) if I use keybindings RBA::Application.instance.set_config('key-bindings', new_config_keybindings_str), but not action.shortcut='Ctrl+Shift+H', then the same thing happens.

    Does the klayouttrc need these in a specific order ? I cannot get this to remain active past OK on the setup GUI ... Can you help ?



  • I think I got it figured out. Blindly adding a keybinding string :'' to the string that is used in RBA::Application.instance.set_config was probably not quite right. I have to use menu.insert_item to auto-insert it into the config string properly, but only internally at that point of runtime. Then, the application, has to exit to write to klayoutrc. After that, it is available in RBA::Application.instance.get_config('key-bindings'). The trick is to then search for the key by name and only replace the value, but never to just add a key:value pair.
    On top of that, if the addShortCut routine determines that the key does not yet exist in key-bindings for some reason, I can add a shortcut to the action programmatically - so that I don't have the same shortcut in key-bindings as attached to some action. (at some point I was worried that it would be a conflict if it exists more than once)

  • Hi Thomas,

    thanks a lot for letting me know and sorry for being somewhat unresponsive. I'm trying to finish the next major release.

    You're right about the key/value problem. Maybe there should be a function to manipulate the key-bindings rather than setting the configuration string. I'll think about this.



Sign In or Register to comment.