Home > Community > Forums > Custom IC SKILL > How to create two or three key strokes bindkeys

Email

* Required Fields

Recipients email * (separate multiple addresses with commas)

Your name *

Your email *

Message *

Contact Us

* Required Fields
First Name *

Last Name *

Email *

Company / Institution *

Comments: *

 How to create two or three key strokes bindkeys 

Last post Thu, May 15 2014 10:52 AM by theopaone. 8 replies.
Started by SlimAnt 21 Oct 2009 09:37 AM. Topic has 8 replies and 2462 views
Page 1 of 1 (9 items)
Sort Posts:
  • Wed, Oct 21 2009 9:37 AM

    • SlimAnt
    • Not Ranked
    • Joined on Thu, Oct 15 2009
    • Posts 10
    • Points 200
    How to create two or three key strokes bindkeys Reply

    Hello,

    How can I create two or three key strokes bindkeys without changing the existing bindkeys?

    For example, addition of existing bindkeys such as: m -> to activate move

    I would like to create new bindkeys such as: jmp -> SKILL code to jump to a certain coordinate


    I tried using the following function getc to read the next character from keyboard and it doesn't work.

       procedure( call_2()

            TT = getc()

                    if( TT = "p" then

                         ; function to jump

                    )

         )


       procedure( call_1()

              TT = getc()

                     if( TT = "m" then

                            call_2()

                     )

          )


    hiSetBindKey("Layout" "none<Key>j" "call_1()")


    I am using version IC6.1.3

    I Appreciate any help that I can get.

    • Post Points: 20
  • Thu, Oct 22 2009 5:57 AM

    Re: How to create two or three key strokes bindkeys Reply

    I had originally planned to describe an outline of a way to do this - but realised that as I started writing the outline, I wasn't that far off having the code itself. So I put together the code below which is a way to implement what I've called "sequence" bindkeys.

    Rather than having to code each specific combination (as in the code in the original post) you register a SKILL action against particular sequences. 

    Anyway, the comments at the top of the code should explain things clearly enough.

    /* abSeqBindKey.ils
    
    Author     A.D.Beckett
    Group      Custom IC (UK), Cadence Design Systems Ltd.
    Language   SKILL++ (keep the .ils suffix on this file)
    Date       Oct 22, 2009 
    Modified   
    By         
    
    A package to support sequence bindkeys. This means you can define multi-key
    bindkeys. So for example, you can define a bindkey "chop" - you type the four
    characters c, h, o, and then p - and this then triggers the bindkey.
    The sequence is displayed as a banner label so you can see the current 
    sequence. Escape is normally used to reset the sequence.
    
    Note this is really a proof-of-concept - it is not fully formed, and may
    need some enhancement.
    
    ; Initialize the a-z, A-Z, and 0-9 bindkeys to be entry keys
    ; and escape to be a reset key for Layout application
    abSeqBindKey->initBindKeys("Layout")
    
    ; give warning if any key sequence defined which obscures another
    ; for example, "ed" obscures "edit"
    abSeqBindKey->option(?checkObscured t)
    
    ; Define some key sequences
    abSeqBindKey->set("Layout" "fit" "hiZoomAbsoluteScale(hiGetCurrentWindow() 0.9)")
    abSeqBindKey->set("Layout" 
      '(
        ("copy" "leHiCopy()")
        ("chop" "leHiChop()")
        ("del"  "leHiDelete()")
        ("undo" "hiUndo()")
       )
    )
    
    ; Retrieve bindkeys:
    abSeqBindKey->get("Layout") => returns all the keys
    abSeqBindKey->get("Layout" "chop") => "leHiChop()"
    
    ; If you want to define your own bindkeys (rather than using initBindKeys)
    ; then you'll need to use these:
    abSeqBindKey->enter("X") ; enters an X in the sequence
    abSeqBindKey->reset()    ; resets the sequence
    
    Limitations:
    
    Doesn't have the concept of "Enter Function" bindkeys which are
    different during enter functions. Could do, but needs some thought
    as to a sensible use model.
    
    ***************************************************
    
    SCCS Info: @(#) abSeqBindKey.ils 10/22/09.13:44:45 1.1
    
    */
    
    importSkillVar(abSeqBindKey)
    abSeqBindKey=let(
        ((bindkeys makeTable('bindkeys nil)) obscuredCheck)
    
        /*****************************************************************
        *                                                                *
        *                     initBindKeys(appType)                      *
        *                                                                *
        * EXPORTED function to initialize the bindkeys a-z, A-Z and 0-9, *
        *  as well as Escape, to work with the sequence bindkey system.  *
        *                                                                *
        *****************************************************************/
        defun(initBindKeys (appType)
    	let((appRoot)
    	    appRoot=hiGetBindKeyInheritRoot(appType)
    	    when(appRoot
    		;--------------------------------------------------------
    		; Define bindkeys for a-z, A-Z and 0-9
    		;--------------------------------------------------------
    		for(ascii charToInt('a) charToInt('z)
    		    hiSetBindKey(appRoot
    			strcat("" intToChar(ascii))
    			sprintf(nil "abSeqBindKey->enter(\"%s\")" 
    			    intToChar(ascii))
    		    )
    		    hiSetBindKey(appRoot
    			strcat("Shift" intToChar(ascii))
    			sprintf(nil "abSeqBindKey->enter(\"%s\")" 
    			    upperCase(intToChar(ascii)))
    		    )
    		) ; for
    		for(ascii charToInt('\0) charToInt('\9)
    		    hiSetBindKey(appRoot
    			strcat("" intToChar(ascii))
    			sprintf(nil "abSeqBindKey->enter(\"%s\")" 
    			    intToChar(ascii))
    		    )
    		) ; for
    		hiSetBindKey(appRoot "Escape" "abSeqBindKey->reset()")
    	    ) ; when appRoot
    	) ; let
        ) ; defun initBindKeys
    
        /************************************************************************
        *                                                                       *
        *                              enter(char)                              *
        *                                                                       *
        *   EXPORTED Function to enter a character in the sequence. If there    *
        *     is a sequence bindkey registered for that sequence, reset and     *
        *       then execute the bindkey definition - otherwise continue        *
        * collecting the characters in the sequence (and display in the banner) *
        *                                                                       *
        ************************************************************************/
        defun(enter (char)
    	let((win appType appRoot bindkeyTab defn sequence)
    	    win=hiGetCurrentWindow()
    	    when(win
    		sequence=strcat(win~>abSequence || "" char)
    		win~>abSequence=sequence
    	    )
    	    appType=win && hiGetAppType(win)
    	    when(appType
    		appRoot=hiGetBindKeyInheritRoot(appType)
    	    )
    	    when(appRoot
    		;--------------------------------------------------------
    		; Look up the bindkey definition. If found, then
    		; reset the sequence and evaluate it, otherwise just
    		; append the current sequence.
    		;--------------------------------------------------------
    		bindkeyTab=bindkeys[appRoot]
    		defn=bindkeyTab && bindkeyTab[sequence]
    		if(stringp(defn) then
    		    reset()
    		    errsetstring(defn t)
    		else
    		    hiChangeBannerLabel(
    			hiGetCurrentWindow()
    			strcat("Seq: " sequence)
    			0
    		    )
    		) ; if bindkey found
    	    ) ; when appRoot
    	) ; let
        ) ; defun enter
    
        /***************************************************************
        *                                                              *
        *                           reset()                            *
        *                                                              *
        *       EXPORTED function to reset the current sequence        *
        *                                                              *
        ***************************************************************/
        defun(reset ()
    	hiGetCurrentWindow()~>abSequence=""
    	hiChangeBannerLabel(
    	    hiGetCurrentWindow()
    	    "Seq: "
    	    0
    	)
        ) ; defun reset
    
        /***************************************************************
        *                                                              *
        *                    check(bindkeyTab key)                     *
        *                                                              *
        *  INTERNAL function to check that a new key sequence is not   *
        *    obscured by another, or does not obscure another. Only    *
        *      checked if option(?checkObscured t) has been used.      *
        *                                                              *
        ***************************************************************/
        defun(check (bindkeyTab key)
    	let((len subKeyName)
    	    when(obscuredCheck && stringp(bindkeyTab[key])
    		len=strlen(key)
    		;--------------------------------------------------------
    		; Look for any existing key sequences which the new key is
    		; the beginning part of
    		;--------------------------------------------------------
    		foreach(keyName bindkeyTab
    		    when(key!=keyName && zerop(strncmp(key keyName len)) &&
    			stringp(bindkeyTab[keyName])
    			warn("Definition for sequence %s will obscure sequence %s\n"
    			    key keyName)
    		    ) ; when
    		) ; foreach
    		;--------------------------------------------------------
    		; Look for any key sequences which are shorter than the new key
    		;--------------------------------------------------------
    		for(sub 1 sub1(len)
    		    subKeyName=substring(key 1 sub)
    		    when(stringp(bindkeyTab[subKeyName])
    			warn("Definition for sequence %s will obscure sequence %s\n"
    			    subKeyName key)
    		    ) ; when
    		) ; for
    	    )
    	) ;let
        ) ; defun
    
        /***************************************************************
        *                                                              *
        *                   set(appType key [defn])                    *
        *                                                              *
        *  EXPORTED function to set one or more sequence bindkeys for  *
        *                        an application                        *
        *                                                              *
        ***************************************************************/
        defun(set (appType key @optional defn "tg")
    	let((appRoot bindkeyTab)
    	    appRoot=hiGetBindKeyInheritRoot(appType)
    	    when(appRoot
    		bindkeyTab=bindkeys[appRoot]
    		unless(bindkeyTab
    		    bindkeyTab=makeTable('appBindkeys nil)
    		    bindkeys[appRoot]=bindkeyTab
    		)
    		;--------------------------------------------------------
    		; Handle list of definitions, and individual definitions
    		;--------------------------------------------------------
    		if(listp(key) then
    		    foreach(keyDefn key
    			if(listp(keyDefn) && length(keyDefn==2) then
    			    bindkeyTab[car(keyDefn)]=cadr(keyDefn)
    			    check(bindkeyTab car(keyDefn))
    			else
    			    warn("Key definition %L is invalid\n" keyDefn)
    			)
    		    )
    		else
    		    bindkeyTab[key]=defn
    		    check(bindkeyTab key)
    		)
    		t
    	    ) ; when appRoot
    	) ; let
        ) ; defun set
    
        /*******************************************************************
        *                                                                  *
        *                        get(appType [key])                        *
        *                                                                  *
        * EXPORTED function to get one or all sequence bindkey definitions *
        *                                                                  *
        *******************************************************************/
        defun(get (appType @optional key "tg")
    	let((appRoot bindkeyTab)
    	    appRoot=hiGetBindKeyInheritRoot(appType)
    	    when(appType 
    		bindkeyTab=bindkeys[appRoot]
    		;--------------------------------------------------------
    		; If the key argument provided, just return the definition
    		; otherwise return an assoc list of the whole lot
    		;--------------------------------------------------------
    		if(key then
    		    bindkeyTab && bindkeyTab[key]
    		else
    		    tableToList(bindkeyTab)
    		)
    	    ) ; when appType
    	) ; let
        ) ; defun get
    
        /***************************************************************
        *                                                              *
        *                  option(@key checkObscured)                  *
        *                                                              *
        *       EXPORTED function to set any options. Currently        *
        *                     just ?checkObscured.                     *
        *                                                              *
        ***************************************************************/
        defun(option (@key checkObscured)
    	obscuredCheck=checkObscured
        )
    
        ;--------------------------------------------------------------------
        ; DPL containing all the package functions available from outside
        ;--------------------------------------------------------------------
        `(nil
    	initBindKeys ,initBindKeys
    	enter ,enter
    	reset ,reset
    	set ,set
    	get ,get
    	option ,option
        )
    ) ; let
    
    

    Regards,

    Andrew.

     

    • Post Points: 35
  • Thu, Oct 22 2009 8:28 AM

    • SlimAnt
    • Not Ranked
    • Joined on Thu, Oct 15 2009
    • Posts 10
    • Points 200
    Re: How to create two or three key strokes bindkeys Reply

     Hi Andrew,

    Thank you very much for your solution.
    Wow, It is not as simple as I thought.

    I am a new comer to this programming; thus, I will find time to digest these complicated codes.

    Thanks again,
    SlimAnt

    • Post Points: 20
  • Thu, Oct 22 2009 10:24 AM

    Re: How to create two or three key strokes bindkeys Reply

    Hi SlimAnt,

    The code is not actually that complicated (a lot of it is comments); what I did however was to come up with a generic solution which allows registration of the bindkeys, rather than hard coding a specific solution (which is what your trial code was doing). I think you'll find that after you've defined a few bindkey combinations, the code I provided is much simpler than it would have been if you'd coded some complex "state machine" type representation.

    Regards,

    Andrew.

    • Post Points: 20
  • Thu, Oct 22 2009 4:14 PM

    • SlimAnt
    • Not Ranked
    • Joined on Thu, Oct 15 2009
    • Posts 10
    • Points 200
    Re: How to create two or three key strokes bindkeys Reply

    Hi Andrew,

    Thank you for your follow up which was encouraging.

    I have read it and now understand on how to use. This is much better than what I had in mind.

    I am so happy for this. Just as happy as a kid getting a new toy.
    Thanks again,
    SlimAnt

    • Post Points: 20
  • Thu, Oct 22 2009 6:20 PM

    • kbhow
    • Top 75 Contributor
    • Joined on Thu, May 7 2009
    • Penang, Pulau Pinang
    • Posts 120
    • Points 2,045
    Re: How to create two or three key strokes bindkeys Reply

    Hi Andrew,

    Nice coding. =D

    You are great Sifu (Guru).

    How

    • Post Points: 5
  • Wed, May 7 2014 9:14 AM

    • Mwcaboose
    • Not Ranked
    • Joined on Tue, Oct 8 2013
    • Posts 5
    • Points 100
    Re: How to create two or three key strokes bindkeys Reply

     Can this be made to work with Shift/Ctl/Alt as well?

    • Post Points: 20
  • Fri, May 9 2014 11:03 AM

    Re: How to create two or three key strokes bindkeys Reply

    In principle, yes. You'd have to change initBindKeys to add bindings for modified keys - and this would need to call the ->enter function with some sequence to identify that unambiguously. Currently the ->enter gets called with a single character, e.g. "a", "B", "0" - but there's no reason why it couldn't be something else - e.g. "^D" to represent control-D - and then you enter that in your sequence definitions.

    Whether it's really what you want, I'm not sure - this is a bit of an all or nothing solution.

    Note, I didn't try changing it as described above - but from a quick glance back through the code (and I did write it getting on for 5 years ago), I think that should be possible.

    Regards,

    Andrew.

    • Post Points: 20
  • Thu, May 15 2014 10:52 AM

    • theopaone
    • Top 75 Contributor
    • Joined on Tue, Feb 12 2013
    • Cedar Park, TX
    • Posts 85
    • Points 1,230
    Re: How to create two or three key strokes bindkeys Reply

    Hi  Andrew,

    This is great code.  It takes me back to GDS-1 (1970's) where every command was a two or three key sequence. You could get pretty good with a single hand on the keyboard and another with the pen (no on-screen menus).

    I'm going to use this to add special functionality with multiple key sequences, like emacs.

     Ted

     

    • Post Points: 5
Page 1 of 1 (9 items)
Sort Posts:
Started by SlimAnt at 21 Oct 2009 09:37 AM. Topic has 8 replies.