The SetWindowExt XOP allows the window hook function specified using the SetWindow operation to respond to keyboard events, mouse wheel events, and all mouse button events. Unfortunately, this XOP is only for Windows users.
If you have any problems with this XOP, please e-mail Christopher Neese.
The XOP and its source code can be downloaded via the links below.
Download SetWindowExt Source Code
SetWindowExt XOP
SetWindowExt (SWX) is an external operation that extends the functionality the SetWindow command by sending more events to a windows hook function. SWX also adds two external functions, SetProcedureText, and DoRecreationDialog which are useful in fully enabling Igor Pro experiments that use SWX.
This version of SetWindowExt has been tested only on Igor Pro 4.0, but likely works for Igor Pro 3.13 and higher. Please note that SetWindowExt is strictly a Windows-based XOP. SWX relies heavily on the Windows API, thus a Macintosh version would need to be written from scratch and quite likely would provide slightly different functionality. SWX has been tested on Windows 95 and Windows 2000. Because SWX relies on the Windows API, it may perform differently with different versions of Windows.
Revision Notes
1.00 SetWindowExt first released.
SetWindowExt [/U] winName
The SetWindowExt operation enables (disables) additional messages to a window's hook function.
Parameters
winName The name of a graph, panel, layout, or table window. winName can be the keyword kwTopWin to specify the topmost graph, panel, layout, or table window.
Flags
/U disables additional messages.
Details
SetWindowExt uses the hook function specified by the SetWindow command. It is not possible to use SetWindowExt
without first calling SetWindow.
Because, SetWindowExt duplicates the functionality of SetWindow with
hookevents=1, it is recommended that only hookevents=0 or hookevents=2 be used
with SetWindowExt. If your hook
function is receiving duplicate mouse events, this is the likely problem.
If the window has no hook
function, SetWindowExt gracefully does nothing. If the hook function does not exist, or is invalid SetWindowExt
prints "Warning: SetWindowExt cannot reach hook function." in the experiment's history area.
SetWindowExt remains active
until a SetWindowExt/U command is issued, or the window is killed. SetWindowExt does remain active between Igor
Pro sessions. See Adding SetWindowExt to a Recreation Macro for the code to add SetWindowExt to the end of a
recreation macro.
The hook function is called by
Igor when various window events take place. Igor tells the hook function why it
is being called by storing an event code in the hook function's infoStr
parameter. This is used for advanced user controls.
The hook function has the
following syntax:
Function procName (infoStr)
String infoStr
String event= StringByKey("EVENT",infoStr)
...
return statusCode // 0 if nothing done, else 1 or 2
End
infoStr is a string which will contain a semicolon separated list of key :value pairs:
WINDOW:winName name of the window.
EVENT:eventKey eventKey identifies the event:
close the OS is requesting that the window be closed.
mousedown when the left mouse button is clicked.
mousedblclk when the left mouse button is released.
mouseup when the left mouse button is released.
rmousedown when the left mouse button is clicked.
rmousedblclk when the left mouse button is released.
rmouseup when the left mouse button is released.
mmousedown when the left mouse button is clicked.
mmousedblclk when the left mouse button is released.
mmouseup when the left mouse button is released.
mousewheel when the mouse wheel is moved (Windows 98 or NT 4.0 or above).
keydown when a non-system key is pressed.
keyup when a non-system key is released.
MODIFIERS:flags Bits set based on state of certain keys:
bit 0 is set if the left mouse button is down.
bit 1 is set if shift key is down.
bit 2 is set if ALT is down.
bit 3 is set if CTRL is down.
bit 4 is set if the right mouse button is down.
bit 5 is set if the middle mouse button is down.
For any mouse event, the following will also be present:
MOUSEX:x pixel x coordinate in pixels of the mouse.
MOUSEY:y pixel y coordinate in pixels of the mouse.
TICKS:time time event happened.
For a mousewheel event, the following will also be present:
DELTA:delta amount the mouse wheel was turned. Currently, this is ±120.
For a key event, the following will also be present:
KEY:keynum Windows virtual key code for
the key. See Windows Virtual Key Codes.
PREV:prevstate 1 if key was previously down, 0
is key was previously up. Use this
value to detect autorepeat.
Note that a mouseup event may or may not correspond to a previous mousedown. If the user clicks in the window, drags out and releases the button then the mouseup event will be missing. If the user clicks in another window, drags into this one and then releases then a mouseup will be sent that had no previous mousedown.
A non-zero return value will cause Igor to skip normal processing of the message. This is most useful with mousedown.
See Also
Operations[SetWindow], Functions[AxisValFromPixel], Functions[NumberByKey], Functions[TraceFromPixel], Functions[StringByKey].
SetProcedureText(procedureNameStr, procedureTextStr, flag)
The ProcedureText function changes or adds a macro or function in the procedure window, returning 0 if successful.
Parameters
procedureNameStr The name of the procedure. This should be identical to the came of the procedure contained in procedureTextStr, but this is not enforced. However, procedureNameStr is the name Igor uses in determining if the procedure already exists.
procedureTextStr The actual text of the procedure. Nothing is done to validate this code.
flag The bits set in flag change the behavior of SetProcedureText:
bit 0 is set to check if procedureNameStr is an existing macro???
bit 1 is set to check if procedureNameStr is an existing function???
bit 2 is set to allow SetProcedureText to overwrite an existing function???
bit 3 is set to allow SetProcedureText to overwrite an existing function???
Details
Set flag to 0 if you do not want to overwrite an existing procedure. Set flag to 255 if you want to overwrite an existing procedure.
SetProcedureText cannot directly be called from a macro
or function, because Igor cannot edit the procedure window and execute compiled
procedures at the same time. However,
SetProcedureText can be indirectly called from a macro or function using Execute/P. See Adding
SetWindowExt to a Recreation Macro for an
example of using SetProcedureText via Execute/P.
See Also
Operations[Execute], Functions[ProcedureText], Functions[WinRecreation].
DoRecreationDialog(operationNameStr)
This function calls the Close Window dialog that asks the user if he/she would like to save a recreation macro.
Parameters
operationNameStr The name of the recreation macro initially displayed in the dialog.
Details
The dialog returns 0 if the user chooses
"Cancel", 1 if the user chooses "Save", 2 if the user
chooses "Replace", or 3 if the user chooses "No Save". The name of the recreation function is
returned via the global variable S_FnName, which is created in the
current Data Folder. Igor does not
process the results of this function.
The primary use of this function is to provide input for the SetProcedureText
function.
See Also
Functions[ProcedureText], Functions[SetProcedureText], Functions[WinRecreation].
Adding SetWindowExt to a Recreation Macro
The SetWindowExt command is not automatically added to a window recreation macro. It is not easily possible for the SWX XOP to accomplish this, because the XOP does not in general know that a window has been killed until after the window has been destroyed. The SWX XOP certainly does not know if the user or a procedure has used the DoWindow command!
This problem can be mostly solved by trapping the
"kill" event in the window hook function and using DoRecreationDialog, SetProcedureText with Execute/P, and WinRecreation.
The functions below
demonstrate how to solve this problem.
SWXHook is a hook function that traps the "kill" event,
calling SWXKillDialog. SWXKillDialog
uses DoRecreationDialog, and SetProcedureText with Execute/P, calling SWXRecreation.
SWXRecreation simply returns the window's recreation macro with "SetWindowExt kwTopWin" inserted right before endMacro.
The functions below do not
check to see if SetWindowExt is actually active for the window. Thus SWXHook should only be used for
functions with SetWindowExt exnabled.
Also, if the window was not created with the /K=1 flag, the user may see
two Close Window dialogs. The first is
from Igor's normal behavior the second is from the DoRecreationDialog
function.
function SWXHook(infoStr)
string infoStr
string winStr = StringByKey("WINDOW",InfoStr)
string eventStr = StringByKey("EVENT",InfoStr)
strswitch (eventStr)
//Handle other events here
case "kill":
return DoRecreationDialog(WinStr)
endswitch
return 0
end
function SWXKillDialog(WinStr)
string WinStr
//This portion of the hook function will make sure that
//SetWindowExt kwTopWin is added to the recreation menu.
//However, if Display, Edit, NewPanel, or NewLayout have
// /K=0, the result will be dual DoRecreationDialogs.
//Because procedure windows cannot be edited while functions
//or macros are running, it is necessary to invoke
//SetProcedureText via Execute/P.
//There is no way to prevent the SetProcedureText command from
// showing in the History window.
switch (DoRecreationDialog(WinStr))
case 0:
//Cancel
return 2
case 1:
//Save
case 2:
//Replace
SVAR/Z S_FnName
if (cmpstr(S_FnName,WinStr))
DoWindow/F $WinStr
DoWindow/C $S_FnName
endif
String/G S_SWX_RecreationMacroText = SWXRecreation(S_FnName)
Execute/P/Z "SetProcedureText(\""+S_FnName+"\",S_SWX_RecreationMacroText,255)"
return 1
case 3:
// No Save
return 0
endswitch
end function
function/S SWXRecreation(WinName)
string WinName
string theMacro = WinRecreation(WinName,0)
variable insert = strsearch(theMacro,"\rEndMacro\r",0)
if (insert < 0)
return ""
else
return (theMacro[0,insert-1]+"\r\tSetWindowExt kwTopWin"+theMacro[insert,strlen(theMacro)])
endif
end
Windows Virtual Key Codes
The Windows virtual key codes are presented below, in a form that can be copied directly into a procedure window. The unusual key codes are commented out. The name of the key that produces the key code on an American keyboard is given when it is not obvious.
//
// Virtual Keys, Standard Set
// Modifed from winuser.h in the Windows API
//The following don't occur as normal keyup and keydown events
//Static Constant VK_LBUTTON = 0x01 //Left Mouse Button
//Static Constant VK_RBUTTON = 0x02 //Right Mouse Button
//Static Constant VK_CANCEL = 0x03 //Ctrl-Break
//Static Constant VK_MBUTTON = 0x04 //Middle Mouse Button
Static Constant VK_BACK = 0x08 //Backspace
Static Constant VK_TAB = 0x09
Static Constant VK_CLEAR = 0x0C //Numeric keypad 5 with Num Lock OFF
Static Constant VK_RETURN = 0x0D
Static Constant VK_SHIFT = 0x10
Static Constant VK_CONTROL = 0x11
Static Constant VK_MENU = 0x12 //Alt
Static Constant VK_PAUSE = 0x13
Static Constant VK_CAPITAL = 0x14 //Caps Lock
//Static Constant VK_KANA = 0x15
//Static Constant VK_HANGUL = 0x15
//Static Constant VK_JUNJA = 0x17
//Static Constant VK_FINAL = 0x18
//Static Constant VK_HANJA = 0x19
//Static Constant VK_KANJI = 0x19
Static Constant VK_ESCAPE = 0x1B
//Static Constant VK_CONVERT = 0x1C
//Static Constant VK_NONCONVERT = 0x1D
//Static Constant VK_ACCEPT = 0x1E
//Static Constant VK_MODECHANGE = 0x1F
Static Constant VK_SPACE = 0x20
Static Constant VK_PRIOR = 0x21 //Page Up
Static Constant VK_NEXT = 0x22 //Page Down
Static Constant VK_END = 0x23
Static Constant VK_HOME = 0x24
Static Constant VK_LEFT = 0x25
Static Constant VK_UP = 0x26
Static Constant VK_RIGHT = 0x27
Static Constant VK_DOWN = 0x28
Static Constant VK_SELECT = 0x29
Static Constant VK_PRINT = 0x2A
Static Constant VK_EXECUTE = 0x2B
Static Constant VK_SNAPSHOT = 0x2C //Print Screen
Static Constant VK_INSERT = 0x2D
Static Constant VK_DELETE = 0x2E
Static Constant VK_HELP = 0x2F
Static Constant VK_0 = 0x30
Static Constant VK_1 = 0x31
Static Constant VK_2 = 0x32
Static Constant VK_3 = 0x33
Static Constant VK_4 = 0x34
Static Constant VK_5 = 0x35
Static Constant VK_6 = 0x36
Static Constant VK_7 = 0x37
Static Constant VK_8 = 0x38
Static Constant VK_9 = 0x39
Static Constant VK_A = 0x41
Static Constant VK_B = 0x42
Static Constant VK_C = 0x43
Static Constant VK_D = 0x44
Static Constant VK_E = 0x45
Static Constant VK_F = 0x46
Static Constant VK_G = 0x47
Static Constant VK_H = 0x48
Static Constant VK_I = 0x49
Static Constant VK_J = 0x4A
Static Constant VK_K = 0x4B
Static Constant VK_L = 0x4C
Static Constant VK_M = 0x4D
Static Constant VK_N = 0x4E
Static Constant VK_O = 0x4F
Static Constant VK_P = 0x50
Static Constant VK_Q = 0x51
Static Constant VK_R = 0x52
Static Constant VK_S = 0x53
Static Constant VK_T = 0x54
Static Constant VK_U = 0x55
Static Constant VK_V = 0x56
Static Constant VK_W = 0x57
Static Constant VK_X = 0x58
Static Constant VK_Y = 0x59
Static Constant VK_Z = 0x5A
Static Constant VK_LWIN = 0x5B
Static Constant VK_RWIN = 0x5C
Static Constant VK_APPS = 0x5D
Static Constant VK_NUMPAD0 = 0x60
Static Constant VK_NUMPAD1 = 0x61
Static Constant VK_NUMPAD2 = 0x62
Static Constant VK_NUMPAD3 = 0x63
Static Constant VK_NUMPAD4 = 0x64
Static Constant VK_NUMPAD5 = 0x65
Static Constant VK_NUMPAD6 = 0x66
Static Constant VK_NUMPAD7 = 0x67
Static Constant VK_NUMPAD8 = 0x68
Static Constant VK_NUMPAD9 = 0x69
Static Constant VK_MULTIPLY = 0x6A
Static Constant VK_ADD = 0x6B
Static Constant VK_SEPARATOR = 0x6C
Static Constant VK_SUBTRACT = 0x6D
Static Constant VK_DECIMAL = 0x6E
Static Constant VK_DIVIDE = 0x6F
Static Constant VK_F1 = 0x70
Static Constant VK_F2 = 0x71
Static Constant VK_F3 = 0x72
Static Constant VK_F4 = 0x73
Static Constant VK_F5 = 0x74
Static Constant VK_F6 = 0x75
Static Constant VK_F7 = 0x76
Static Constant VK_F8 = 0x77
Static Constant VK_F9 = 0x78
Static Constant VK_F10 = 0x79
Static Constant VK_F11 = 0x7A
Static Constant VK_F12 = 0x7B
//Static Constant VK_F13 = 0x7C
//Static Constant VK_F14 = 0x7D
//Static Constant VK_F15 = 0x7E
//Static Constant VK_F16 = 0x7F
//Static Constant VK_F17 = 0x80
//Static Constant VK_F18 = 0x81
//Static Constant VK_F19 = 0x82
//Static Constant VK_F20 = 0x83
//Static Constant VK_F21 = 0x84
//Static Constant VK_F22 = 0x85
//Static Constant VK_F23 = 0x86
//Static Constant VK_F24 = 0x87
Static Constant VK_NUMLOCK = 0x90
Static Constant VK_SCROLL = 0x91 //Scroll Lock