AutoHotkey Community

It is currently May 26th, 2012, 7:51 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 29 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: November 14th, 2007, 1:16 am 
Offline
User avatar

Joined: October 7th, 2006, 8:45 am
Posts: 3328
Location: Simi Valley, CA
Directory:
Wheel Spinners for Numbers in Edit Boxes
[VxE]'s Encryption Function
String Replace Function
Clipboard Execute
Quick Click Dictionary Lookup
Various Unicode handling functions (read from files and insert into controls)
Vector Function Library: a collection of functions for manipulating vectors
Arrow Keys to Numpad Numbers
Hue Sat Lum Functions
Reload() with parameters and the "Part()" function
GuiControlAutosize(). After changing a gui control's contents, update its size based on its new contents.
ControlGetClassName(). Get the class name of a control without its instance number. A basic wrapper for "GetClassName".

This thread is dedicated to the various little bits of code that I care to put into one place, but which I don't feel like giving their own threads.

_________________
Ternary (a ? b : c) guide     TSV Table Manipulation Library
Post code inside [code][/code] tags!


Last edited by [VxE] on October 2nd, 2009, 1:32 am, edited 26 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 22nd, 2008, 7:33 am 
this post sucks








but not as much as this thread :D


Report this post
Top
  
Reply with quote  
PostPosted: March 22nd, 2008, 9:12 am 
Offline
User avatar

Joined: October 7th, 2006, 8:45 am
Posts: 3328
Location: Simi Valley, CA
Although this post previously contained a hash function based on AdvAPI32.dll, I have removed it due to the availability of superior alternatives that use the same dll.

Instead, here is a library-style function collection for computing hashes ( SHA1 and SHA256 ) and the related HMACs.

Note: I have not conducted speed tests between these functions and AdvAPI32.dll-powered hash functions.
Code:
/*
####################################################################################################
####################################################################################################
######                                                                                        ######
######                        Secure Hash Algorithms: SHA-1 and SHA-256                       ######
######                                                                                        ######
######                             Also: HMAC_SHA1 and HMAC_SHA256                            ######
######                                                                                        ######
####################################################################################################
####################################################################################################

This library contains functions for calculating cryptographic hashes using the SHA1 and SHA256
algorithms and functions for signing messages using those hashes (HMAC).
*/

SHA() { ; ------------------------------------------------------------------------------------------
; Library inclusion stub. Name this file 'SHA.ahk' and save it to your Autohotkey Lib folder.
; To include these functions in your script, simply call this function near the top of your script.
    Return "Hash functions SHA1 and SHA256 as well as HMAC_SHA1 and HMAC_SHA256 are available "
        . "in this script. These functions were written by [VxE] and are available publicly "
        . "at http://www.autohotkey.com/forum/viewtopic.php?p=186095#186095"
} ; SHA() ------------------------------------------------------------------------------------------

SHA1( byref data, len = 0 ) { ; --------------------------------------------------------------------
; This implementation of the SHA1 algorithm was written by [VxE] on 09-13-2010.
; More info about the SHA-1 hash algorithm at http://en.wikipedia.org/wiki/SHA-1
; Also see http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
    m32 := 0xffffffff ; this stands for modulo 32-bit, since AHK's numbers are all 64 bit, we'll
    ; need to explicitly truncate bits beyond 32 by bitwise-ANDing them with this number.

    IfLessOrEqual, Len, 0, StringLen, Len, data ; autodetect data length if it's not explicitly declared

    ; initialize the 5 inter-block collector variables
    _a := 0x67452301, _b := 0xEFCDAB89, _c := 0x98BADCFE, _d := 0x10325476, _e := 0xC3D2E1F0

    ; The number of blocks is the number of bytes in the data plus 8 (for the data length) divided by 64
    Loop % blocks := ( Len + 8 >> 6 ) + 1
    {
        VarSetCapacity( block, 320, 0 ) ; clear a temporary buffer for a copy of this block
        a := _a, b := _b, c := _c, d := _d, e := _e ; initialize the intra-block collector variables
       
        ; 'o' becomes the base offset, in bytes, of the current block
        If ( Len - 64 >= o := A_Index - 1 << 6 ) ; Copy the current block into the buffer
            DllCall("RtlMoveMemory", "UInt", &block, "UInt", &data + o, "Int", 64 )
        Else If ( Len - o > 0 ) ; if this is the last block, only copy the remaining bytes (less than 64)
            DllCall("RtlMoveMemory", "UInt", &block, "UInt", &data + o, "Int", Len - o )

        If ( Len - o >= 0 && Len - o < 64 ) ; if this is the last block with actual data in it, then
            NumPut( 128, block, Len - o, "Char" ) ; append a 0x80 byte to terminate the message data

        If ( A_Index = blocks ) ; if this is the actual last block, inject the data length in bits
            Loop 8 ; as a 64-bit big-endian integer into the last 8 bytes of the buffer.
                NumPut( Len << 3 >> ( 8 - A_Index << 3 ) & 255, block, 55 + A_Index, "Char" )

        Loop 80 ; Since the block is 320 bytes, it contains 80 dwords
        {
        ; dwords 1 thru 16 are 4-byte chunks of the buffer interpereted as big-endian 32-bit integers
            If ( 64 > o := A_Index - 1 << 2 ) ; 'o' is now the offset of the next dword in the buffer
                NumPut( w := NumGet( block, o + 3, "UChar" )
                 | NumGet( block, o + 2, "UChar" ) << 8
                 | NumGet( block, o + 1, "UChar" ) << 16
                 | NumGet( block, o, "UChar" ) << 24, block, o, "UInt" )
            Else ; dwords 17 through 80 are each derived from 4 other dwords, XORed together and
            { ; then left rotated by 1 bit (using 32-bit arithmetic, don't forget)
                w := NumGet( block, o - 4 * 3, "UInt" ) ^ NumGet( block, o - 4 * 8, "UInt" )
                    ^ NumGet( block, o - 4 * 14, "UInt" ) ^ NumGet( block, o - 4 * 16, "UInt" )
                NumPut( w := ( w << 1 | ( w >> 31 )) & m32, block, o, "UInt" )
            }
        ; A value ('f') is calculated from a constant, a dword from the buffer, and the intra-block variables
        ; The formula for this value changes depending on how far into the block 'o' is.
            If ( o < 80 )
                f := m32 & 0x5A827999 + ( ( b & c ) | ((~b) & d) ) + ( a << 5 | ( a >> 27 )) + e + w
            Else If ( o < 160 )
                f := m32 & 0x6ED9EBA1 + ( b ^ c ^ d ) + ( a << 5 | ( a >> 27 )) + e + w
            Else If ( o < 240 )
                f := m32 & 0x8F1BBCDC + ( ( b & c ) | ( b & d ) | ( c & d ) ) + ( a << 5 | ( a >> 27 )) + e + w
            Else f := m32 & 0xCA62C1D6 + ( b ^ c ^ d ) + ( a << 5 | ( a >> 27 )) + e + w
        ; once 'f' is calculated, the intra-block variables are rolled, with 'a' receiving 'f's value
            e := d, d := c, c := m32 & ( b << 30 | ( b >> 2 )), b := a, a := f
        }
        ; Now that the block has been processed, add the intra-block variables to their inter-block counterparts
        _a := _a + a & m32, _b := _b + b & m32, _c := _c + c & m32, _d := _d + d & m32, _e := _e + e & m32
    }
    VarSetCapacity( block, 40, 0 ) ; we re-use the block buffer to hold the hash string
    Loop 40 ; The SHA1 hash is, by definition, 40 hex digits long.
    ; This is an obfuscated way of taking the 5 inter-block variables and converting their contents
    ; into hex representation and concatenating them.
        j := Chr( 97 + ( A_Index - 1 >> 3 ) )
        , j := _%j% >> ( ( 8 - A_Index & 7 ) << 2 ) & 15
        , block .= Chr( 48 + j + 39 * ( j > 9 ) )
    Return block ; return the hex string
} ; SHA1( byref data, len = 0 ) --------------------------------------------------------------------

HMAC_SHA1( byref key, byref message, keylen = 0, msglen = 0 ) { ; ----------------------------------
; Function by [VxE]. See RFC 2104 ( http://www.ietf.org/rfc/rfc2104.txt )
; test vectors may be found at ( http://tools.ietf.org/html/rfc2202 )
    Static hex := "123456789abcdef" ; this is for converting hex into byte values

    ; Autodetect the lengths of the key and message if they aren't explicitly set
    IfLessOrEqual, keylen, 0, StringLen, keylen, key
    IfLessOrEqual, msglen, 0, StringLen, msglen, message

    ; define a buffer to hold the message AND the inner padding and copy the message into it
    VarSetCapacity( buffer, msglen + 64, 54 )
    DllCall("RtlMoveMemory", "UInt", &buffer + 64, "UInt", &message, "Int", msglen )

    If ( keylen > 64 ) ; deal with long keys by hashing them
    {
        key := SHA1( key, keylen ), keylen := 20
        Loop, Parse, key
            IfEqual, True, % A_Index & 1, SetEnv, nbl, % InStr( hex, A_LoopField ) << 4
            Else NumPut( nbl | InStr( hex, A_LoopField ), key, A_Index - 2 >> 1, "Char" )
    }
    ; Take the key and for each byte, XOR it with 0x36 and insert the result into the inner padding
    Loop %keylen%
        NumPut( NumGet( key, A_Index - 1, "UChar" ) ^ 54, buffer, A_Index - 1, "Char" )

    ; Hash the inner padding + the message and prep the buffer for the outer hash
    msglen := SHA1( buffer, 64 + msglen ), VarSetCapacity( buffer, 96, 92 )

    ; Take the key and for each byte, XOR it with 5C and insert the result into the outer padding
    Loop %keylen% ;
        NumPut( NumGet( key, A_Index - 1, "UChar" ) ^ 92, buffer, A_Index - 1, "Char" )

    ; Append the message hash to the outer padding ( converting hex into bytes )
    Loop, Parse, msglen
        IfEqual, True, % A_Index & 1, SetEnv, nbl, % InStr( hex, A_LoopField ) << 4
        Else NumPut( nbl | InStr( hex, A_LoopField ), buffer, 64 + ( A_Index - 2 >> 1 ), "Char" )

    ; Return the hash of the modified message. Note that (84) = block size (64) + digest length (20)
    ; If you're modifying this function for other hash algorithms, you must change this value.

    Return SHA1( buffer, 84 ), VarSetCapacity( buffer, 0 )

} ; HMAC_SHA1( byref key, byref message, keylen = 0, msglen = 0 ) ----------------------------------

SHA256( byref data, len = 0 ) { ; ------------------------------------------------------------------
; This implementation of the SHA256 algorithm was written by [VxE] on 08-29-2010.
; More info about the SHA-1 hash algorithm at http://en.wikipedia.org/wiki/SHA-2
; Also see http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf

    ; The first time this function is run, the static variable 'k' is transformed into an array
    ; of 64 dwords. These are the constants used when processing the data blocks
    Static m32 := 0, k := "
    ( ltrim join
        982f8a4291443771cffbc0b5a5dbb5e95bc25639f111f159a4823f92d55e1cab
        98aa07d8015b8312be853124c37d0c55745dbe72feb1de80a706dc9b74f19bc1
        c1699be48647beefc69dc10fcca10c246f2ce92daa84744adca9b05cda88f976
        52513e986dc631a8c82703b0c77f59bff30be0c64791a7d55163ca0667292914
        850ab72738211b2efc6d2c4d130d385354730a65bb0a6a762ec9c281852c7292
        a1e8bfa24b661aa8708b4bc2a3516cc719e892d1240699d685350ef470a06a10
        16c1a419086c371e4c774827b5bcb034b30c1c394aaad84e4fca9c5bf36f2e68
        ee828f746f63a5781478c8840802c78cfaffbe90eb6c50a4f7a3f9bef27871c6
    )"
    If !m32 ; this variable is static, but it also serves as an initialization flag
    {    ; notice the k-constants are originally in hex format... they get changed here
        m32 := 0xffffffff
    ; m32 stands for modulo 32-bit, because AHK's numbers are all 64-bit,  we'll
    ; need to explicitly truncate bits beyond 32 by bitwise-ANDing them with this number.
        Loop, Parse, k
            IfEqual, True, % A_Index & 1, SetEnv, i, % InStr( "123456789abcdef", A_LoopField ) << 4
        Else NumPut( i | InStr( "123456789abcdef", A_LoopField ), k, A_Index - 2 >> 1, "UChar" )
    }

    IfLessOrEqual, Len, 0, StringLen, Len, data ; autodetect data length if it's not explicitly declared

    ; initialize the 8 inter-block collector variables
      _a := 0x6a09e667, _b := 0xbb67ae85, _c := 0x3c6ef372, _d := 0xa54ff53a
    , _e := 0x510e527f, _f := 0x9b05688c, _g := 0x1f83d9ab, _h := 0x5be0cd19

    ; The number of blocks is the number of bytes in the data plus 8 (for the data length) divided by 64
    Loop % blocks := ( Len + 8 >> 6 ) + 1
    {
        VarSetCapacity( block, 256, 0 ) ; clear a temporary buffer for a copy of this block
        a := _a, b := _b, c := _c, d := _d, e := _e, f := _f, g := _g, h := _h ; initialize the intra-block collector variables
       
        ; 'o' becomes the base offset, in bytes, of the current block
        If ( Len - 64 >= o := A_Index - 1 << 6 ) ; Copy the current block into the buffer
            DllCall("RtlMoveMemory", "UInt", &block, "UInt", &data + o, "Int", 64 )
        Else If ( Len - o > 0 ) ; if this is the last block, only copy the remaining bytes (less than 64)
            DllCall("RtlMoveMemory", "UInt", &block, "UInt", &data + o, "Int", Len - o )

        If ( Len - o >= 0 && Len - o < 64 ) ; if this is the last block with actual data in it, then
            NumPut( 128, block, Len - o, "Char" ) ; append a 0x80 byte to terminate the message data

        If ( A_Index = blocks ) ; if this is the actual last block, inject the data length in bits
            Loop 8 ; as a 64-bit big-endian integer into the last 8 bytes of the buffer.
                NumPut( Len << 3 >> ( 8 - A_Index << 3 ) & 255, block, 55 + A_Index, "Char" )

        Loop 64 ; Since the block is 256 bytes, it contains 64 dwords
        {
        ; dwords 1 thru 16 are 4-byte chunks of the buffer interpereted as big-endian 32-bit integers
            If ( 64 > o := A_Index - 1 << 2 ) ; 'o' is now the offset of the next dword in the buffer
                NumPut( w := NumGet( block, o + 3, "UChar" )
                 | NumGet( block, o + 2, "UChar" ) << 8
                 | NumGet( block, o + 1, "UChar" ) << 16
                 | NumGet( block, o, "UChar" ) << 24, block, o, "UInt" )
            Else ; dwords 17 through 64 are each derived from 4 other dwords
            {
                sig1 := NumGet( block, o - 4 * 15, "UInt" )
                sig2 := NumGet( block, o - 4 * 2, "UInt" )
                sig1 := (( sig1 >> 7 ) | ( ( sig1 & 0x7f ) << 25 ))
                    ^ (( sig1 >> 18 ) | ( ( sig1 & 0x3ffff ) << 14 ))
                    ^ ( sig1 >> 3 )
                sig2 := (( sig2 >> 17 ) | ( ( sig2 & 0x1ffff ) << 15 ))
                    ^ (( sig2 >> 19 ) | ( ( sig2 & 0x7ffff ) << 13 ))
                    ^ ( sig2 >> 10 )
                sig3 := NumGet( block, o - 4 * 7, "UInt" ) + NumGet( block, o - 4 * 16, "UInt" )
                NumPut( w := m32 & sig1 + sig2 + sig3, block, o, "UInt" )
            }
            j := NumGet( k, o, "Uint" ) ; obtain a value from the constant static array
            ; t1 and t2 are temporary variables to hold a value that need to be calculated before
            ; the intra-block variables are rolled.
            t2 := ( (( a >> 2 ) | ( ( a & 0x3 ) << 30 ))
                ^ (( a >> 13 ) | ( ( a & 0x1fff ) << 19 ))
                ^ (( a >> 22 ) | ( ( a & 0x3fffff ) << 10 )) )
                + ( ( a & b ) ^ ( a & c ) ^ ( b & c ) ) & m32
            t1 := ( (( e >> 6 ) | ( ( e & 0x3f ) << 26 ))
                ^ (( e >> 11 ) | ( ( e & 0x7ff ) << 21 ))
                ^ (( e >> 25 ) | ( ( e & 0x1ffffff ) << 7 )) )
                + ( ( e & f ) ^ ( (~e) & g ) ) + h + j + w & m32
            ; roll the intra-block variables, 'a' receives the temporary values.
            h := g, g := f, f := e, e := d + t1 & m32, d := c, c := b, b := a, a := t1 + t2 & m32
        }

        ; Now that the block has been processed, add the intra-block variables to their inter-block counterparts
        _a := _a + a & m32, _b := _b + b & m32, _c := _c + c & m32, _d := _d + d & m32
        , _e := _e + e & m32, _f := _f + f & m32, _g := _g + g & m32, _h := _h + h & m32
    }
    VarSetCapacity( block, 64, 0 ) ; we re-use the block buffer to hold the hash string
    Loop 64 ; The SHA256 hash is, by definition, 64 hex digits long.
    ; This is an obfuscated way of taking the 5 inter-block variables and converting their contents
    ; into hex representation and concatenating them.
        j := Chr( 97 + ( A_Index - 1 >> 3 ) )
        , j := _%j% >> ( ( 8 - A_Index & 7 ) << 2 ) & 15
        , block .= Chr( 48 + j + 39 * ( j > 9 ) )
    Return block ; return the hex string
} ; SHA256( byref data, len = 0 ) ------------------------------------------------------------------

HMAC_SHA256( byref key, byref message, keylen = 0, msglen = 0 ) { ; --------------------------------
; Function by [VxE]. See RFC 2104 ( http://www.ietf.org/rfc/rfc2104.txt )
; test vectors may be found at ( http://tools.ietf.org/html/rfc4231 )
    Static hex := "123456789abcdef" ; this is for converting hex into byte values

    ; Autodetect the lengths of the key and message if they aren't explicitly set
    IfLessOrEqual, keylen, 0, StringLen, keylen, key
    IfLessOrEqual, msglen, 0, StringLen, msglen, message

    ; define a buffer to hold the message AND the inner padding and copy the message into it
    VarSetCapacity( buffer, msglen + 64, 54 )
    DllCall("RtlMoveMemory", "UInt", &buffer + 64, "UInt", &message, "Int", msglen )

    If ( keylen > 64 ) ; deal with long keys by hashing them
    {
        key := SHA256( key, keylen ), keylen := 32
        Loop, Parse, key
            IfEqual, True, % A_Index & 1, SetEnv, nbl, % InStr( hex, A_LoopField ) << 4
            Else NumPut( nbl | InStr( hex, A_LoopField ), key, A_Index - 2 >> 1, "Char" )
    }
    ; Take the key and for each byte, XOR it with 0x36 and insert the result into the inner padding
    Loop %keylen%
        NumPut( NumGet( key, A_Index - 1, "UChar" ) ^ 54, buffer, A_Index - 1, "Char" )

    ; Hash the inner padding + the message and prep the buffer for the outer hash
    msglen := SHA256( buffer, 64 + msglen ), VarSetCapacity( buffer, 96, 92 )

    ; Take the key and for each byte, XOR it with 5C and insert the result into the outer padding
    Loop %keylen% ;
        NumPut( NumGet( key, A_Index - 1, "UChar" ) ^ 92, buffer, A_Index - 1, "Char" )

    ; Append the message hash to the outer padding ( converting hex into bytes )
    Loop, Parse, msglen
        IfEqual, True, % A_Index & 1, SetEnv, nbl, % InStr( hex, A_LoopField ) << 4
        Else NumPut( nbl | InStr( hex, A_LoopField ), buffer, 64 + ( A_Index - 2 >> 1 ), "Char" )

    ; Return the hash of the modified message. Note that (96) = block size (64) + digest length (32)
    ; If you're modifying this function for other hash algorithms, you must change this value.

    Return SHA256( buffer, 96 ), VarSetCapacity( buffer, 0 )

} ; HMAC_SHA256( byref key, byref message, keylen = 0, msglen = 0 ) --------------------------------

another edit, this is my version of MD5 done in AHK:
Code:
MD5( byref data, len=0 ) { ; -----------------------------------------------------------------------
; Function by [VxE]. Specify the data length if 'data' may possibly contain null bytes.

   ; static variables and constants r[0~63], encoded here as bytes with an offset of 64
   ; ( that means the real value is the byte value minus 64, e.g: r[0] = 7, so 7 + 64 = 71 = 'G' )
   Static S, k, p:=0, r := "GLQVGLQVGLQVGLQVEINTEINTEINTEINTDKPWDKPWDKPWDKPWFJOUFJOUFJOUFJOU"

   VarSetCapacity( S, 64, 0 ) ; Initialize the block buffer S and constants p and k[0~63]
   IfEqual, p, 0, Loop % VarSetCapacity( k, 256 + !( p := &S ) ) >> 2 & 64
      NumPut( Floor(Abs(Sin(A_Index)) * 2**32 ), k, A_Index - 1 << 2, "UInt" )

   ; autodetect message length if it's not specified (or is not positive)
   IfLess, len, 1, StringLen, len, data

   ; initialize running accumulators and terminator (the terminator is appended to the message)
   ha := 0x67452301, hb := 0xEFCDAB89, hc := 0x98BADCFE, hd := 0x10325476, term := 0x80

   ; Begin rolling the message. This loop does 1 iteration for each 64 byte block such that the
   ; last block has fewer than 55 bytes in it ( to leave room for the terminator and data length )
   Loop % len + 72 >> 6
   {
      If ( f := len - 64 > ( e := A_Index - 1 << 6 ) ? 64 : len > e ? len - e : 0 )
         DllCall( "RtlMoveMemory", "UInt", p, "UInt", &data + e, "Int", f ) ; copy the block
      IfLess, f, 64 ; append the terminator to the message, then wipe the terminator since
         NumPut( ( term | 0 ) | term := 0, S, f, "UChar" ) ; this may not be the last block
      IfLess, f, 56, Loop 8 ; if this is the real last block, insert the data length in BITS
         NumPut( ( len << 3 >> ( A_Index - 1 << 3 ) ) & 255, S, 55 + A_Index, "UChar" )
      
      a := ha, b := hb, c := hc, d := hd ; copy running accumulators to intermediate variables

      Loop 64 ; begin rolling the block. These operations have been condensed and obfuscated.
      { ; For i from 0 to 63 {
         e := NumGet( r, i := A_Index - 1, "UChar" ) & 31 ; extract the constant r[i]
         f := 0 = ( j := i >> 4 ) ? (b&c)|(~b&d) : j=1 ? (d&b)|(~d&c) : j=2 ? b^c^d : c^(~d|b)
         g := (( i * ( 3817 >> j * 3 & 7 ) + ( 328 >> j * 3 & 7 ) & 15 ) << 2 ) + p
         w := (*(g+3) << 24 | *(g+2) << 16 | *(g+1) << 8 | *g) + a + f + NumGet(k,i<<2,"UInt")
         a := d, d := c, c := b, b += w << e | (( w & 0xFFFFFFFF ) >> ( 32 - e ))
      }
      ; add the intermediate variables to the running accumlators (making sure to mod by 2**32)
      ha := ha+a&0xFFFFFFFF, hb := hb+b&0xFFFFFFFF, hc := hc+c&0xFFFFFFFF, hd := hd+d&0xFFFFFFFF
      VarSetCapacity( S, 64, 0 ) ; Clear the block ( set bits to zero )
   }
   Loop 32 ; convert the running accumulators into 32 hex digits
      i := Chr( 96 + ( A_Index + 7 >> 3 ) ), S .= SubStr( "123456789abcdef0"
      , h%i% >> ( Mod( A_Index - 1 + (A_Index & 1) - !(A_Index & 1), 8 ) << 2 ) & 15, 1 )
   Return S ; return the hex digits
} ; MD5( byref data, len=0 ) -----------------------------------------------------------------------

_________________
Ternary (a ? b : c) guide     TSV Table Manipulation Library
Post code inside [code][/code] tags!


Last edited by [VxE] on October 31st, 2010, 2:06 am, edited 7 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 22nd, 2008, 5:19 pm 
somebody doesn't like you.

can't win them all though. :wink: thanks. I picked up some parts.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: April 2nd, 2008, 10:51 am 
Saw your 'hint' to this thread at your signature. Have you thought about to 'rearrange' the threads apperance a little with using BBCodeWriter?

Currently it's quite a tough challenge to get 'the idea behind' a script within a snap.

JM2€Cs + thanks for sharing your scripts with us. Much appreciated 8)


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: April 2nd, 2008, 9:10 pm 
Offline
User avatar

Joined: October 7th, 2006, 8:45 am
Posts: 3328
Location: Simi Valley, CA
Hmmm... there is indeed a lot of housekeeping that I should do with this thread, but recently I've been up to my eyeballs in other work. I suppose I really should break each scriptlet into its own post and keep a directory in the OP.

I'm glad you found something useful here :lol: :P

[Edit: 3-2-2010] More Set Functions (I added the fancy ones: permutation, power, combination, and transpose)
Code:
;
; Set functions library (Upgraded, String-Based), by [VxE]
;
; Introduction:
;      Sets are an important concept in OOP, data management, and
;      discrete mathematics. This function library allows you to
;      define sets of string objects and perform typical set functions
;      on them. Additionally, this library offers six functions for
;      handling multi-dimensional sets: Set_Zip joins two sets
;      on a 1:1 basis and Set_Column extracts a set from a complex
;      set. Set_Combinations, Set_Permutate, and Set_Power return
;      supersets of an input set ( combinations are subsets of N
;      distinct members from the input set ). Set_Transpose returns
;      a set with the same elements, but flipped on the diagonal.
;      The real power behind this library is the ability to use
;      any string as a delimiter, rather than just a single character.
;      This feature makes it easy to work with data collections in
;      multiple text formats and to construct multi-dimensional sets
;      without limits.
;
; Definitions:
;      a 'delimiter' is a string with a length greater than zero.
;      a 'member' is a string within a 'set' bounded by delimiters and/or
;         the ends of the string.
;      a 'set' is a string containing zero or more members, each separated
;         from the previous and next member by a delimiter.
;
; Functions:
;      Set_Column
;      Set_Combinations   ( see http://en.wikipedia.org/wiki/Combination )
;      Set_Delimit
;      Set_GetPos
;      Set_GetPosRegEx
;      Set_Intersect
;      Set_Member
;      Set_Permutations    ( see http://en.wikipedia.org/wiki/Permutation )
;      Set_Power              ( see http://en.wikipedia.org/wiki/Power_set )
;      Set_Remove
;      Set_Size
;      Set_Transpose        ( see http://en.wikipedia.org/wiki/Transpose )
;      Set_Union
;      Set_Zip
;
;      Set_SampleSet
;
; Notes:
;      All string comparisons are case sensitive with the exception of
;      Set_GetPosRegEx, which leaves case sensitivity up to the regex.

Set_Column( Set1, column, PrimaryDelimiter="`n", SecondaryDelimiter="," ) {
; Returns a set which is comprised of the 'column'th sub-member of
; each of 'Set1's members. Essentially, if each member were like a
; row in a table, this function would yield a column from that table.
   VarSetCapacity( Set, StrLen( Set1 ))
   column := Floor( column ) ; truncate decimals
   Set1 .= PrimaryDelimiter
   Stuff := StrLen( PrimaryDelimiter )
   iStuff := StrLen( SecondaryDelimiter )
   Pos := 1 - Stuff
   Lead := 1
   Loop
      If ( 0 < Pos := InStr( Set1, PrimaryDelimiter, 1, Pos + Stuff ) )
      {
         StringMid, member, Set1, %Lead%, Pos - Lead
         Lead := Pos + Stuff
         member .= SecondaryDelimiter
         ilead := 1
         ipos := 1 - istuff
         Loop
            If ( 0 < ipos := InStr( member, SecondaryDelimiter, 1, ipos + Stuff ) )
            {
               StringMid, imember, member, %ilead%, ipos - ilead
               ilead := ipos + iStuff
               If ( A_Index < column )
                  Continue
               Set .= PrimaryDelimiter . imember
               Break
            }
            Else Break
      }
      Else Break
   StringTrimLeft, Set, Set, %Stuff%
   Return Set
}

Set_Combinations( Set1, members=1, PrimaryDelimiter="`n", SecondaryDelimiter="," ) {
; Returns a complex set where each member is composed of 'members' members from
; Set1. The resulting set contains only unique members ( no two members will
; contains exactly the same sub-members, regardless of order ) assuming, of course,
; that the input set contains all unique members in the first place.
   Size := Set_Size( Set1, PrimaryDelimiter ), Pz := 1
   If ( members <= 0 ) || ( members > Size )
      Return "" ; pre-check for neg/zero members
   If ( members = 1 )
      Return Set_Union( Set1, "", PrimaryDelimiter ) ; 1-member -> set as-is
   If ( members = Size )
      Return Set_Delimit( Set1, SecondaryDelimiter, PrimaryDelimiter )

   Set1 .= PrimaryDelimiter
   Stuff := StrLen( PrimaryDelimiter )
   Pos := 1 - Stuff
   Lead := 1
   Loop ; separate the set into an array of members
      If ( 0 < Pos := InStr( Set1, PrimaryDelimiter, 1, Pos + Stuff ) )
      {
         StringMid, member%A_Index%, Set1, %Lead%, Pos - Lead
         Lead := Pos + Stuff
      }
      Else Break
   StringTrimRight, Set1, Set1, %Stuff%

   If ( members + 1 = Size ) ; this is the opposite of 'members' == 1
   {
      Loop, %Size% ; omit each member in turn and append to result
         Set := Set_Delimit( Set_Remove( Set1, member%A_Index%, PrimaryDelimiter ), SecondaryDelimiter, PrimaryDelimiter ) . ( A_Index = 1 ? "" : PrimaryDelimiter . Set )
      Return Set
   }

   Loop, %members% ; calculate the number of combinations (pascal's triangle)
      Pz := Round( pz * ( Size + 1.0 - A_Index ) / ( i%A_Index% := A_Index ) )

   VarSetCapacity( Set, StrLen( Set1 ) * Pz * Size, 0 ) ; a very rough estimate

   Loop, %Pz% ; for each potential combination
   {
      Loop, %members% ; choose N members
      {
         m := i%A_Index%
         Set .= ( A_Index = 1 ? PrimaryDelimiter : SecondaryDelimiter ) . member%m%
         If ( Size - members + A_Index > i%A_Index% )
            c := A_Index ; this is the thing we should increment next
      }
      i%c% += 1 ; increment something
      Loop % members - c ; we need to adjust some things
         k := c + A_Index, i%k% := i%c% + A_Index
   }
   StringTrimLeft, Set, Set, %Stuff%
   Return Set
}

Set_Delimit( Set1, NewD, PrimaryDelimiter="`n" ) {
; Replaces every instance of 'PrimaryDelimiter' in 'Set1' with 'NewD', effectively
; changing the set's delimiter.
   oel := ErrorLevel ; preserve errorlevel
   StringReplace, Set1, Set1, %PrimaryDelimiter%, %NewD%, All
   Return Set1, ErrorLevel := oel
}

Set_GetPos( Set1, string, PrimaryDelimiter="`n" ) {
; Returns the index of the first member of 'Set1' that is an exact
; match of 'string'. The return value is zero if there is no match.
   If ( 1 >= Pos := InStr( PrimaryDelimiter . Set1 . PrimaryDelimiter, PrimaryDelimiter . string . PrimaryDelimiter, 1 ) )
      Return Pos
   StringLeft, Set1, Set1, % Pos - 1
   Return Set_Size( Set1, PrimaryDelimiter)
}

Set_GetPosRegEx( Set1, NeedleRegex, PrimaryDelimiter="`n" ) {
; Returns the index of the first member of 'Set1' that is a match
; of 'NeedleRegex'. The return value is zero if there is no match.
; NOTE: the regex needle should NOT account for the delimiters.
; Anchors "^$" will match a delimiter boundary. For example, the
; needleregex "^$" will match the first empty member in the set.
   Stuff := StrLen( PrimaryDelimiter )
   Set1 .= PrimaryDelimiter
   Pos := 1 - Stuff
   Lead := 1
   Loop
      If ( 0 < Pos := InStr( Set1, PrimaryDelimiter, 1, Pos + Stuff ) )
      {
         StringMid, member, Set1, %Lead%, Pos - Lead
         Lead := Pos + Stuff
         If RegexMatch( member, NeedleRegex )
            Return A_Index
      }
      Else Break
   Return 0
}

Set_Intersect( Set1, Set2, PrimaryDelimiter="`n" ) {
; Performs a set intersection of 'Set1' and 'Set2'. Only the members
; that are in both sets will be in the resulting set.
   If ( Set_Size( Set1 ) > Set_Size( Set2 ) )
      Set := Set2, Set2 := Set1, Set1 := Set
   VarSetCapacity( Set, StrLen( Set1 ), 0)
   Set1 .= PrimaryDelimiter
   Set2 := PrimaryDelimiter . Set2 . PrimaryDelimiter
   Stuff := StrLen( PrimaryDelimiter )
   Pos := 1 - Stuff
   Lead := 1
   Loop
      If ( 0 < Pos := InStr( Set1, PrimaryDelimiter, 1, Pos + Stuff ) )
      {
         StringMid, member, Set1, %Lead%, Pos - Lead
         Lead := Pos + Stuff
         If InStr( Set2, PrimaryDelimiter . member . PrimaryDelimiter, 1 )
            Set .= PrimaryDelimiter . member
      }
      Else Break
   StringTrimLeft, Set, Set, %Stuff%
   Return Set
}

Set_Member( Set1, Which, PrimaryDelimiter="n" ) {
; Returns the 'Which'th member of Set1. A 'Which' less than 1 is
; considered an offset from the last member ('0' being the last)
   Len := Set_Size( Set1, PrimaryDelimiter )
   Which := Floor( Which )
   If ( Which <= 0 ) && ( Len + Which > 0 )
      Which := Len + Which
   If ( Which > Len ) || ( Which <= 0 )
      Return ""
   Set1 .= PrimaryDelimiter
   Stuff := StrLen( PrimaryDelimiter )
   Pos := 1 - Stuff
   Lead := 1
   Loop
      If ( 0 < Pos := InStr( Set1, PrimaryDelimiter, 1, Pos + Stuff ) )
      && ( A_Index < which )
         Lead := Pos + Stuff
      Else Break
   StringMid, member, Set1, %Lead%, Pos - Lead
   Return member
}

Set_Permutations( Set1, PrimaryDelimiter="`n", SecondaryDelimiter=",", p="" ) {
; Returns a complex set where each member is a unique permutation of
; the input set and which contains a number of members equal to the
; factorial of the input set's membercount. Note that 'PrimaryDelimiter'
; is the primary delimiter for both the input and output sets.

; WARNING! This function's output set has a size equal to the FACTORIAL
; of the input set's size. This means that a set of 10 members will
; have 3,628,800 permutations and could easily hit AHK's default
; variable limit of 64 MB. My laptop took nearly 3½ minutes to compute
; the permutations for the 10-member sample set (with setbatchlines,-1)

   Size := Set_Size( Set1, PrimaryDelimiter )
   IfLess, Size, 2, Return p . SecondaryDelimiter . Set1 ; only 1 member, so return !
   VarSetCapacity( Set, StrLen(Set1) * Round(Sqrt(Size*6.283)*(Size/2.718)**Size), 0)
   ; This VarSetCapacity mutiplies the length of the input set string
   ; by an approximation of the factorial of 'Size'. Check wikipedia
   ; for 'factorial' to find out more.
   Set1 .= PrimaryDelimiter
   Stuff := StrLen( PrimaryDelimiter )
   Pos := 1 - Stuff
   Lead := 1
   Loop ; separate the set into an array of members
      If ( 0 < Pos := InStr( Set1, PrimaryDelimiter, 1, Pos + Stuff ) )
      {
         StringMid, member%A_Index%, Set1, %Lead%, Pos - Lead
         Lead := Pos + Stuff
      }
      Else Break

   Loop %Size% ; for each member, generate the permutation of the
   {           ; other members and append that onto our result
      Pos := member1
      Loop % Size-1
      {
         Lead := A_Index + 1
         member%A_Index% := member%Lead%
         leftover := ( A_Index = 1 ? member%A_Index%
            : leftover . PrimaryDelimiter . member%A_Index% )
      }
      member%Size% := Pos

      Set .= PrimaryDelimiter . Set_Permutations( leftover, PrimaryDelimiter, SecondaryDelimiter , ( StrLen(p) ? p SecondaryDelimiter : "" ) . member%Size% )
   }
   StringTrimLeft, Set, Set, %Stuff%
   Return Set
}

Set_Power( Set1, PrimaryDelimiter="`n", SecondaryDelimiter="," ) {
; Returns the power set of 'Set1'. In other words, every distinct combination
; of members from 'Set1' ( separated by 'SecondaryDelimiter' ) is returned in
; a list with a size equal to 2^(||Set1||). Also, the resulting list is in
; order by number of sub-members in each member, starting with zero (null)
   Size := Set_Size( Set1, PrimaryDelimiter )
   VarSetCapacity( Set, StrLen(Set1) * ( 1 << Size ), 0 )
   Loop, %Size%
      Set .= PrimaryDelimiter . Set_Combinations( Set1, A_Index, PrimaryDelimiter, SecondaryDelimiter )
   Return Set
}

Set_Remove( Set1, Set2, PrimaryDelimiter="`n" ) {
; Performs a set intersection of 'Set1' and the complement of 'Set2'
   Set1 .= PrimaryDelimiter
   Set2 := PrimaryDelimiter . Set2 . PrimaryDelimiter
   VarSetCapacity( Set, StrLen( Set1 ) )
   Stuff := StrLen( PrimaryDelimiter )
   Pos := 1 - Stuff
   Lead := 1
   Loop
      If ( 0 < Pos := InStr( Set1, PrimaryDelimiter, 1, Pos + Stuff ) )
      {
         StringMid, member, Set1, %Lead%, Pos - Lead
         Lead := Pos + Stuff
         If !InStr( Set2, PrimaryDelimiter . member . PrimaryDelimiter, 1 )
            Set .= PrimaryDelimiter . member
      }
      Else Break
   StringTrimLeft, Set, Set, %Stuff%
   Return Set
}

Set_Transpose( Set1, PrimaryDelimiter="`n", SecondaryDelimiter="," ) {
; Flips a set so that the columns become the rows.
; Any mising members will be made blank.
   VarSetCapacity( Set, StrLen( Set1 ))
   Set1 .= PrimaryDelimiter
   Stuff := StrLen( PrimaryDelimiter )
   iStuff := StrLen( SecondaryDelimiter )
   Pos := 1 - Stuff
   Lead := 1
   w := 0
   Loop ; convert the set into a local array
      If ( 0 < Pos := InStr( Set1, PrimaryDelimiter, 1, Pos + Stuff ) )
      {
         StringMid, member, Set1, %Lead%, Pos - Lead
         i := A_Index
         Lead := Pos + Stuff
         member .= SecondaryDelimiter
         ilead := 1
         ipos := 1 - istuff
         Loop
            If ( 0 < ipos := InStr( member, SecondaryDelimiter, 1, ipos + Stuff ) )
            {
               StringMid, member%i%_%A_Index%, member, %ilead%, ipos - ilead
               ilead := ipos + iStuff
               If ( A_Index > w )
                  w := A_Index
            }
            Else Break
         member := A_Index
      }
      Else Break
   Loop, %w%
   {
      i := A_Index
      Loop, %member%
         Set .= ( A_Index = 1 ? PrimaryDelimiter : SecondaryDelimiter ) . member%A_Index%_%i%
   }
   StringTrimLeft, Set, Set, %Stuff%
   Return Set
}

Set_Size( Set, PrimaryDelimiter="`n" ) {
; Returns the total number of members in 'Set'. NOTE: an empty string
; always contains ZERO members, while any non-empty string contains
; a MINIMUM of ONE member.
   If ( StrLen( Set ) = 0 )
      Return 0
   oscs := A_StringCaseSense
   StringCaseSense, On
   oel := ErrorLevel
   StringReplace, Set, Set, %PrimaryDelimiter%, %PrimaryDelimiter%, UseErrorLevel
   StringCaseSense, %oscs%
   Return ErrorLevel + 1, ErrorLevel := oel
}

Set_Union( Set1, Set2, PrimaryDelimiter="`n" ) {
; Returns the set which is the union of the members in Set1 and Set2
; This function also removes duplicate members in the union.
; ( Removing duplicates is really the point of this function )
   Set1 .= PrimaryDelimiter
   If StrLen( Set2 ) > 0
      Set1 .= Set2 . PrimaryDelimiter
   VarSetCapacity( Set, StrLen( Set1 ) )
   Stuff := StrLen( PrimaryDelimiter )
   Pos := 1 - Stuff
   Lead := 1
   Loop
      If ( 0 < Pos := InStr( Set1, PrimaryDelimiter, 1, Pos + Stuff ) )
      {
         StringMid, member, Set1, %Lead%, Pos - Lead
         Lead := Pos + Stuff
         If !InStr( Set . PrimaryDelimiter, PrimaryDelimiter . member . PrimaryDelimiter, 1 )
            Set .= PrimaryDelimiter . member
      }
      Else Break
   StringTrimLeft, Set, Set, %Stuff%
   Return Set
}

Set_Zip( Set1, Set2, PrimaryDelimiter="`n", SecondaryDelimiter="," ) {
; Returns a new set where the 'N'th member is a concatenation of
; the 'N'th member of Set1, SecondaryDelimiter, and the 'N'th member of Set2
; If a set doesn't have an 'N'th member, its 'N'th member is
; considered blank.
   Set1 .= PrimaryDelimiter
   Set2 .= PrimaryDelimiter
   VarSetCapacity( Set, StrLen( Set1 ) + StrLen( Set2 ) )
   Stuff := StrLen( PrimaryDelimiter )
   Pos1 := Pos2 := 1 - Stuff
   Lead1 := Lead2 := Out1 := Out2 := 1
   Loop
      If ( 0 < Pos1 := Out1 * InStr( Set1, PrimaryDelimiter, 1, Pos1 + Stuff ) )
       + ( 0 < Pos2 := Out2 * InStr( Set2, PrimaryDelimiter, 1, Pos2 + Stuff ) )
      {
         If ( Out1 := ( Pos1 != 0 ) )
            StringMid, member1, Set1, %Lead1%, Pos1 - Lead1
         Else
            member1 := ""
         Lead1 := Pos1 + Stuff

         If ( Out2 := ( Pos2 != 0 ) )
            StringMid, member2, Set2, %Lead2%, Pos2 - Lead2
         Else
            member2 := ""
         Lead2 := Pos2 + Stuff

         Set .= PrimaryDelimiter . member1 . SecondaryDelimiter . member2
      }
      Else Break
   StringTrimLeft, Set, Set, %Stuff%
   Return Set
}

Set_SampleSet( n ) {
; Here are 8 sample sets for use in testing various parts of this library
   Return n = 3 ? "
( LTRIM
                  False
                  [VxE]
                  True
)" : n = 4 ? "
( LTRIM
                  Cherry
                  Tangerine
                  Chocolate
                  BubbleGum
)" : n = 5 ? "
( LTRIM
                  Butterfinger
                  3 Musketeers
                  Milky Way
                  Baby Ruth
                  Kit Kat
)" : n = 6 ? "
( LTRIM
                  Puppet
                  Roller Skates
                  Guitar
                  Slingshot
                  Bandage
                  Handcuffs
)" : n = 7 ? "
( LTRIM
                  Katar
                  Cutlass
                  Gladius
                  Flamberge
                  Dirk
                  Stiletto
                  Claymore
)" : n = 8 ? "
( LTRIM
                  Baby Ruth
                  Twix
                  Kit Kat
                  Butterfinger
                  100 Grand
                  3 Musketeers
                  Almond Joy
                  Milky Way
)" : n = 9 ? "
( LTRIM
                  Horse
                  Turtle
                  Gibbon
                  Elephant
                  Kitten
                  Chicken
                  Hampster
                  Crocodile
                  Pigeon
)" : n = 10 ? "
( LTRIM
                  Rabbit
                  Monkey
                  Pony
                  Kitten
                  Puppy
                  Seal
                  Goat
                  Chicken
                  Piglet
                  Donkey
)" : "0`n1"
}


[Edit: 2-10-2010] Set functions
Code:
;
; Set functions library (Upgraded), By [VxE]
;
; Introduction:
;      Sets are an important concept in OOP, data management, and
;      discrete mathematics. This function library allows you to
;      define sets of string objects and perform basic set functions
;      on them. Additionally, this library offers two functions for
;      handling multi-dimensional sets: Set_Zip joins two sets
;      on a 1:1 basis and Set_Column extracts a set from a complex
;      set. The real power behind this library is the ability to use
;      any string as a delimiter, rather than just a single character.
;      This feature makes it easy to work with data collections in
;      multiple text formats and to construct multi-dimensional sets
;      without limits.
;
; Definitions:
;      a 'delimiter' is a substring with a length greater than zero.
;      a 'member' is a string within a 'set' bounded by delimiters and/or
;         the ends of the string.
;      a 'set' is a string containing zero or more members, each separated
;         from the previous and next member by an instance of a delimiter.
;
; Functions:
;      Set_Column
;      Set_Delimit
;      Set_GetPos
;      Set_GetPosRegEx
;      Set_Intersect
;      Set_Member
;      Set_Remove
;      Set_Size
;      Set_Union
;      Set_Zip
;
; Notes:
;      All string comparisons are case sensitive with the exception of
;      Set_GetPosRegEx, which leaves case sensitivity up to the regex.
;      When using Set_GetPosRegEx, it is highly recommended to use the
;      'S' option in the needleregex since the function loops RegexMatch
;      internally and therefore can be very slow.

Set_Column( Set1, column, PD="`n", SD="," ) {
; Returns a set which is comprised of the 'column'th sub-member of
; each of 'Set1's members. Essentially, if each member were like a
; row in a table, this function would pull a column out of that table.
   VarSetCapacity( Set, StrLen( Set1 ))
   column := Floor( column )
   Set1 .= PD
   Stuff := StrLen( PD )
   iStuff := StrLen( SD )
   Pos := 1 - Stuff
   Lead := 1
   Loop
      If ( 0 < Pos := InStr( Set1, PD, 1, Pos + Stuff ) )
      {
         StringMid, member, Set1, %Lead%, Pos - Lead
         Lead := Pos + Stuff
         member .= SD
         ilead := 1
         ipos := 1 - istuff
         Loop
            If ( 0 < ipos := InStr( member, SD, 1, ipos + Stuff ) )
            {
               StringMid, imember, member, %ilead%, ipos - ilead
               ilead := ipos + iStuff
               If ( A_Index < column )
                  Continue
               Set .= PD . imember
               Break
            }
            Else Break
      }
      Else Break
   StringTrimLeft, Set, Set, %Stuff%
   Return Set
}

Set_Delimit( Set1, NewD, PD="`n" ) {
; Replaces every instance of 'PD' in 'Set1' with 'NewD', effectively
; changing the set's delimiter.
   oel := ErrorLevel
   StringReplace, Set1, Set1, %PD%, %NewD%, All
   Return Set1, ErrorLevel := oel
}

Set_GetPos( Set1, string, PD="`n" ) {
; Returns the index of the first member of 'Set1' that is an exact
; match of 'string'. The return value is zero if there is no match.
   If ( 1 >= Pos := InStr( PD . Set1 . PD, PD . string . PD, 1 ) )
      Return Pos
   StringLeft, Set1, Set1, % Pos - 1
   Return Set_Size( Set1, PD)
}

Set_GetPosRegEx( Set1, NeedleRegex, PD="`n" ) {
; Returns the index of the first member of 'Set1' that is a match
; of 'NeedleRegex'. The return value is zero if there is no match.
; NOTE: the regex needle should not account for the delimiters.
   Stuff := StrLen( PD )
   Set1 .= PD
   Pos := 1 - Stuff
   Lead := 1
   Loop
      If ( 0 < Pos := InStr( Set1, PD, 1, Pos + Stuff ) )
      {
         StringMid, member, Set1, %Lead%, Pos - Lead
         Lead := Pos + Stuff
         If RegexMatch( member, NeedleRegex )
            Return A_Index
      }
      Else Break
   Return 0
}

Set_Intersect( Set1, Set2, PD="`n" ) {
; Performs a set intersection of 'Set1' and 'Set2'. Only the members
; that are in both sets will be in the resulting set.
   If ( Set_Size( Set1 ) > Set_Size( Set2 ) )
      Set := Set2, Set2 := Set1, Set1 := Set
   VarSetCapacity( Set, StrLen( Set1 ), 0)
   Set1 .= PD
   Set2 := PD . Set2 . PD
   Stuff := StrLen( PD )
   Pos := 1 - Stuff
   Lead := 1
   Loop
      If ( 0 < Pos := InStr( Set1, PD, 1, Pos + Stuff ) )
      {
         StringMid, member, Set1, %Lead%, Pos - Lead
         Lead := Pos + Stuff
         If InStr( Set2, PD . member . PD, 1 )
            Set .= PD . member
      }
      Else Break
   StringTrimLeft, Set, Set, %Stuff%
   Return Set
}

Set_Member( Set1, Which, PD="n" ) {
; Returns the 'Which'th member of Set1. A 'Which' less than 1 is
; considered an offset from the last member ('0' being the last)
   Len := Set_Size( Set1, PD )
   Which := Floor( Which )
   If ( Which <= 0 ) && ( Len + Which > 0 )
      Which := Len + Which
   If ( Which > Len ) || ( Which <= 0 )
      Return ""
   Set1 .= PD
   Stuff := StrLen( PD )
   Pos := 1 - Stuff
   Lead := 1
   Loop
      If ( 0 < Pos := InStr( Set1, PD, 1, Pos + Stuff ) )
      && ( A_Index < which )
         Lead := Pos + Stuff
      Else Break
   StringMid, member, Set1, %Lead%, Pos - Lead
   Return member
}

Set_Remove( Set1, Set2, PD="`n" ) {
; Performs a set intersection of 'Set1' and the complement of 'Set2'
   Set1 .= PD
   Set2 := PD . Set2 . PD
   VarSetCapacity( Set, StrLen( Set1 ) )
   Stuff := StrLen( PD )
   Pos := 1 - Stuff
   Lead := 1
   Loop
      If ( 0 < Pos := InStr( Set1, PD, 1, Pos + Stuff ) )
      {
         StringMid, member, Set1, %Lead%, Pos - Lead
         Lead := Pos + Stuff
         If !InStr( Set2, PD . member . PD, 1 )
            Set .= PD . member
      }
      Else Break
   StringTrimLeft, Set, Set, %Stuff%
   Return Set
}

Set_Size( Set, PD="`n" ) {
; Returns the total number of members in 'Set'. NOTE: an empty string
; always contains ZERO members, while any non-empty string contains
; a MINIMUM of ONE member.
   If ( StrLen( Set ) = 0 )
      Return 0
   oscs := A_StringCaseSense
   StringCaseSense, On
   oel := ErrorLevel
   StringReplace, Set, Set, %PD%, %PD%, UseErrorLevel
   StringCaseSense, %oscs%
   Return ErrorLevel + 1, ErrorLevel := oel
}

Set_Union( Set1, Set2, PD="`n" ) {
; Returns the set which is the union of the members in Set1 and Set2
; This function also removes duplicate members in the union.
; ( Removing duplicates is really the point of this function )
   Set1 .= PD
   If StrLen( Set2 ) > 0
      Set1 .= Set2 . PD
   VarSetCapacity( Set, StrLen( Set1 ) )
   Stuff := StrLen( PD )
   Pos := 1 - Stuff
   Lead := 1
   Loop
      If ( 0 < Pos := InStr( Set1, PD, 1, Pos + Stuff ) )
      {
         StringMid, member, Set1, %Lead%, Pos - Lead
         Lead := Pos + Stuff
         If !InStr( Set . PD, PD . member . PD, 1 )
            Set .= PD . member
      }
      Else Break
   StringTrimLeft, Set, Set, %Stuff%
   Return Set
}

Set_Zip( Set1, Set2, PD="`n", SD="," ) {
; Returns a new set where the 'N'th member is a concatenation of
; the 'N'th member of Set1, SD, and the 'N'th member of Set2
; If a set doesn't have an 'N'th member, its 'N'th member is
; considered blank.
   Set1 .= PD
   Set2 .= PD
   VarSetCapacity( Set, StrLen( Set1 ) + StrLen( Set2 ) )
   Stuff := StrLen( PD )
   Pos1 := Pos2 := 1 - Stuff
   Lead1 := Lead2 := Out1 := Out2 := 1
   Loop
      If ( 0 < Pos1 := Out1 * InStr( Set1, PD, 1, Pos1 + Stuff ) )
       + ( 0 < Pos2 := Out2 * InStr( Set2, PD, 1, Pos2 + Stuff ) )
      {
         If ( Out1 := ( Pos1 != 0 ) )
            StringMid, member1, Set1, %Lead1%, Pos1 - Lead1
         Else
            member1 := ""
         Lead1 := Pos1 + Stuff

         If ( Out2 := ( Pos2 != 0 ) )
            StringMid, member2, Set2, %Lead2%, Pos2 - Lead2
         Else
            member2 := ""
         Lead2 := Pos2 + Stuff

         Set .= PD . member1 . SD . member2
      }
      Else Break
   StringTrimLeft, Set, Set, %Stuff%
   Return Set
}

_________________
Ternary (a ? b : c) guide     TSV Table Manipulation Library
Post code inside [code][/code] tags!


Last edited by [VxE] on March 3rd, 2010, 4:26 am, edited 3 times in total.

Report this post
Top
 Profile  
Reply with quote  
PostPosted: April 4th, 2008, 8:38 pm 
Offline
User avatar

Joined: October 7th, 2006, 8:45 am
Posts: 3328
Location: Simi Valley, CA
[Edit: Update ( 6-3-08 )]
Code:
; [VxE]'s Number Wheel Script
; Updated version of number control spinner
; Hover the mouse over an edit control with a number in
; its text and the scrollwheel can change the number
SetTimer, CheckMouseOverControl, 50
*WheelUp::
*WheelDown::
CheckMouseOverControl:
MouseGetPos,,,oWin,oCon
ControlGetText, cs, %oCon%, AHK_ID %oWin%
If !InStr(oCon, "Edit") || StrLen(cs) > 199
{
   If (WheelsOnOff != "off")
   {
      WheelsOnOff := "off"
      Hotkey, *Wheelup, *WheelUp, % WheelsOnOff
      Hotkey, *WheelDown, *WheelDown, % WheelsOnOff
   }
}
else
{
   If (WheelsOnOff != "on")
   {
      WheelsOnOff := "on"
      Hotkey, *Wheelup, *WheelUp, % WheelsOnOff
      Hotkey, *WheelDown, *WheelDown, % WheelsOnOff
   }
   If (A_ThisLabel = "CheckMouseOverControl")
      return

   InPos := OutPos := 0   ; operate on first number found
   Loop, Parse, cs
   {
      np := Asc(A_LoopField)
      If ( np >= 45 && np <= 57 && np != 47 )
         If ( InPos = 0 )
            InPos := OutPos := A_Index
         else
            OutPos := (A_Index-Outpos-1) ? OutPos : A_Index
   }
   np := SubStr( cs, InPos, OutPos - InPos + 1 )
   tic := (InStr(np, ".") ? np/20 : Ceil(np/20))
   If (!GetKeyState("Shift") || !tic )
      tic := 1
   If (GetKeyState("Ctrl"))
      tic := 0.001 + GetKeyState("shift") * 0.024
   np -= tic * ((!InStr(A_ThisHotkey, "up")) * 2 - 1 )
   If InStr( np, "." )
      Loop 9
         If !SubStr(np,0)
            StringTrimRight, np, np, 1
         else
            break
   ControlSetText, %oCon%, % SubStr(cs,1,InPos-1) np SubStr(cs,OutPos+1),AHK_ID %oWin%
}
return


new version (above) replaces old version (below).
Changes 1: Uses a timer to watch the mouse cursor to see if it's over a valid control, then if it is, the wheel keys become active and block the wheel events from reaching the target window, thus preventing any native wheel support the target app might have for such controls. To bypass this, simply put the control in focus and move the cursor off the control before using the mousewheel (that allows the wheel event to reach the app's window).
2: To adjust the rate faster (5%), hold [shift] while scrolling. To force adjustments by 0.001, hold [ctrl]. To force an increment of 0.025, hold [ctrl][shift].
3: This script is meant to make adjusting numbers in edit controls easier for someone using a laptop (no numpad) and a logitech mouse with flywheel scrolling.

[End Edit]

Numerical Control Spinner. This script simulates the ability of the scroll wheel to adjust numbers in edit boxes. This behavior is commonly seen in programs like photoshop, where there are a number of edit boxes for brush settings and stuff. This script operates on the control that is currently under the mouse cursor, so if an edit box already has the wheelie change built in, this script will interfere with that (just don't hover the mouse over those controls and it will work OK)

The Default increment is 1, although I have the script set to increase this increment to 5% of the current value if the user waits for 2 seconds between two wheel ticks. The incrementing value can be reset to 1 by activating any other non-wheel hotkey.

Additional Support Idea for Future Update: Support selecting a number in text and changing it with the scrollwheel.
Code:
; Auto spinners for numerical controls
~*LButton::return
~*WheelUp::
~*WheelDown::
MouseGetPos, X, Y, oWin, oCon
If !InStr(oCon, "Edit") ; we only want spinners to work on edit
   return ; controls, not for things like buttons and such
ControlGetText, gvar, %oCon%, AHK_ID %oWin%
ovar := gvar ; chop up a copy
Loop 8 ; provide accomodation to remove stupid words after numbers in the
   If ( ovar + 1 = "" ) ; edit box like "inches" or "pixels"
      ovar := SubStr(ovar, 1, -1)
   else
      break
If ( ovar + 1 != "" ) ; so, our edit control contains a number, brilliant!
{
   gvar := SubStr(gvar, StrLen(ovar)) ; remove the number part
   If !InStr(A_PriorHotkey, "~*Whee") ; use of a non-wheel hotkey will
      uinc := 1 ; reset the step size to 1
   Else If A_TimeSincePriorHotkey > 2000 ; wait for 2 seconds to set the
      uinc := ovar // 20 ; step size to approx 5% of the current value
   ovar += ((A_ThisHotkey = "~*WheelUp")*2-1) * uinc * ((uinc > 0)*2-1) + (uinc + 0.0 = 0)
   ControlSetText, %oCon%, % ovar gvar, AHK_ID %oWin% ; note the %ovar%%gvar%...
}
return

_________________
Ternary (a ? b : c) guide     TSV Table Manipulation Library
Post code inside [code][/code] tags!


Last edited by [VxE] on June 4th, 2008, 7:37 am, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
PostPosted: April 4th, 2008, 8:47 pm 
Offline
User avatar

Joined: October 7th, 2006, 8:45 am
Posts: 3328
Location: Simi Valley, CA
My Encryption Function... this examples has a simple gui but you can strip out the functions if you'd like. The function's parameters are as follows: str, str, bool.
The first parameter is the key (i.e. password), the second is the message, the third is a switch to specify wither forwards or backwards.

I have added another function () for users who desire greater readability. All that function does is call the main function with the 3rd parameter set to "1".

The only difference between 'encryption' and 'decryption' is the direction of the algorithm. In other words, 'decryption' is the inverse function of 'encryption' and vice versa ad infinitum.
Code:
; [VxE]'s Double-Dynamic Key-Based Encryption Script
; A fully functional security script for protecting text
; version 1.b, Optimized key handling for large keys
; last edit: [7-10-08]

#SingleInstance force
wid := A_ScreenWidth // 2
bwid := (wid - 100) // 5
cwid := wid // 5
dwid := wid - 100
edh := A_ScreenHeight //100
Gui, font, s16, Arial
Gui, Add, Text, w90, Key
Gui, Add, Edit, X100 R1 vMyKey Y10 W%dwid%
Gui, Add, Edit, +wrap R%edh% vInMessage X10 W%wid%
Gui, Add, Edit, Disabled +wrap R%edh% vOutMessage X10 W%wid%
Gui, Add, Button, w%bwid% x25 gEncrypt, Encrypt
Gui, Add, Button, w%bwid% yp xp+%cwid% gDecrypt, Decrypt
Gui, Add, Button, w%bwid% yp xp+%cwid% gSwap, Swap Fields
Gui, Add, Button, w%bwid% yp xp+%cwid% gcopy, Copy Text
Gui, Add, Button, w%bwid% yp xp+%cwid% gGuiClose, &Quit
Gui, Show, AutoSize, [VxE]'s Double-Dynamic Key-Based Encryption Function
return
GuiClose:
GuiEscape:
exitapp

copy:
Swap:
GuiControlGet, OutMessage,,
If A_ThisLabel = copy
   StringReplace, clipboard, OutMessage, `n, `r`n, all
else
{
   GuiControlGet, InMessage,,
   StringReplace, OutMessage, OutMessage, `r`n, `n, all
   StringReplace, InMessage, InMessage, `r`n, `n, all
   GuiControl,, InMessage, %OutMessage%
   GuiControl,, OutMessage, %InMessage%
}
return

Decrypt:
Encrypt:
GuiControlGet, MyKey,,
GuiControlGet, InMessage,,
GuiControl,, OutMessage, % Encrypt( mykey, InMessage, A_ThisLabel )
return

; Readability consideration, example:
; result := Decrypt( key, message ) ; will attempt to decrypt the message
Decrypt( key, message, optional = "" )
{
   return Encrypt( key, message, !optional )
}

; Param 3 is a binary switch to determine this function's direction.
; [blank], [0], or ["e*"] yields forwards, anything else yields backwards.
; Readability consideration: simply omit the third parameter and use "Decrypt()" to decrypt.
Encrypt(key, message, CryptEvent = "")
{ ; CryptEvent defaults to 'encrypt', but really only the first letter is needed
   LowerBound = 34
   UpperBound = 126
   StringReplace, Message, Message, `r`n, `n, all
   StringLeft, CryptEvent, CryptEvent, 1
   If !CryptEvent
      CryptEvent = e
   Loop, parse, key
      key .= "`n" Asc(A_LoopField)
   key := SubStr(key, InStr(Key, "`n",0,1)+1)
   NewMessage =
   Loop, Parse, Message
   {
      code := Asc(A_LoopField)
      If ( code >= LowerBound ) && ( code <= UpperBound )
      {
         mco := code
         prevc := A_Index
         newkey := ""
         Loop, Parse, key, `n
            code := Clamp(( code - (A_LoopField * ( Mod(A_LoopField, 2)
            * 2 - 1 )) * ((CryptEvent = "e") * 2 - 1) ), LowerBound, UpperBound )
         If CryptEvent = e
            mco := code
         Loop, Parse, key, `n
            newkey .= "`n" (prevc := Clamp((A_LoopField + mco * (Mod((mco
            +Prevc), 2) * 2 - 1) + Prevc), 1, 255))
         key := SubStr( newkey, 2 )
      }
      NewMessage .= Chr(code)
   }
return % NewMessage
}


clamp( number, low, high ) ; altered mutation of Mod() function
{ ; 7-10-2008 edit:
   span := (high - low + (high > low)*2 - 1)
   return number + span * Round(((low-number)/2 + (high-number)/2)/span)
}

_________________
Ternary (a ? b : c) guide     TSV Table Manipulation Library
Post code inside [code][/code] tags!


Last edited by [VxE] on July 10th, 2008, 10:10 pm, edited 3 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject: Joystick to Numberpad
PostPosted: April 4th, 2008, 8:52 pm 
Offline
User avatar

Joined: October 7th, 2006, 8:45 am
Posts: 3328
Location: Simi Valley, CA
G-Functions: make your gui controls trigger a function in the same manner as they would trigger a g-label.
Code:
; G-Functions: Set up gui controls with a function instead of a g-label. This technique
; was proposed by yanjchan # http://www.autohotkey.com/forum/viewtopic.php?t=53227
; though there have been several threads asking for functions to be associated with
; gui controls the way g-labels can. Format a gui control's options like this example:
;     Gui, Add, Edit, gGFunctionHandler vFunction[%A_Now%?#this#?#A_GuiControl#]
; In this example, 'Function' is the name of a function in the script, %A_Now% is
; resolved when the control is added to the gui. #this# is resolved when the g-label
; triggers (and it becomes the contents of the control, via GuiControlGet). Similarly,
; #A_GuiControl# is resolved when the g-label triggers and it becomes the exact string
; following the 'v' in the example. The question marks delimit the parameters the way
; commas delimit parameters in a function call.

GFunctions() { ; For library inclusion, name this file "GFunctions.ahk".
; Calling this function returns the name of the label needed to use g-functions.
   Return "GFunctionHandler"
}

GFunctionHandler:
   Critical
   ErrorLevel := GFunctionHandler(A_GuiControl)
   If InStr( ErrorLevel, "Error: " ) = 1
      MsgBox, %ErrorLevel%
Return

GFunctionHandler(¿f) {
; This function examines a control's variable name and constructs a function
; call with parameters based on it.
   Local ¿0, ¿1, ¿2, ¿3, ¿4, ¿5, ¿6, ¿7, ¿8, ¿9, ¿10, ¿11, ¿12, ¿13
   , ¿14, ¿15, ¿16, ¿17, ¿18, ¿19, ¿20, ¿21, ¿22, ¿23, ¿24, ¿25, ¿26
   , ¿27, ¿28, ¿29, ¿30, ¿31, ¿32, ¿33, ¿34, ¿35, ¿36, ¿37, ¿38, ¿39
   , ¿40, ¿41, ¿42, ¿43, ¿44, ¿45, ¿46, ¿47, ¿48, ¿49, ¿50, ¿51, ¿52
   , ¿53, ¿54, ¿55, ¿56, ¿57, ¿58, ¿59, ¿60, ¿61, ¿62, ¿63, ¿64, this

   If RegexMatch( ¿f, "[^\w@$?#\[\]\x80-\xff]")
      Return "Error: Invalid G-Function"
   ; error: the input contains an illegal character

   GuiControlGet, ¿0, HWND, %¿f% ; get the HWND of the control
   VarSetCapacity( ¿1, 256, 0 ) ; make space in this variable
   ; get the control class name for this control
   DllCall("GetClassName", "uint", ¿0, "str", ¿1, "int", 255 )
   If ( ¿1 == "SysListView32" ) ; it's a listview
      Gui, Listview, %¿f%
   Else If ( ¿1 == "SysTreeView32" ) ; it'a a treeview
      Gui, Treeview, %¿f%
   Else If ( ¿1 != "" ) ; Load the reserved variable 'this'
      GuiControlGet, this,, %¿f%

   If InStr( ¿f, "]", 0, 0 ) == StrLen( ¿f )
   { ; parse the parameters listed in the g-function
      ¿0 := SubStr( ¿f, ¿1 := InStr( ¿f, "[" ) + 1, -1 )
      StringLeft, ¿f, ¿f, % ¿1 - 2
      ¿1 := ""

      Loop, Parse, ¿0, ?
      {
         StringReplace, ¿0, A_LoopField, #, `%, all
         Transform, ¿%A_Index%, DEREF, %¿0%
         If ( 64 <= ¿0 := A_Index ) ; we have a hard limit of 64 parameters
            Break
      }
   }
   Else ; the g-function specifies no parameters
      ¿0 := 0
    If StrLen( ¿f ) == 0
      Return "Error: The G-Function name is blank"

   StringReplace, ¿f, ¿f, #, #, UseErrorLevel
   If !Mod( ErrorLevel, 2 ) && Errorlevel > 0
   {
      StringReplace, ¿f, ¿f, #, `%, All
      Transform, ¿f, DEREF, %¿f%
   }

; ¿0 contains the number of parameters in the g-function. Now check the function name
   If ( 0 < this := IsFunc( ¿f )) ; if the function exists...
   && ( this-1 <= ¿0 ) ; ... and we have enough parameters, then do it
      Return %¿f%( ¿1, ¿2, ¿3, ¿4, ¿5, ¿6, ¿7, ¿8, ¿9, ¿10, ¿11, ¿12, ¿13
         , ¿14, ¿15, ¿16, ¿17, ¿18, ¿19, ¿20, ¿21, ¿22, ¿23, ¿24, ¿25, ¿26
         , ¿27, ¿28, ¿29, ¿30, ¿31, ¿32, ¿33, ¿34, ¿35, ¿36, ¿37, ¿38, ¿39
         , ¿40, ¿41, ¿42, ¿43, ¿44, ¿45, ¿46, ¿47, ¿48, ¿49, ¿50, ¿51, ¿52
         , ¿53, ¿54, ¿55, ¿56, ¿57, ¿58, ¿59, ¿60, ¿61, ¿62, ¿63, ¿64 )
Return this ? "Error: Not enough parameters in the g-function"
      : "Error: The g-function does not exist"
}

_________________
Ternary (a ? b : c) guide     TSV Table Manipulation Library
Post code inside [code][/code] tags!


Last edited by [VxE] on February 11th, 2010, 8:29 am, edited 4 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject: Clipboard Execute
PostPosted: April 4th, 2008, 9:11 pm 
Offline
User avatar

Joined: October 7th, 2006, 8:45 am
Posts: 3328
Location: Simi Valley, CA
A more recent manifestation of one of my earlier scripts. This script attempts to run the contents of the clipboard as an AHK script with added safeguards and self-cleaning features.

Update: 1-10-10. New version (5).

Features:
- Any number of files may be included (via #Include) in the script generated by the ClipEx function. See the comments regarding the 'ClipEx_Includes' variable
- Certain keywords are under the 'Blacklist' variable, if any of those words are found on the clipboard, a confirmation dialogue will ask whether you wish to run the code anyways.
- The script file that is generated each time the function runs is deleted if it is no longer running.
- Script files are given unique names
- When executing code with a gui, the label "GuiClose" is added if it isn't already in the code. The label is followed by "Exitapp"
- The format of this code is flow-neutral, meaning that it will not interrupt the Auto-Execute section if placed there (or anywhere else, for that matter).
Code:
; ClipEx5
; Clipboard Execute, version 5 (by [VxE])
; To use: call the function ClipEx() from anywhere in your script.
; Reserved global variable: "ClipEx_p" -> contains a list of active PIDs and script file paths.
; Reserved label: "ClipEx_check_existence" -> parses "ClipEx_p" and cleans up once scripts have finished.
ClipEx()
{
   Global ClipEx_p
   Static IsInitialized, ClipEx_Lifespan, ClipEx_CancelKey, Keywords_Blacklist
   , ClipEx_Includes, Blacklist_Warning, Write_Run_Delay
   If ! IsInitialized
   { ; begin static initialization
      Write_Run_Delay = 50 ; milliseconds to wait between writing the clipex file and running it
      ClipEx_Lifespan = 60 ; seconds until the script terminates unconditionally
      ClipEx_CancelKey = Esc ; put a hotkey here to be a killswitch for the script
      Keywords_Blacklist =
      ( ltrim C
; ClipEx will show a confirmation MsgBox before running code which contains any of these words.
         regwrite
         filedelete
         A_Startup
         shutdown
;         onexit
         UrlDownloadToFile
      )
      Blacklist_Warning =
      ( ltrim % join`s
            The word%plural% "%Matched_Blacklist%" %was_were%
            found in the clipboard.`nThis could cause
            undesired or malicious effects if run.
           
            `n`nDo you wish to continue ?
      )
      ClipEx_Includes =
      ( ltrim C
; List here all files, or directories containing .ahk files, that should be
; #included in the ClipEx script. There is no message when any of these fails.
; These are checked / updated on the fly, and non-absolute paths use the current working directory
      %A_MyDocuments%\AutoHotkey\MyProject\Functions ; default example
; Also see 'libraries of functions' in AutoHotkey.chm
      )
      IsInitialized = 1
   } ; end static initialization

   Thread, NoTimers ; cuz we don't need interruptions

; Use the current working direcrtory for non-absolute paths to #include
   ClipEx_included := ""
   Loop, Parse, ClipEx_Includes, `n, `r %A_Tab%
      If InStr( ClipEx_m := FileExist( A_LoopField ), "D" ) ; if the file is a directory
         Loop, % A_LoopField . ( SubStr( A_LoopField, 0 ) = "\" ? "" : "\" ) . "*.ahk"
            ClipEx_included .= "`r`n#Include, " A_LoopFileLongPath
      Else   If (ClipEx_m)
            ClipEx_included .= "`r`n#Include, " A_LoopField
   
   ClipEx_Template = ; load the template
   ( ltrim
; [VxE]'s ClipEx, version 5.
; This file was generated by inserting the clipobard's text into a template
      SetTimer, ClipEx_Cleanup, -%ClipEx_LifeSpan%000
      Hotkey, %ClipEx_CancelKey%, ClipEx_Cleanup, on
; This is the beginning of the clipboard's text
      %Clipboard%
; This is the end of the clipboard's text.
      ClipEx_Cleanup: ; this label is called by a timer set at the top of the script
      critical
      Exitapp
; #Included Files
      %ClipEx_included%
   )

; Automatically replace the cleanup label with 'guiclose' if the clipboard contains
; 'Gui' but does not contain 'guiclose'. This is simply a convenience so that the
; script will exit when you close the clipex Gui, instead of simply hiding the gui
; and waiting for its lifespan to run out
   If InStr( ClipEx_Template, "Gui" ) && !InStr( ClipEx_Template, "GuiClose:" )
      StringReplace, ClipEx_Template, ClipEx_Template, ClipEx_Cleanup, GuiClose, All

; Check the script text for any blacklisted words
   Matched_Blacklist := "", plural := 0
   Loop, parse, Keywords_Blacklist, `n
      If InStr(ClipEx_Template, A_LoopField)
         Matched_Blacklist .= A_Tab . A_LoopField, plural++
   StringTrimLeft, Matched_Blacklist, Matched_Blacklist, 1
   Loop, % plural - 2 ; replace all but the last delimiter with ", "
      StringReplace, Matched_Blacklist, Matched_Blacklist, %A_Tab%, % """, """

; Replace the last delimiter with " and ". This is only a superficial feature
   StringReplace, Matched_Blacklist, Matched_Blacklist, %A_Tab%, " and "
   If plural ; if there are more then zero blacklisted words in the script
   {
      was_were := plural = 1 ? "was" : "were" ; what it is
      plural := plural = 1 ? "" : "s" ; gramMaR!
         Transform, text, DEREF, %Blacklist_Warning%
      MsgBox, 52, Security Warning !!, %text% ; show a msgbox with the warning
      IfMsgBox, No ; the user decided not to run the code after all
         return
   }

   ClipEx := "ClipEx" . A_Now . SubStr( A_TickCount, -2 ) . ".ahk"
   FileAppend, %ClipEx_Template%, %ClipEx%
   Sleep %Write_Run_Delay%
   Run, %A_AhkPath% "%ClipEx%",,, ClipEx_m ; keep the PID of the spawned script
   ClipEx_p .= ClipEx_m . "?" . ClipEx . "`n" ; append it to our list
   SetTimer, ClipEx_check_existence, 200
return
} ; end of ClipEx() function

Loop 0 ; this causes script execution to skip the following block
{
   ClipEx_check_existence:
; Check our spawned ClipEx processes. Once the process terminates, delete the ClipEx file
      DetectHiddenWindows, on
      If ( ClipEx_p = "`n" )
         SetTimer, ClipEx_check_existence, off
      Else
         Loop, Parse, ClipEx_p, `n ; parse through the list
         {
            StringSplit, ClipEx_, A_LoopField, ?
            If ClipEx_0 <> 2
               continue
            If !WinExist( "Ahk_PID " ClipEx_1 ) ; if the script's window can't be found
            {
               StringReplace, ClipEx_p, ClipEx_p, `n%A_LoopField%`n, `n
               FileDelete, %ClipEx_2% ; delete it and remove it from our list
            }
         }
   return
}

_________________
Ternary (a ? b : c) guide     TSV Table Manipulation Library
Post code inside [code][/code] tags!


Last edited by [VxE] on January 10th, 2010, 10:50 pm, edited 6 times in total.

Report this post
Top
 Profile  
Reply with quote  
PostPosted: April 4th, 2008, 9:32 pm 
Offline
User avatar

Joined: October 7th, 2006, 8:45 am
Posts: 3328
Location: Simi Valley, CA
Don't know what a word means? Just Control+Double-Click it (while this script is running)

The variable at the top (page) contains the URL for the results page of a dictionary or search page, some other popular ones are listed in comments below. To use a different search site, simply go to that site, type in a unique word into the search field, click 'search', then get the URL from the results page and replace your unique word with []MySearchTarget[] and put that into the script.
Code:
; [VxE]'s Ctrl+DblClick word lookup script
page = http://dictionary.cambridge.org/results.asp?searchword=[]MySearchTarget[]&x=48&y=1
; page = http://www.merriam-webster.com/dictionary/[]MySearchTarget[]
; page = http://www.google.com/search?hl=en&q=[]MySearchTarget[]&btnG=Google+Search
; page = http://search.yahoo.com/search?p=[]MySearchTarget[]&fr=yfp-t-501&toggle=1&cop=mss&ei=UTF-8
; page = http://en.wikipedia.org/wiki/Special:Search?search=[]MySearchTarget[]&fulltext=Search

~^LButton::
MouseGetPos, px, py
pm := px . py
If    ( A_PriorHotkey = A_ThisHotkey )
     && (A_TimeSincePriorHotkey < DllCall("GetDoubleClickTime"))
     && (om = pm) ; if the mouse moved, it wasn't a double-click
{
   Sleep 150
   sclip := clipboardall
   Clipboard := ""
   Send ^c
   Clipwait, 1
   StringReplace, specpage, page, []MySearchTarget[], %Clipboard%
   Clipboard := sclip
   Run %specpage% ; open page in default browser
}
Else
   om := pm
return

_________________
Ternary (a ? b : c) guide     TSV Table Manipulation Library
Post code inside [code][/code] tags!


Report this post
Top
 Profile  
Reply with quote  
 Post subject: Unicode in gui controls
PostPosted: April 4th, 2008, 9:35 pm 
Offline
User avatar

Joined: October 7th, 2006, 8:45 am
Posts: 3328
Location: Simi Valley, CA
These functions are workarounds for using unicode in various circumstances. They are as follows:
Quote:
A2W( byref string ) - converts an ansi string that contains html-unicode into a bona fide wide-char string. Note that AHK will no longer be able to manipulate it as a string.
ControlSetTextW( Control OR HWND, string ) - Converts 'string' into a wide-char string and sets the designated control's text to that string.
ControlGetTextW( Control OR HWND ) - Retrieves wide-char text from a control and converts it into a mix of ascii and html-type character codes.
FileReadU( filepath ) - Returns the text inside the designated .txt file. It can handle files that contain unicode characters by converting such characters into their html-type codes.

Code:
A2W( byref str ) ; Ascii to Wide-char. Version 2.0
{ ; function by [VxE], changes a string into unicode format. Uses html-style
; codes for unicode characters (i.e. &#x1234; or &#12345; ). Intended for
; external functions (via DllCall). Return value is the number of characters.
   text := str
   u := v := pos := 0
   Loop
      If (pos := InStr( text, "&#", 0, pos+1 ))
      && (pos2 := InStr( text, "`;", 0, pos ))
      {
         If (num := Abs("0" . SubStr( text, pos+2, pos2-pos-2 )))
         {
            u++
            u%u% := num
            StringReplace, text, text, % SubStr(text, pos, pos2-pos+1), % chr(4)
         }
      }
      Else   Break
   VarSetCapacity(str, 2+2*len:=StrLen(text), 0) ; make space and wipe bits
   Loop, Parse, text
      If (num := Asc(A_LoopField)) = 4
         v++, NumPut( u%v%, str, 2*A_Index-2, "UShort" )
      Else   NumPut( num, str, 2*A_Index-2, "UShort" )
   return len
}
Code:
; Unicode ControlSetText. Note: when using a ClassNN as the 'control' parameter
; this function tries to find it on the Last Found Window. Preceed any such calls
; with a command that updates the Last Found Window, such as IfWinExist
ControlSetTextW( control, newtext="" ) ; For best results, use the control's hwnd as the 'control' parameter
{
   If control is INTEGER
      hwnd := control
   Else   ControlGet, hwnd, hwnd,, %control%
   A2W( newtext )
   Return DllCall("SendMessageW", "uint", hwnd, "int", 0xC, "int", 0, "int", &newtext )
}
Code:
; Unicode ControlGetText. Note: when using a ClassNN as the 'control' parameter
; this function tries to find it on the Last Found Window. Preceed any such calls
; with a command that updates the Last Found Window, such as IfWinExist
ControlGetTextW( control ) ; For best results, use the control's hwnd as the 'control' parameter
{
   Static SizeLimit := 65536 ; aka 64 KB
   If control is INTEGER
      hwnd := control
   Else   ControlGet, hwnd, hwnd,, %control%
   oif := A_FormatInteger
   SetFormat, IntegerFast, D
   VarSetCapacity( text, SizeLimit, 0 )
   Size := DllCall("SendMessageW", "uint", hwnd, "int", 0xD, "int", SizeLimit//2, "int", &text )
   VarSetCapacity( control, Size, 0 ) ; because of gradual concatenation
   Loop %Size%
      If ( Num := NumGet( text, 2*A_Index-2, "UShort" ) )
         If ( Num < 0x100 )
            control .= Chr(Num)
         Else
            control .= "&#" Num "`;"
   SetFormat, IntegerFast, %oif%
   return control
}
Code:
; Save to file named "FileReadU.txt" in a lib folder or resource folder
; This function set reads notepad's .txt files and replaces any unicode
; characters with their html codes (i.e. "&#12345;" )

FileReadU( filepath, ForceType="Auto: BOM" ) ; reads a txt file (notepad) even if it is in unicode format
{ ; function by [VxE], Version 1.3. Read the file and its BOM. Then, based on the BOM
 ; decode any unicode ( if there is any ). Supports all 4 of notepad's available formats,
 ; including Big-Endian Unicode and UTF-8.
 ; For filetypes without a BOM, specify ForceType = "UTF-8" or "Unicode" or "Big-endian Unicode"
 ;
   FileGetSize, size, %filepath%
   FileRead, file, %filepath%
   oif := A_FormatInteger
   SetFormat, IntegerFast, D
   Type := NumGet( file, 0, "UShort" )
   T2 := NumGet( file, 2, "UChar" )
   ErrorLevel := Size
   If Instr( ForceType, "Big" )
      ErrorLevel := TxUnicodeBe( file, 0, size )
   Else If InStr( ForceType, "UTF-8" ) = 1
      ErrorLevel := TxUTF_8( file, 0, size )
   Else If InStr(ForceType, "Unicode") = 1
      ErrorLevel := TxUnicodeLe( file, 0, size )
   Else If ( Type = 0xBBEF ) && ( T2 = 0xBF ) ; UTF-8 BOM
      ErrorLevel := TxUTF_8( file, 2, size )
   Else If (Type = 0xFEFF) ; 'normal' unicode BOM
      ErrorLevel := TxUnicodeLe( file, 2, size )
   Else If (Type = 0xFFFE) ; big-endian unicode BOM
      ErrorLevel := TxUnicodeBe( file, 2, size )
   SetFormat, Integer, %oif%
   Return file
}

TxUTF_8( byref data, offset=3, size=0 ) ; Transcode a bitstream as though it were
{ ; function by [VxE]. Decode a UTF-8 string
   VarSetCapacity( text, size+0 ? size : VarSetCapacity( data ), 0 )
   Index := 0
   Loop
   If ( ch := NumGet( data, offset++, "UChar" ) )
      If ( 2 = ( ch >> 6 ) ) ; this byte is part of a code sequence
         code := (code << 6) | ( ch & 0x3F )
      Else
      {
         If code
            text .= code < 0x100 ? Chr(code) : "&#" code "`;"
         code := 0
         Index++
         If ( 0x6 = ( ch >> 5 ) ) ; the beginning of a 2-byte sequence
            code := ch & 0x1F
         Else If ( 0xE = ( ch >> 4 ) ) ; the beginning of a 3-byte sequence
            code := ch & 0xF
         Else If ( 0x1E = ( ch >> 3 ) ) ; the beginning of a 4-byte sequence
            code := ch & 0x7
         Else   text .= Chr( ch )
      }
   Else
   {
      data := text . ( code ? "&#" code "`;" : "" )
      return A_Index - 1
   }
}

TxUnicodeBe( byref data, offset=2, size=0 )
{ ; function by [VxE]. Decode a big-endian unicode string
   VarSetCapacity( text, size+0 ? size : VarSetCapacity( data ), 0 )
   Loop
   If ( ch := NumGet( data, 2*A_Index-2+offset, "UShort" ) )
      If !( ch & 0xFF )
         text .= Chr(ch >> 8)
      Else   text .= "&#" (ch >> 8) | ((ch & 255) << 8) "`;"
   Else
   {
      data := text
      return A_Index-1
   }
}

TxUnicodeLe( byref data, offset=2, size=0 )
{ ; function by [VxE]. Decode a little-endian unicode string
   VarSetCapacity( text, size+0 ? size : VarSetCapacity( data ), 0 )
   Loop
   If ( ch := NumGet( data, 2*A_Index-2+offset, "UShort" ) )
      If ( ch < 0x100 )
         text .= Chr(ch)
      Else   text .= "&#" ch "`;"
   Else
   {
      data := text
      return A_Index-1
   }
}

_________________
Ternary (a ? b : c) guide     TSV Table Manipulation Library
Post code inside [code][/code] tags!


Last edited by [VxE] on August 9th, 2009, 9:43 pm, edited 10 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject: Vector Function Library
PostPosted: April 4th, 2008, 9:49 pm 
Offline
User avatar

Joined: October 7th, 2006, 8:45 am
Posts: 3328
Location: Simi Valley, CA
This is my vector function library. I wrote it because I needed easy vector support for some of my other projects. I tried to optimize these functions for speed without sacrificing ease of use. I'm also working on a matrix function library as a companion to this vector lib.

Code:
; [VxE]'s vector function library [10-10-08]
; A collection of vector functions
; A formal vector has the format
;      ##, ##, ##, ##;
; where ## indicates a real number.
; Formalized vector format is used internally to
; increase efficiency. Formalization optimizations
; are not strictly for internal use, if your input
; vectors are in the formal format, you may specify
; 1 as the second parameter to increase performance.
; Supported operations currently include:
;    Float Vect_Item( Vector Index )
;    Float Vect_Len( Vector )
;    Float Vect_Dot( Vector . Vector )
;    Float Vect_Angle(["deg"] Vector . Vector )
;    Vector Vect_Formal( string )
;    Vector Vect_Norm( Vector )
;    Vector Vect_Sub( Vector ... Vector )
;    Vector Vect_Add( Vector ... Vector )
;    Vector Vect_Mult( Vector . Float )
;    Vector Vect_Proj( Vector . Vector )
;    Vector Vect_Reflect( Vector . Vector )
;    Vector Vect_Cross( Vector . Vector )
;

; Returns the Nth member of the input vector
; NOTE: seperate the vector and the index
; by a semicolor or a newline character
; When using a formal vector, you may
; simply use the following format:
; result := Vect_Item( FormalVector . 3, 1 )
; This function will probably never be used
; because you can just use StringSplit and
; put all of the vector's members into vars
Vect_Item(vect, formal=0)
{
   IfNotEqual, formal, 1
   {
      Loop, Parse, vect, `;`n, %A_Space%%A_Tab%`r`,
        IfLess, A_Index, 3, SetEnv, factor%A_Index%, % Vect_Formal(A_LoopField)
         Else Break
      factor2 := SubStr(Factor2, 1, -1+InStr(Factor2, ","))
   } Else StringSplit, factor, vect, `;, %A_Space%%A_Tab%`r`n`,
   
   Loop, Parse, factor1, `,, %A_Space%`;
      IfEqual, A_Index, % Round( factor2 ), return %A_LoopField%
   return ""
}


; Returns the absolute length of the input vector
Vect_Len(vect, formal=0)
{
   off := A_FormatFloat
   SetFormat, Float, 0.15
   IfNotEqual, formal, 1, SetEnv, vect, % Vect_Formal(vect)
   Loop, Parse, vect, `,, %A_Space%`;
      sum += A_LoopField**2
   SetFormat, Float, %off%
   return sqrt(sum)
}

; returns the dot product of the first two vectors.
; the dot product is an easy test of orthogonality
; if the dot product is zero, the two vectors are
; orthogonal (at a right-angle to each other)
Vect_Dot(vlist, formal=0)
{
   off := A_FormatFloat
   SetFormat, Float, 0.15
   IfNotEqual, formal, 1, Loop, Parse, vlist, `;`n, %A_Space%%A_Tab%`r`,
   {
      IfEqual, A_LoopField,, Continue
      IfEqual, True, % !(vect := Vect_Formal(A_LoopField)), continue
      u++
      StringSplit, v%u%d, vect, `,, %A_Space%%A_Tab%`r`;
      IfLess, vorder, % v%u%d0, SetEnv, vorder, % v%u%d0
   }
   else   Loop, Parse, vlist, `;`n, `r%A_Space%%A_Tab%
   {
      IfEqual, A_LoopField,, Continue
      u++
      StringSplit, v%u%d, A_LoopField, `,, `n%A_Space%
      IfLess, vorder, % v%u%d0, SetEnv, vorder, % v%u%d0
   }
   Loop %vorder%
      EnvAdd, acc, v1d%A_Index% * v2d%A_Index%
   SetFormat, Float, %off%
   return acc + 0
}

; returns the angle between the first two vectors in vlist
; Essentially, return the arccosine of the dot product of the
; normals of two vectors.
; default return value is in radians, specify "deg" before
; any vectors to return the angle in degrees. Example:
; ResultInDegrees := Vect_Angle( "deg" Vector1 Vector2 )
Vect_Angle(vlist, formal=0)
{
   off := A_FormatFloat
   SetFormat, Float, 0.15
   deg := u := 1
   IfEqual,True, % InStr(vlist,"deg")
    SetEnv,vlist, % SubStr(vlist,53.3-deg:=45/ATan(1))
   IfNotEqual, formal, 1, Loop, Parse, vlist, `;`n, %A_Space%%A_Tab%`r`,
   {
      IfEqual, A_LoopField,, Continue
      IfEqual, True, % !(vect%u% := Vect_Formal(A_LoopField)), continue
      else u++
   }
   else   Loop, Parse, vlist, `;`n, `r%A_Space%%A_Tab%
      IfEqual, A_LoopField,, Continue
      else vect%u% := A_LoopField ";", u++
   angle := ACos( Vect_Dot( Vect_Norm( vect1, 1 ) . Vect_Norm( vect2, 1 ), 1 ) )
   SetFormat, Float, %off%
   return angle * deg
}


; Formalize a string into a vector by parsing through
; any numeric characters (includes '-' and '.') and
; appending them according to the following rules:
; 0. Characters listed in the second parameter
; are ignored (for instance: commas in large numbers)
; 1. The first semicolon or newline reached marks
; the end of the input string. This is to stop multiple
; vectors from being formalized into a frankenvector
; 2. all non-numeric chars become item breaks
; 3. an item break preceeds every minus sign
; 4. within an unbroken numeric string, the second
; decimal point is dropped along with all chars
; following it until the next item break is reached
; 5. There are no empty vector members unless the
; input contains no numeric characters.
; NOTE: If there is a way to do this in one line
; with regex, I'm not interested! Either release
; it or append it to this library yourself.
Vect_Formal(string, ignorechars="")
{
   Loop, Parse, string, , %ignorechars%
      If A_LoopField !=
         IfEqual, A_LoopField, `;, break
         else   nv .= (u := InStr("-.1234567890", A_LoopField)) ? (u
            =1 ? " " : "") A_LoopField : " "
   Loop, Parse, nv, %A_Space%
      IfEqual, A_LoopField,, Continue
      Else    IfNotEqual, A_LoopField, -
      {
         stringsplit, q, A_LoopField, .
         vect .= ", " q1 + 0 (q0>1 ? "." q2 : "")
      }
   return StrLen(vect) > 3 ? SubStr(vect,3) ";" : ""
}


; Returns the normal of the input vector
Vect_Norm(vect, formal=0)
{
   off := A_FormatFloat
   SetFormat, Float, 0.15
   IfNotEqual, formal, 1, SetEnv, vect, % Vect_Formal(vect)
   len := Vect_Len(vect, 1)
   Loop, Parse, vect, `,, %A_Space%`;
      nv .= ", " A_LoopField / len
   SetFormat, Float, %off%
   return substr(nv,3) ";"
}

; Returns the sum of the first vector and the negatives
; of all subsequent vectors in the list
Vect_Sub(vlist, formal=0)
{
   off := A_FormatFloat
   SetFormat, Float, 0.15
   IfNotEqual, formal, 1, Loop, Parse, vlist, `;`n, %A_Space%%A_Tab%`r`,
   {
      IfEqual, A_LoopField,, Continue
      IfEqual, True, % !(vect := Vect_Formal(A_LoopField)), continue
      u++
      StringSplit, v%u%d, vect, `,, %A_Space%%A_Tab%`r`;
      IfLess, vorder, % v%u%d0, SetEnv, vorder, % v%u%d0
   }
   else   Loop, Parse, vlist, `;`n, `r%A_Space%%A_Tab%
   {
      IfEqual, A_LoopField,, Continue
      u++
      StringSplit, v%u%d, A_LoopField, `,, `n%A_Space%
      IfLess, vorder, % v%u%d0, SetEnv, vorder, % v%u%d0
   }
   Loop %vorder%
   {
      v := A_Index
      Loop %u%
         IfEqual, A_Index, 1, SetEnv, acc, % v1d%v%
         else   EnvSub, acc, % v%A_Index%d%v%
      nv .= ", " acc
   }
   SetFormat, Float, %off%
   return substr(nv,3) ";"
}

; Adds the vectors in the list.
Vect_Add(vlist, formal=0)
{
   off := A_FormatFloat
   SetFormat, Float, 0.15
   IfNotEqual, formal, 1, Loop, Parse, vlist, `;`n, %A_Space%%A_Tab%`r`,
   {
      IfEqual, A_LoopField,, Continue
      IfEqual, True, % !(vect := Vect_Formal(A_LoopField)), continue
      u++
      StringSplit, v%u%d, vect, `,, %A_Space%%A_Tab%`r`;
      IfLess, vorder, % v%u%d0, SetEnv, vorder, % v%u%d0
   }
   else   Loop, Parse, vlist, `;`n, `r%A_Space%%A_Tab%
   {
      IfEqual, A_LoopField,, Continue
      u++
      StringSplit, v%u%d, A_LoopField, `,, `n%A_Space%
      IfLess, vorder, % v%u%d0, SetEnv, vorder, % v%u%d0
   }
   Loop %vorder%
   {
      v := A_Index
      acc := 0
      Loop %u%
         EnvAdd, acc, % v%A_Index%d%v%
      nv .= ", " acc
   }
   SetFormat, Float, %off%
   return substr(nv,3) ";"
}

; Returns the input vector with length
; multiplitd by a factor. NOTE: seperate
; the vector and the factor by a
; semicolor or a newline character
; When using a formal vector, you may
; simply use the following format:
; result := Vect_Mult( FormalVector . 3, 1 )
Vect_Mult(vect, formal=0)
{
   off := A_FormatFloat
   SetFormat, Float, 0.15
   IfNotEqual, formal, 1
   {
      Loop, Parse, vect, `;`n, %A_Space%%A_Tab%`r`,
        IfLess, A_Index, 3, SetEnv, factor%A_Index%, % Vect_Formal(A_LoopField)
         Else Break
      factor2 := SubStr(Factor2, 1, -1+InStr(Factor2, ","))
   } Else StringSplit, factor, vect, `;, %A_Space%%A_Tab%`r`n`,
   
   Loop, Parse, factor1, `,, %A_Space%`;
      nv .= ", " A_LoopField * factor2
   SetFormat, Float, %off%
   return substr(nv,3) ";"
}

; returns a vector describing the projection A onto B
; where A is the first vector in the list and B is the next
; The result is linearly dependant to vector B
Vect_Proj(vlist, formal=0)
{
   u=1
   IfNotEqual, formal, 1, Loop, Parse, vlist, `;`n, %A_Space%%A_Tab%`r`,
   {
      IfEqual, A_LoopField,, Continue
      IfEqual, True, % !(vect%u% := Vect_Formal(A_LoopField)), continue
      else u++
   }
   else   Loop, Parse, vlist, `;`n, `r%A_Space%%A_Tab%
      IfEqual, A_LoopField,, Continue
      else vect%u% := A_LoopField ";", u++
   return Vect_Mult(vect2 . Vect_Dot(vect1 . vect2, 1) / (Vect_Len(vect2, 1)**2), 1)
}

; if the second vector is normal to a plane, and
; the first vector is not paralell to that plane
; then this function returns the first vector
; after it bounces off the plane
; In essense, this function subtracts twice the
; projection of v1 onto v2 from v1, clear?
; Also, the angle between a vector and its reflection
; is exactly equal to twice the angle betwen that
; vector and the normal it is being reflected from
; so, Vect_Angle( v1 v2 ) is the same as
; Vect_Angle( Vect_Reflect( v1 v2 ) v2 )
Vect_Reflect(vlist, formal=0)
{
   u=1
   IfNotEqual, formal, 1, Loop, Parse, vlist, `;`n, %A_Space%%A_Tab%`r`,
   {
      IfEqual, A_LoopField,, Continue
      IfEqual, True, % !(vect%u% := Vect_Formal(A_LoopField)), continue
      else u++
   }
   else   Loop, Parse, vlist, `;`n, `r%A_Space%%A_Tab%
      IfEqual, A_LoopField,, Continue
      else vect%u% := A_LoopField ";", u++
   vx := Vect_Proj(vect1 . vect2, 1)
   return Vect_Sub(vect1 . vx . vx, 1)
}

; returns a vector that is the cross-product of
; the first two vectors in vlist provided that
; those two vectors are independant and are in R3
; Note: the cross product in Rn requires n-1 vectors
; and is produced by calculating the determinants of
; n square matrices of size (n-1)x(n-1)
; For example, in R5...
;
;  v1 = v1a, v1b, v1c, v1d, v1e
;  v2 = v2a, v2b, v2c, v2d, v2e
;  v3 = v3a, v3b, v3c, v3d, v3e
;  v4 = v4a, v4b, v4c, v4d, v4e
; Cross = I,   J,   K,   L,   M
; I = Det( v1b, v1c, v1d, v1e; v2b, v2c, v2d, v2e; v3b, v3c, v3d, v3e; v4b, v4c, v4d, v4e)
; J = Det( v1c, v1d, v1e, v1a; v2c, v2d, v2e, v2a; v3c, v3d, v3e, v3a; v4c, v4d, v4e, v4a)
; K = Det( v1d, v1e, v1a, v1b; v2d, v2e, v2a, v2b; v3d, v3e, v3a, v3b; v4d, v4e, v4a, v4b)
; L = Det( v1e, v1a, v1b, v1c; v2e, v2a, v2b, v2c; v3e, v3a, v3b, v3c; v4e, v4a, v4b, v4c)
; M = Det( v1a, v1b, v1c, v1d; v2a, v2b, v2c, v2d; v3a, v3b, v3c, v3d; v4a, v4b, v4c, v4d)
; where Det() is the determinate of the specified matrix
; And for large n's, the fastest way to get the determinant
; is through row-reduction to row-echelon form and then
; multiply along the diagonal. Since row-reduction would
; have a big-O notation of O(n²) whereas finding
; the determinate by laplace expansion would have a
; big-O of O(n!) (and that's really bad!!)
;
Vect_Cross(vlist, formal=0) ; WARNING: R3 supported only!!!!
{
   off := A_FormatFloat
   SetFormat, Float, 0.15
   IfNotEqual, formal, 1, Loop, Parse, vlist, `;`n, %A_Space%%A_Tab%`r`,
   {
      IfEqual, A_LoopField,, Continue
      IfEqual, True, % !(vect := Vect_Formal(A_LoopField)), continue
      u++
      StringSplit, v%u%d, vect, `,, %A_Space%%A_Tab%`r`;
   }
   else   Loop, Parse, vlist, `;`n, `r%A_Space%%A_Tab%
   {
      IfEqual, A_LoopField,, Continue
      u++
      StringSplit, v%u%d, A_LoopField, `,, `n%A_Space%
   }
   vr := (v1d2 * v2d3 - v1d3 * v2d2) ", "
   vr .= (v1d3 * v2d1 - v1d1 * v2d3) ", "
   vr .= (v1d1 * v2d2 - v1d2 * v2d1) ";"
   SetFormat, Float, %off%
   return vr
}

_________________
Ternary (a ? b : c) guide     TSV Table Manipulation Library
Post code inside [code][/code] tags!


Last edited by [VxE] on October 10th, 2008, 11:13 am, edited 3 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: June 7th, 2008, 4:44 am 
Offline
User avatar

Joined: October 7th, 2006, 8:45 am
Posts: 3328
Location: Simi Valley, CA
This script turns the 4 arrow keys into the number keys on the numberpad. Press one or two arrow keys to get the appropriate numpad number or pgup/home/end or numpadarrows (depending on the numlock state). Feel free to change the actual toggle to something other than Numlock (the appskey is pretty handy ;)). Also the alternate functions can be easily customized.
Code:
; [VxE]'s Arrow Keys To Numpad Multiplexer.
ArrowKeys = Up,Left,Down,Right
NumPadAliases = End,Down,PgDn,Left,NumpadClear,Right,Home,Up,PgUp
StringSplit, k, ArrowKeys, `,
StringSplit, NumAlias, NumPadAliases, `,
NumAlias0 = Ins ; I'd recommend 'BackSpace' as it seems more useful
Loop, Parse, ArrowKeys, `,
   Hotkey, $*%A_LoopField%, $*Up, on
$*Up::
mark := SubStr(((sk1:=GetKeyState(k1,"P"))-(sk3:=GetKeyState(k3,"P"))+1)*3
+(sk4:=GetKeyState(k4,"P"))-(sk2:=GetKeyState(k2,"P"))+2-5*(!sk2 & !sk4 & sk1 & sk3),0)
If (!InThread)
{
   InThread = 1
   Sleep 40 ; delay to allow coordination of multiple keys
   If (GetKeyState("NumLock", "T")) ; put any toggle you want
      Send {blind}{NumPad%mark%}
   else
      Send % "{blind}{" NumAlias%mark% "}" ; "{blind}{Numpad" NumAlias%mark% "}"
   InThread = 0
}
return

_________________
Ternary (a ? b : c) guide     TSV Table Manipulation Library
Post code inside [code][/code] tags!


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: June 8th, 2008, 7:24 am 
Offline
User avatar

Joined: October 7th, 2006, 8:45 am
Posts: 3328
Location: Simi Valley, CA
I know that RGB to HSV has been done before in AHK (props, tonne), but here's another manifestation of it which handles hex-code BGR (like what PixelGetColor returns) as well as the reverse: HSL to BGR

Code:
Hue(BGR) ; Hue: output range [0,360) float
{ ; Function by [VxE], formula from wikipedia.org/wiki/HSV_color_space
   OFF := A_FormatFloat
   SetFormat, Float, 0.16
;   pi := ATan(1) * 4
   pi := 360 / 2 ; what do you consider a full circle ? 360º or 2pi ?
   hex := pi / 3
   blue := (BGR >> 16) / 256
   green := ((BGR >> 8) & 255) / 256
   red := (BGR & 255) / 256
   max := ((blue > green) && (blue > red)) ? blue : (green > red ? green : red)
   min := ((blue < green) && (blue < red)) ? blue : (green < red ? green : red)
   If (min = max)
      res := 0
   else If (max = red)
      res := hex * ((green - blue) / (max - min))
   else If (max = green)
      res := hex * ((blue - red) / (max - min)) + 2 * hex
   else If (max = blue)
      res := hex * ((red - green) / (max - min)) + 4 * hex
   If (res >= 2 * pi )
      res -= 2 * pi
   If (res < 0 )
      res += 2 * pi
   SetFormat, Float, %OFF%
   return res
}
Code:
Sat(BGR) ; Saturation: output range [0,1)
{ ; Function by [VxE], formula from wikipedia.org/wiki/HSV_color_space
   OFF := A_FormatFloat
   SetFormat, Float, 0.16
   blue := (BGR >> 16) / 256
   green := ((BGR >> 8) & 255) / 256
   red := (BGR & 255) / 256
   max := ((blue > green) && (blue > red)) ? blue : (green > red ? green : red)
   min := ((blue < green) && (blue < red)) ? blue : (green < red ? green : red)
   lum := (min + max) / 2
   If (min = max)
      res := 0
   else If (lum <= 0.5)
      res := (max - min) / (2*lum)
   else
      res := (max - min) / (2-2*lum)
   SetFormat, Float, %OFF%
   return res
}
Code:
Lum(BGR) ; output range [0,1)
{ ; Function by [VxE], formula from wikipedia.org/wiki/HSV_color_space
   OFF := A_FormatFloat
   SetFormat, Float, 0.16
   blue := (BGR >> 16) / 256
   green := ((BGR >> 8) & 255) / 256
   red := (BGR & 255) / 256
   max := ((blue > green) && (blue > red)) ? blue : (green > red ? green : red)
   min := ((blue < green) && (blue < red)) ? blue : (green < red ? green : red)
   res := (min + max) / 2
   SetFormat, Float, %OFF%
   return res
}
Code:
HSL_to_RGB( hue, sat, lum ) ; inputs should be [0,360) : [0,1) : [0,1), output = 24b hex BGR
{ ; Function by [VxE], formula from wikipedia.org/wiki/HSV_color_space
   OFF := A_FormatFloat
   SetFormat, Float, 0.16
   If ( lum < 0.5 )
      weight := Lum + Lum * Sat
   else
      weight := Lum + Sat - Lum * Sat
   size := 2 * Lum - weight
   value := hue / 360
   red := value + 1/3 - (value > 2/3)
   green := value
   blue := value - 1/3 + (value < 1/3)

   If (blue < 1/6)
      blue := (blue * 6 * (weight - size)) + size
   else if (blue < 1/2)
      blue := weight
   else if (blue < 2/3)
      blue := ((2/3 - blue) * 6 * (weight - size)) + size
   else
      blue := size

   If (green < 1/6)
      green := (green * 6 * (weight - size)) + size
   else if (green < 1/2)
      green := weight
   else if (green < 2/3)
      green := ((2/3 - green) * 6 * (weight - size)) + size
   else
      green := size

   If (red < 1/6)
      red := (red * 6 * (weight - size)) + size
   else if (red < 1/2)
      red := weight
   else if (red < 2/3)
      red := ((2/3 - red) * 6 * (weight - size)) + size
   else
      red := size

   OIF := A_FormatInteger
   SetFormat, Integer, Hex
   ret := (Round(blue*256) << 16) | (Round(green*256) << 8) | Round(red*256)
   SetFormat, Float, %OFF%
   SetFormat, Integer, %OIF%
   ret := "0x" SubStr( "00000" SubStr(ret, 3), -5 )
   StringUpper, ret, ret
   return ret
}

And of course, the accessory function
Code:
FlipBlueAndRed(c) ; takes RGB or BGR and swaps the R and B
{
   return (c&255)<<16 | (c&65280) | (c>>16)
}

_________________
Ternary (a ? b : c) guide     TSV Table Manipulation Library
Post code inside [code][/code] tags!


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 29 posts ]  Go to page 1, 2  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: Google [Bot], Yahoo [Bot] and 7 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