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 XOP

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.


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.


/U disables additional messages.


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



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.


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???


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].


This function calls the Close Window dialog that asks the user if he/she would like to save a recreation macro.


operationNameStr The name of the recreation macro initially displayed in the dialog.


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)



return 0


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:


return 2

case 1:


case 2:



if (cmpstr(S_FnName,WinStr))

DoWindow/F $WinStr

DoWindow/C $S_FnName


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


end function

function/S SWXRecreation(WinName)

string WinName

string theMacro = WinRecreation(WinName,0)

variable insert = strsearch(theMacro,"\rEndMacro\r",0)

if (insert < 0)

return ""


return (theMacro[0,insert-1]+"\r\tSetWindowExt kwTopWin"+theMacro[insert,strlen(theMacro)])



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