All Manuals > Foreign Language Interface User Guide and Reference Manual > 1 Introduction to the FLI

1.2 Using the FLI to get the cursor position

Note: The rest of the examples in this chapter only work in LispWorks for Windows.

The following example shows how to use the FLI to call a C function in a Win32 library. The function we are going to call returns the screen position of the mouse pointer, or cursor. The example consists of three stages: setting up the correct data types to pass and receive the data, defining and calling a FLI function to call the Win32 function, and collecting the values returned by the Win32 function to find where the cursor is.

1.2.1 Defining FLI types

The example uses the FLI to find the position of the cursor using the Windows function GetCursorPos, which has the following C prototype:

BOOL GetCursorPos( LPPOINT )

The LPPOINT argument is a pointer to the POINT structure, which has the following C definition:

typedef struct tagPOINT {
    LONG x; 
    LONG y; 
} POINT; 

First we use the define-c-typedef macro to define a number of basic types which are needed to pass data to and from the Windows function.

(fli:define-c-typedef bool (:boolean :int))
 
(fli:define-c-typedef long :long)

This defines two types, BOOL and LONG, which are used to associate a Lisp boolean value (t or nil) with a C boolean of type int, and a Lisp bignum with a C long. These are required because the Windows function GetCursorPos returns a boolean to indicate if it has executed successfully, and the cursor's x and y positions are specified in a long format in the POINT structure.

Next, we need to define a structure for the FLI which is used to get the coordinates of the cursor. These coordinates will consist of an x and a y position. We use the define-c-typedef macro for this, and the resulting Lisp FLI code has obvious parallels with the C tagPOINT structure.

(fli:define-c-struct tagpoint
  (x long)
  (y long))

The tagPOINT structure for the FLI, corresponding to the C structure of the same name, has been defined. This now needs to be further defined as a type for the FLI, using define-c-typedef.

(fli:define-c-typedef point (:struct tagpoint))

Finally, a pointer type to point to the structure is required. It is this FLI pointer which will be passed to the Windows function GetCursorPos, so that GetCursorPos can change the x and y values of the structure pointed to.

(fli:define-c-typedef lppoint (:pointer point))

All the required FLI types have now been defined. Although it may seem that there is a level of duplicity in the definitions of the structures, pointers and types in this section, this was necessary to match the data structures of the C functions to which the FLI will interface. We can now move on to the definition of FLI functions to perform the interfacing.

1.2.2 Defining a FLI function

This next step uses the define-foreign-function macro to define a FLI function, or interface function, to be used to call the GetCursorPos function. An interface function takes its arguments, converts them into a C format, calls the foreign function, receives the return values, and converts them into a suitable Lisp format.

(fli:define-foreign-function (get-cursor-position "GetCursorPos")
  ((lp-point lppoint))
  :result-type bool)

In this example, the defined FLI function is get-cursor-position. It takes as its argument a pointer of type lppoint, converts this to a C format, and calls GetCursorPos. It takes the return value it receives from GetCursorPos and converts it into the FLI bool type we defined earlier.

We have now defined all the types and functions required to get the cursor position. The next step is to allocate memory for an instance of the tagPOINT structure using allocate-foreign-object. The following line of code binds location to a pointer that points to such an instance.

(setq location (fli:allocate-foreign-object :type 'point))

Finally, we can use our interface function get-cursor-position to get the cursor position:

(get-cursor-position location)

1.2.3 Accessing the results

The position of the cursor is now stored in a POINT structure in memory, and location is a pointer to that location. To find out what values are stored we use the foreign-slot-value accessor, which returns the value stored in the specified field of the structure.

(fli:foreign-slot-value location 'x)
(fli:foreign-slot-value location 'y)

Foreign Language Interface User Guide and Reference Manual - 01 Dec 2021 19:34:56