Skip to content

Instantly share code, notes, and snippets.

@Aatoz
Last active December 25, 2015 09:59
Show Gist options
  • Save Aatoz/6957863 to your computer and use it in GitHub Desktop.
Save Aatoz/6957863 to your computer and use it in GitHub Desktop.
AutoLeap.ahk
; License: public domain
; Feel free to modify and improve upon the work herein, but be certain to give credit me (Verdlin) when using my scripts
; Credits:
; Tidbit: st.ahk lib
; tkoi: ILButton.ahk
; If you see your work and you are not credit, this is not deliberate. Notify me and I will credit you ASAP
/*
TODOs:
1. Circle gestures will be WAAY more useful if I can post messages while still recording.
For example, lets say the gesture is "Left, Circle." As things stand now, actions are trigerred AFTER the
gesture has been recorded (once no fingers are detected). But what if the action was the resizing of the window?
It would be quite useful if, say, Left, Circle made the window smaller and KEPT on making the window smaller while
the Circle gesture was being performed
*/
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;; By overriding __Delete, we can ensure that GUIs and global objects are automatically destroyed
Leap(hMsgHandlerFunc)
{
; Check to see if core LeapMotion software is even installed on this machine
RegRead, sKey, HKCR, airspace\shell\open\command
if (!InStr(sKey, "Leap Motion"))
{
Msgbox, 4096,, Error! Leap Motion software is required to run this script.
return false
}
global g_hMsgHandlerFunc := hMsgHandlerFunc, g_sLeapWorkingDir := A_ScriptDir "\AutoLeap"
gosub, DoLeap
static base := {__Delete:"Leap_Delete"}
return Object("base", base)
}
;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;
Leap_Delete(v="")
{
global
SetTimer, Record, Off
g_WB := ; Clearing the document does not kill the IE GUI, and the GUI is hidden, so WinKill it
WinKill, Leap Motion JavaScript Sample - Windows Internet Explorer ahk_class IEFrame
return
}
;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;
InitLeap:
{
; Note: with the current design, this tolerance factor is actually ignored
; I do think it will be needed, though, and I am keeping it here so that
; I do not completely forget about it
g_iTolerance := 15
g_asGestures := []
g_bUnfold := true
return
}
;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;
InitOSD:
{
GUI AutoLeapOSD: New, hwndg_hAutoLeapOSD
Gui, +AlwaysOnTop -Caption +Owner +LastFound +ToolWindow +E0x20
WinSet, Transparent, 210
GUI, Color, 202020
GUI, Font, s18 c5C5CF0 wnorm ; c0xF52C5F
GUI, Add, Text, x0 y0 hwndg_hAutoLeapOSDText vg_vAutoLeapOSDText Wrap Center
g_hFont := Fnt_GetFont(g_hAutoLeapOSDText)
g_iMaxWidth := A_ScreenWidth
GUI, AutoLeapOSD:Show, x0 y0 NoActivate
GUI, AutoLeapOSD:Hide ; Not using WinMove for sizing since it activates the window
return
}
;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;
DoLeap:
{
gosub InitLeap
;~ Gui Add, ActiveX, w980 h640 vWB, Shell.Explorer ; The final parameter is the name of the ActiveX component.
global g_WB := ComObjCreate("InternetExplorer.Application") ;// Create an IE object
g_WB.Visible := true ;// Make the IE object visible -- if I can find a way around the annoying block problem, then this can be removed!!
g_WB.Navigate(g_sLeapWorkingDir "\AutoLeap.html") ; This is specific to the web browser control.
WinActivate, Leap Motion JavaScript Sample - Windows Internet Explorer ahk_class IEFrame
Msgbox, 4096,, Click the, "Allow blocked content" button, and then press "OK" on this dialog.
g_WB.Visible := false
gosub InitOSD
; TODO: Is there possibly an OnMessage event that may be hooked on to?
; I really would rather just trigger the Leap routines when they are actually needed
SetTimer, Record
return
}
;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;
Record:
{
try
{
g_wb.document.getElementById("pauseOnGesture").checked
}
catch, sError
{
Tooltip %sError%
return
}
; Ensure we always pause on gestures
if (!g_wb.document.getElementById("pauseOnGesture").checked)
g_wb.document.getElementById("pauseOnGesture").click()
g_sPointableData := g_WB.document.getElementById("pointableData").innerText
g_sGestureData := g_WB.document.getElementById("gestureData").innerText
if (g_sPointableData == A_Blank)
return
g_bFinishedRecording := g_sPointableData = "No pointables" ; Should we finish when there are no fingers or when there are no palms?
if (g_bFinishedRecording)
PostRecordedData()
if (g_sGestureData == "No gestures")
return
; Record new data in g_asGestures
TranslateLeapData(LoadLeapDataIntoIni())
gosub LeapOSD_Update
g_wb.document.getElementById("pause").click() ; Unpause
return
}
;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;
LeapOSD_Update:
{
sGestures := st_glue(g_asGestures, ", ")
if (sGestures == A_Blank)
return
GUI, AutoLeapOSD:Default
rect := Str_MeasureTextWrap(sGestures, g_iMaxWidth, g_hFont)
GUIControl, MoveDraw, g_vAutoLeapOSDText, % "W" rect.right " H" rect.bottom
GUIControl,, g_vAutoLeapOSDText, %sGestures%
if (g_bUnfold)
{
WAnim_FoldOrUnfold(true, rect.right, g_hAutoLeapOSD)
GUI, Show, % "W" rect.right " H" rect.bottom " NoActivate"
g_bUnfold := false
}
else GUI, Show, % "W" rect.right " H" rect.bottom " NoActivate"
; Post data for gesture recorders...
if (g_hMsgHandlerFunc)
g_hMsgHandlerFunc.("Record", g_asGestures, "")
return
}
;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;
PostRecordedData()
{
global g_asGestures, g_hAutoLeapOSD, g_vAutoLeapOSDText, g_bUnfold, g_iMaxWidth, g_hMsgHandlerFunc
if (g_asGestures.MaxIndex())
{
if (g_hMsgHandlerFunc)
{
g_hMsgHandlerFunc.("Post", g_asGestures, sOutput)
if (sOutput)
{
GUI, AutoLeapOSD:Default
GUI, Show, w%g_iMaxWidth% NoActivate
GUIControl,, g_vAutoLeapOSDText, %sOutput%
GUIControl, MoveDraw, g_vAutoLeapOSDText, % "W" g_iMaxWidth
DismissAfter1000MS()
}
else GUI, AutoLeapOSD:Hide
}
else GUI, AutoLeapOSD:Hide
;~ WinGetPos,,,, iH, ahk_id %g_hAutoLeapOSD%
;~ WAnim_SlideViewInOutFrom(false, "Top", 0, -iH, g_hAutoLeapOSD, "AutoLeapOSD", 5)
;~ msgbox ok %ih%
g_bUnfold := true
}
g_asGestures := []
return
}
;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;
DismissAfter1000MS()
{
SetTimer, DismissAfter1000MS, 1000
return
}
DismissAfter1000MS:
{
if (g_bDismiss)
{
g_bDismiss := false
GUI, AutoLeapOSD:Hide
g_bUnfold := true
SetTimer, %A_ThisLabel%, Off
}
else g_bDismiss := true
return
}
;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;; Loads data from g_sPointableData and g_sGestureData into class_EasyIni object
/* sPointableData will be formatted like:
Pointable ID: 96
Belongs to hand with ID: 43
Classified as a finger
Length: 46.5 mm
Direction: (0.18, -0.09, -0.98)
Tip position: (-44.2, 243.2, 16.1) mm
Tip velocity: (-3.3, -10.3, -18.2) mm/s
sGestureData will be formatted like:
"Gesture ID: 8
type: swipe
state: start
hand IDs:
pointable IDs: 65
duration: 0 µs
start position: (-163.8, 115.5, 16.4) mm
current position: (-63.3, 124.8, -41.8) mm
direction: (0.86, 0.08, -0.50)
speed: 2450.3 mm/s"
*/
LoadLeapDataIntoIni()
{
global g_sPointableData, g_sGestureData
FileDelete, copy.ini
vLeapData := class_EasyIni("copy.ini", "")
Loop, Parse, g_sGestureData, `n, `r
{
; For now, don't handle multi-finger gestures
if (A_Index > 1)
return
; Begin "Gesture ID:..." (etc.) parsing
if (SubStr(A_LoopField, 1, 11) = "Gesture ID:")
{
sThisSec := "Gesture" A_Index
Loop, Parse, g_sGestureData, `,
{
/*
1=Gesture ID: 8
2= type: swipe
3= state: start
4= hand IDs:
5= pointable IDs: 65
6= duration: 0 µs
7= start position: (-163.8
8= 115.5
9= 16.4) mm
10= current position: (-63.3
11= 124.8
12= -41.8) mm
13= direction: (0.86
14= 0.08
15= -0.50)
16= speed: 2450.3 mm/s
*/
sTrimmedLoopField := Trim(A_LoopField)
if (A_Index == 1 || A_Index == 4 || A_Index == 5 || A_Index == 6 || A_Index ==16)
continue
else if (A_Index == 2)
vLeapData.AddSection(sThisSec, "Type", SubStr(sTrimmedLoopField, 7))
else if (A_Index == 3)
vLeapData.AddKey(sThisSec, "State", sTrimmedLoopField)
else if (A_Index == 7)
vLeapData.AddKey(sThisSec, "StartX", SubStr(sTrimmedLoopField, 18))
else if (A_Index == 8)
vLeapData.AddKey(sThisSec, "StartY", sTrimmedLoopField)
else if (A_Index == 9)
vLeapData.AddKey(sThisSec, "StartD", SubStr(sTrimmedLoopField, 1, StrLen(sTrimmedLoopField) - 4))
else if (A_Index == 10)
vLeapData.AddKey(sThisSec, "CurX", SubStr(sTrimmedLoopField, 20))
else if (A_Index == 11)
vLeapData.AddKey(sThisSec, "CurY", sTrimmedLoopField)
else if (A_Index == 12)
vLeapData.AddKey(sThisSec, "CurD", SubStr(sTrimmedLoopField, 1, StrLen(sTrimmedLoopField) - 4))
else if (A_Index == 13)
vLeapData.AddKey(sThisSec, "DirX", SubStr(sTrimmedLoopField, 13))
else if (A_Index == 14)
vLeapData.AddKey(sThisSec, "DirY", sTrimmedLoopField)
else if (A_Index == 15)
vLeapData.AddKey(sThisSec, "DirD", SubStr(sTrimmedLoopField, 1, StrLen(sTrimmedLoopField) - 1))
}
}
}
vLeapData.Save()
/*
iPointable := 0
Loop, Parse, g_sPointableData, `n, `r
{
; Direction: (0.18, -0.09, -0.98)
if (SubStr(A_LoopField, 1, 10) = "Direction:")
{
iPointable++
vLeapData.AddKey("Pointable" iPointable, "Direction", A_LoopField, sError)
}
; Tip position: (-44.2, 243.2, 16.1) mm
if (SubStr(A_LoopField, 1, 13) = "Tip position:")
vLeapData["Pointable" iPointable]["Tip"] := A_LoopField
}
*/
return vLeapData
}
;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;
TranslateLeapData(vLeapData)
{
global g_iTolerance, g_asGestures
; For now, gestures are interpeted as linear movements along a 2D plane
; Movements will interpreted as only one of the following:
;1. Left
;2. Right
;3. Up
;4. Down
;5. Circle - TODO: Circle-Left, Circle-Right
;6. KeyTap (A quick Up+Down gesture)
; The disadvance to this approach is that diagnal gestures will be recorded awkwardly
; Eventually, I really hope to allow more advanced gestures,
; but I don't want to bite off more than I can chew
; It is also important to note that AddGesture_Safe is used to ensure that there are no
; repeat gestures, i.e. Right, Right
for sGesture in vLeapData
{
if (vLeapData[sGesture].Type = "Circle")
{
AddGesture_Safe("Circle", g_asGestures)
continue
}
else if (vLeapData[sGesture].Type = "KeyTap")
{
; A Keytap is essentially a Down+Up gesture
AddGesture_Safe("KeyTap", g_asGestures)
continue
}
; Compare directions and give preference the the movement that was greater
if (abs(vLeapData[sGesture].DirX) > abs(vLeapData[sGesture].DirY))
{
if (vLeapData[sGesture].DirX > 0)
AddGesture_Safe("Right", g_asGestures)
else AddGesture_Safe("Left", g_asGestures)
}
else ; Movement along Y axis was greater, so interpret as Up or Down
{
if (vLeapData[sGesture].DirY > 0)
AddGesture_Safe("Up", g_asGestures)
else AddGesture_Safe("Down", g_asGestures)
}
;~ vLeapData[sGesture].DirD
}
return g_asGestures
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;; This function safely prevents recording of double gestures
;;;;;;;;;;;;;; i.e. "RIght, Right" or "Left, Left," etc.
AddGesture_Safe(sGesture, ByRef rasGestures)
{
if (rasGestures[rasGestures.MaxIndex()] != sGesture)
rasGestures.Insert(sGesture)
return
}
;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;~ TranslateLeapData(vLeapData)
;~ {
;~ global g_iTolerance
;~ asGestures := []
;~ for sGesture in vLeapData
;~ {
;~ if ((abs(vLeapData[sGesture].StartX) - abs(vLeapData[sGesture].CurX)) > g_iTolerance)
;~ if (vLeapData[sGesture].DirX > 0)
;~ asGestures.Insert("Right")
;~ else asGestures.Insert("Left")
;~ if ((abs(vLeapData[sGesture].StartY) - abs(vLeapData[sGesture].CurY)) > g_iTolerance)
;~ if (vLeapData[sGesture].DirY > 0)
;~ asGestures.Insert("Up")
;~ else asGestures.Insert("Down")
;~ vLeapData[sGesture].DirD
;~ }
;~ return asGestures
;~ }
;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment