#pragma rtGlobals=1 // Use modern global access method. // ================================================================================================= // // Package: GenericWindowHook.ipf // Author: W. Harneit // Version: March 2011 // // Description: // // - Provides a generic window hook function that monitors events, GenericWinHook(), // and an installer function, InstallGenericWinHook(), that sets up an exterior panel (dubbed here the "event panel"). // - Works for any window that can receive events (Graphs, Tables, Layouts, Panels, Notebooks). // - You can simply use the event panel to examine what really happens to your window while developing your own hook function. // - You can also use the GenericWinHook() code as a starting point for own your hook function. // // Usage: // // - From the command line or from your own function, call // InstallGenericWinHook() // for the top window (Graph, Panel, Table, Layout, or Notebook). // // - You can also provide a target window name (here: Table0) using the optional parameter syntax: // InstallGenericWinHook(winName = "Table0") // // After that, watch what kind of events your target window is receiving in response to user actions (mouse, keyboard, menu, ...) // // Note: Sometimes, several events happen in quick succession, too fast for the eye to follow. // A version of this package with scrollable event log is in preparation... // // Hints: // // - If you install the generic hook in two windows simultaneously, both exterior panels show the same information. The information // shown depends on which window is currently receiving events, i.e., it depends on your mouse position and on which window // is currently on top (i.e., Igor's target window). // This behaviour is intended since it can be instructive to see that windows always receive mouse events when your mouse is // passing over them, regardless of whether the window is the target window or not. It also helps to monitor kill events, which // also kill the exterior panel. Just look at one of the other mirroring event panels, which is the name I give these exterior panels. // // - If you want to have several _independent_ event panels, you need to call the installer function with an // additional optional parameter specifying a global string variable (the full path to that variable is required): // InstallGenericWinHook(hookSVAR = "root:gsMyHookMessage") // This global string variable will be created by installGenericWinHook(), there is no need to create it yourself. // // - If you want to use your own hook function instead of the provided GenericWinHook(), call // InstallGenericWinHook(hookName = "MyWinHook") // // - If you also want to use the messaging feature in your own hook function, call // InstallGenericWinHook(hookName = "MyWinHook", hookSVAR = "MySVAR") // Your hook function should then have the minimum content: // // function MyWinHook(s) // struct WMWinHookStruct &s // SVAR msg = $GetUserData(s.winName, "", "GenHookSVAR") // // msg = "This is my message" // // end // // ================================================================================================= // If you don't like the (default) names I've given the generic hook function and message string var, // please modify the following constants accordingly: strconstant ksGenHookName = "GenericWinHook" strconstant ksGenHookSVAR = "root:gsGenericWinHookMessage" function InstallGenericWinHook([winName, hookName, hookSVAR]) string winName, hookName, hookSVAR winName = SelectString( ParamIsDefault(winName) || (strlen(winName) == 0), winName, StringFromList(0,WinList("*",";","")) ) DoWindow/F/HIDE=0 $winName if( V_Flag ) NewPanel /EXT=0 /HOST=# /N=Events/NA=2 /W=(0,0,231,178) ModifyPanel fixedSize=0 string genHookSVAR = SelectString(ParamIsDefault(hookSVAR), hookSVAR, ksGenHookSVAR) String/G $genHookSVAR TitleBox whsBox, size={0,0}, pos={1,1}, variable = $genHookSVAR SetActiveSubwindow ## SetWindow $winName, userdata(GenHookSVAR) = genHookSVAR SetWindow $winName, hook(GenHookName) = $SelectString(ParamIsDefault(hookName), hookName, ksGenHookName) endif end function GenericWinHook(s) struct WMWinHookStruct &s variable rVal = 0 SVAR msg = $GetUserData(s.winName, "", "GenHookSVAR") sprintf msg, "=====================================\r" sprintf msg, "%s winName = %s\r", msg, s.winName sprintf msg, "%s winRect = top:%g, left:%g, bottom:%g, right:%g\r", msg, s.winRect.top, s.winRect.left, s.winRect.bottom, s.winRect.right sprintf msg, "%s mouseLoc = v:%g, h:%g\r", msg, s.mouseLoc.v, s.mouseLoc.h sprintf msg, "%s ticks = %g (%s)\r", msg, s.ticks, Secs2Time(s.ticks/60,3,1) sprintf msg, "%s event = code:%g, name:%s, mod:%g\r", msg, s.eventCode, s.eventName, s.eventMod sprintf msg, "%s=====================================\r", msg sprintf msg, "%s (user defined) cursor = do set:%g, code:%g\r", msg, s.doSetCursor, s.cursorCode sprintf msg, "%s=====================================\r", msg switch( s.eventCode ) case 0: // "activate" break case 1: // "deactivate" break case 2: // "kill" break case 3: // "mouseDown" break case 4: // "mouseMoved" break case 5: // "mouseUp" break case 6: // "resize" break case 7: // "cursorMoved" sprintf msg, "%s cursor = %s\r", msg, s.cursorName sprintf msg, "%s is free = %g\r", msg, s.isFree sprintf msg, "%s on trace = %s\r", msg, s.traceName sprintf msg, "%s at point number = %g, y:%g\r", msg, s.pointNumber, s.yPointNumber break case 8: // "modified" break case 9: // "enableMenu" break case 10: // "menu" sprintf msg, "%s menu = name:%s, item:%s\r", msg, s.menuName, s.menuItem break case 11: // "keyboard" variable key = s.keycode string keyStr if( key > 32 ) keyStr = num2char(key) elseif( key > 13 ) // 27..32 => 8..13 [ESC, LEFT, RIGHT, UP, DOWN, SPACE] key -= 19 elseif( key > 4 ) // 8..13 => 2..7 [BACKSPACE, TAB, LF, END, PAGEUP, PAGEDOWN, CR] key -= 6 // 10 (LF) will never be generated as a keycode => 4 (end) is safe endif if( key < 14 ) keyStr = StringFromList(key-1, "home;back;tab;end;pgup;pgdn;return;escape;left;right;up;down;space") elseif( key == 92 ) // BACKSLASH keyStr = "\\\\" elseif( key == 127 ) // DELETE keyStr = "delete" endif sprintf msg, "%s keycode = %g ( %s )\r", msg, s.keycode, keyStr break case 12: // "moved" break case 13: // "renamed" sprintf msg, "%s old win name = %s\r", msg, s.oldWinName break case 14: // "subWindowKill" break case 15: // "hide" break case 16: // "show" break case 17: // "killVote" break case 18: // "showTools" break case 19: // "hideTools" break case 20: // "showInfo" break case 21: // "hideInfo" break case 22: // "mouseWheel" sprintf msg, "%s wheel = dy:%g, dx: %g\r", msg, s.wheelDy, s.wheelDx break case 23: // "spinUpdate" endswitch msg = RemoveEnding(msg) return rVal end