AutoHotkey Community

It is currently May 27th, 2012, 6:45 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 12 posts ] 
Author Message
PostPosted: August 14th, 2011, 12:32 pm 
Offline

Joined: August 14th, 2011, 2:55 am
Posts: 7
Hi Everyone,

I have some difficulties in firing a Hotkey by pressing two or more arbitrary modifiers and would like to enlist your help.

I successfully turned the CapsLock and the LWin into arbitrary modifiers. For instances, when I press the CapsLock and "j", AHK fires "Ctrl-Left"; when I press the LWin and "j", AHK fires "Shift-Left". However, the aforementioned actions could only be done independently, and I could not achieve the desirable action like "Shift-Ctrl-Left" by pressing all LWin, CapsLock and "j". Below is the codes that I am using:

Code:
CapsLock::
Hotkey, *j, CapsLock_j, On
Return

CapsLock Up::
Hotkey, *j, Off
Return

CapsLock_j:
Send ^{Left}
Return

LWin::
Hotkey, *j, LWin_j, On
Return

LWin Up::
Hotkey, *j, Off
Return

LWin_j:
Send +{Left}
Return


Is there any code that could help me to accomplish what I need? Thanks for your help in advance.


Last edited by amichaelhk on August 14th, 2011, 1:47 pm, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 14th, 2011, 1:19 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
That's an interesting problem you've come up with, as I'm sure there are many ways to solve it, depending on the requirements. :)

Here are two different ways to solve it, with slightly different results:
Code:
CapsLock & j::Send % GetKeyState("LWin","P") ? "^+{Left}" : "^{Left}"
<#j::Send +{Left}

Code:
ctrl_key := "CapsLock"
shift_key := "LWin"
other_key := "j"

mod1 := 0
mod2 := 0

Hotkey *%ctrl_key%,     mod_key
Hotkey *%ctrl_key% Up,  mod_key
Hotkey *%shift_key%,    mod_key
Hotkey *%shift_key% Up, mod_key

return

mod_key:    ; Modifier key pressed or released.
    mods := ""
    if GetKeyState(ctrl_key, "P")
        mods .= "^"
    if GetKeyState(shift_key, "P")
        mods .= "+"
    Hotkey %other_key%, other_key, % mods ? "On" : "Off"
    return

other_key:  ; Modified key pressed (with at least one modifier).
    Send %mods%{Left}
    return

It can be useful to know both methods. If the ternary op ( ? : ) looks too cryptic, you can split it out into an IF statement or read up on the ternary operator.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 14th, 2011, 4:16 pm 
Offline

Joined: August 14th, 2011, 2:55 am
Posts: 7
Hi Lexikos, thanks for your quick and informative reply! :D

This is the first time I see the ternary-style IF/Else statement, it looks neat.

The first one looks more familiar to me as I always use the "&" to make some modifiers hotkeys. The second one looks more professional and shows me much more possibility about different keys combinations.

I am really curious about the largest extent that AHK could reach. Assuming now I use Tab, CapsLock, and LWin as arbitrary modifiers (their native functions would be discarded), when pressing the key "J":

Tab & j = Alt-PageDown
CapsLock & j = Ctrl-Left
LWin & j = Shift-Right
Tab & CapsLock & LWin & j = Arbitrary clipboard copy
Tab & CapsLock & j = Arbitrary clipboard paste
CapsLock & LWin & j = OtherFunction1
Tab & LWin & j = OtherFunction2

Is there anyway we could assign modifiers in this way, especially combining three or more modifiers? It seems that, when I use your mentioned first way, using "KeyA & KeyB" could only add one GetKeyState which only forming a maximum of two modifiers combo.

This case is fictitious. I just want to use it to see the way of coding when using three or even more arbitrary modifiers. I really appreciate anyone who could shed light on it.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 15th, 2011, 2:43 pm 
Offline

Joined: August 14th, 2011, 2:55 am
Posts: 7
Quote:
Tab & j = Alt-PageDown
CapsLock & j = Ctrl-Left
LWin & j = Shift-Right
Tab & CapsLock & LWin & j = Arbitrary clipboard copy
Tab & CapsLock & j = Arbitrary clipboard paste
CapsLock & LWin & j = OtherFunction1
Tab & LWin & j = OtherFunction2


Hi is there anyone who could guide me a further step to combine three or more arbitrary modifiers?

Really appreciate your help.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 15th, 2011, 4:51 pm 
Offline

Joined: August 14th, 2011, 2:55 am
Posts: 7
In fact I have tried to write something like the first taught way::

Code:
; Trying three arbitrary modifiers at once.
CapsLock::Return  ; Discard the original CapsLock function so as to make it a solely arbitrary modifier. Not necessary but hoping it could increase the chance of getting the code work.
LWin::Return  ; Same reason as that of CapsLock.

Tab & j::  ; Press down the arbitrary modifier Tab
GetKeyState, LWinState, LWin  ; Get the key state of LWin.
GetKeyState, CapsLockState, CapsLock, P  ; Get the key state of CapsLock Physical.
If (LWinState = D AND CapsLockState = D)  ; When also pressing down both the LWin and CapsLock.
{
   Send ^{Right}
   Return
}
If (LWinState = U AND CapsLockState = D)  ; When also pressing only the CapsLock.
{
   Send +^{Left}
   Return
}
If (LWinState = D AND CapsLockState = U)  ; When also pressing only the LWin.
{
   Send {Right}
   Return
}
Else  ; Neither pressing LWin nor CapsLock.
   Send +{Left}
Return


However whatever I press it only fires the last action (Else one, Shift-Left). What's wrong with my code? Could anyone give me a hint? Again thanks in advance for your teaching.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 15th, 2011, 7:48 pm 
Offline

Joined: May 20th, 2009, 6:18 pm
Posts: 129
The problem is the difference between "traditional if-statements" and expressions. You can, for example, write
Code:
If LWinState = D

as a traditional if-statement, but when there's parentheses, then it's an expression and it should be
Code:
if (LWinState = "D")

with quotation marks around the D to indicate that it is referring to a literal string, the letter D, and not the variable whose name is D.
Check out the documentation for variables and expressions,
http://www.autohotkey.com/docs/Variables.htm


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 15th, 2011, 10:52 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
Adding more modifiers to my previous script should be simple. Just add, for instance, an alt_key variable and do for it what's already done for shift_key and ctrl_key. However, at some point you'll hit the limitations of your keyboard hardware.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 16th, 2011, 11:08 am 
Offline

Joined: August 14th, 2011, 2:55 am
Posts: 7
Hi comvox,

Thanks for you pointing out my mistake! I am really a layman on programming. :D

I have corrected the code, but somehow using the GetKeyState Command Style does not work. I changed the codes to GetKeyState Function Style and get a little success. Below is the code which demonstrates hotkeys firing upon different pressing states of the arbitrary modifiers:

Code:
; Trying to make CapsLock, LWin and Tab as three arbitrary modifiers at once.
CapsLock::Return
LWin::Return
Tab::Return

$j:: ; Using the "j" key as an example firing the actions.
If ((GetKeyState("Tab", "P") && GetKeyState("LWin", "P")) && GetKeyState("CapsLock", "P"))
{
   Msgbox All three keys down.
   Return
}
If ((GetKeyState("Tab", "P") && !GetKeyState("LWin", "P")) && GetKeyState("CapsLock", "P"))
{
   Msgbox Tab and CapsLock down, LWin up.
   Return
}
If ((GetKeyState("Tab", "P") && GetKeyState("LWin", "P")) && !GetKeyState("CapsLock", "P"))
{
   Msgbox Tab and LWin down, CapsLock up.
   Return
}
If ((GetKeyState("Tab", "P") && !GetKeyState("LWin", "P")) && !GetKeyState("CapsLock", "P"))
{
    Msgbox LWin and CapsLock up, Tab down.
   Return
}
If ((!GetKeyState("Tab", "P") && !GetKeyState("LWin", "P")) && GetKeyState("CapsLock", "P"))
{
   Msgbox Tab and LWin up, CapsLock down.
   Return
}
If ((!GetKeyState("Tab", "P") && GetKeyState("LWin", "P")) && !GetKeyState("CapsLock", "P"))
{
    Msgbox Tab and CapsLock up, LWin down.
    Return
}
If ((!GetKeyState("Tab", "P") && GetKeyState("LWin", "P")) && GetKeyState("CapsLock", "P"))
{
    Msgbox LWin and CapsLock down, Tab up.
    Return
}
Else
{
    Send {Blind}j
    Return
}
Return


The code looks tedious, but is working and intuitive. Would like to hear your opinion about such style and recommendations about increasing the code's efficiency.


Last edited by amichaelhk on August 16th, 2011, 11:40 am, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 16th, 2011, 11:35 am 
Offline

Joined: August 14th, 2011, 2:55 am
Posts: 7
Lexikos wrote:
Adding more modifiers to my previous script should be simple. Just add, for instance, an alt_key variable and do for it what's already done for shift_key and ctrl_key. However, at some point you'll hit the limitations of your keyboard hardware.


Hi Lexikos,

I have to confess that I am really stupid being stuck on thinking that, like your example code, the firing actions must contain the {left} for all modifiers, and the modifiers are only limited to being remapped to only one traditional modifiers (Shift, Control) whatever firing keys (j and the remaining letters) are pressed.

After your confirmation of more possibilities based on your code's structure, I tried to rewrite it and also got "half" success. Below is the code:

Code:
; Using CapsLock and LWin as arbitrary modifiers, and "j" and "k" as firing keys.
ctrl_key := "CapsLock"
shift_key := "LWin"
j_key := "j"
k_key := "k"

Hotkey *%ctrl_key%, mod_key
Hotkey *%ctrl_key% Up, mod_key
Hotkey *%shift_key%, mod_key
Hotkey *%shift_key% Up, mod_key

return

mod_key:    ; Modifier key pressed or released.
    kmods := ""
    jmods := ""
    if (GetKeyState(ctrl_key, "P") && !GetKeyState(shift_key, "P"))
    {
        kmods := "CLk"
        jmods := "CLj"
    }
    if (GetKeyState(shift_key, "P") && !GetKeyState(ctrl_key, "P"))
    {
        kmods := "LWk"
        jmods := "LWj"
    }
    if (GetKeyState(ctrl_key, "P") && GetKeyState(shift_key, "P"))
    {
        kmods := "LWCLk"
        jmods := "LWCLj"
    }
    Hotkey %j_key%, j_key, % jmods ? "On" : "Off"
    Hotkey %k_key%, k_key, % kmods ? "On" : "Off"
    return

k_key:
    SendRaw %kmods%
    return

j_key:  ; Modified key pressed (with at least one modifier).
    SendRaw %jmods%
    return


Why I said it was a "half" success is that the firing actions could not entirely get rid of the modifiers' native functions (which is LWin). When I fire the keys, letters printed are missing some of the assigned letters. When I press the LWin-related combinations AHK only prints some letters and Windows locks my desktop. Since the assigned letter and the missing letter are "l", this implies that the firing actions include native Win modifier action, combing "l" which fires "Win-l" and locks my computer.

However when I press CapsLock and LWin independently, they both react like they would have been disabled. I tried adding "CapsLock::Return" and "LWin::Return" but it would entirely disable the hotkey code too.

Therefore I would like to ask if there is any other way which could completely disable the original key functions. Thanks for your guidance.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 16th, 2011, 11:04 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
Win+L and Ctrl+Alt+Del are special combinations which are detected more aggressively by the OS. Actually, I have Win+L disabled on my system (via the DisableLockWorkStation policy) and still I seem to get "W" instead of "LW" (but "CL" works). If you need to send "L", wait for LWin to be released first.

Code:
ctrl_key := "CapsLock"
shift_key := "LWin"
j_key := "j"
k_key := "k"

Hotkey *%ctrl_key%, mod_key
Hotkey *%ctrl_key% Up, mod_key
Hotkey *%shift_key%, mod_key
Hotkey *%shift_key% Up, mod_key

return

mod_key:    ; Modifier key pressed or released.
    mods := ""
    if GetKeyState(ctrl_key, "P")
        mods .= "CL"
    if GetKeyState(shift_key, "P")
        mods .= "LW"
    Hotkey *%j_key%, other_key, % mods ? "On" : "Off"
    Hotkey *%k_key%, other_key, % mods ? "On" : "Off"
    return

other_key:  ; Modified key pressed (with at least one modifier).
    other_key(mods, SubStr(A_ThisHotkey, 2)) ; For local variables.
    return

other_key(mods, key)
{
    if InStr(mods . key, "L")
        KeyWait LWin ; (global) mods and A_ThisHotkey will change in the meantime.
    SendRaw % mods . key
}


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 17th, 2011, 3:04 pm 
Offline

Joined: August 14th, 2011, 2:55 am
Posts: 7
Lexikos wrote:
Win+L and Ctrl+Alt+Del are special combinations which are detected more aggressively by the OS. Actually, I have Win+L disabled on my system (via the DisableLockWorkStation policy) and still I seem to get "W" instead of "LW" (but "CL" works). If you need to send "L", wait for LWin to be released first.


Thanks for your code and your opinion about the original Windows Hotkeys' behaviour! The code just does the job well, and also illustrates the feasibility of AHK codes. This is also my first time to see a piece of AHK code embedding an arbitrarily defined function, which is an elegant and powerful way to achieve the goal.

In fact it was really an accident discovering the conflicts of the Win+L hotkey as I had used the Send command to try to demonstrate the effectiveness of such coding structure. I changed the first set of coding (which mainly used the If and GetKeyState commands) to firing Send command containing the letter L. The result was similar to this set of code before your polishing, which locked the Windows.


Report this post
Top
 Profile  
Reply with quote  
PostPosted: March 22nd, 2012, 11:36 pm 
I post here because it seems to fit, hope it's okay.

It's understandable that Windows intercepts Ctrl-Alt-Del and #L for security integrity. But I've come across more on XP and W7.

I have a crummy keyboard with the DEL key right next to ENTER -- with predictable loss of work. I tried this: -

DEL::return
^DEL::send {DEL}

but W7 still interprets ^DEL as "delete word" in all apps I've tested. I changed the second line to !DEL, which works; but the Alt key is much more awkward, I have to look down at the keyboard.

Another is #u -- it invokes the W7 Accessability control panel even if remapped.

Finally, this (for fast scrolling in a graphics programme) has no effect: -

Up::Send +{Up}
Down::Send +{Down}
Left::Send +Left
Right::Send +Right

Is there any way to trap ^DEL and #u anybody knows of, and modify the cursor keys?

Thanks in advance for any ideas or pointers (even RTFM).


Report this post
Top
  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 12 posts ] 

All times are UTC [ DST ]


Who is online

Users browsing this forum: batto, JSLover, sjc1000, Yahoo [Bot] and 60 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group