llTakeControls(integer controls, integer accept, integer pass_on)

The control functions allow an object to respond to user interface input that normally controls the avatar. For example, this allows creation of a scripted vehicle that moves in response to the keyboard commands that normally move the avatar. Also, a gun can be created that fires in response to mouse button activity.

The controls parameter is an integer bitfield which is used to specify which user-interface controls the script is interested in. Possible values are:

Constant Hex Integer Description
CONTROL_FWD 0x00000001 1 forward control (W or up arrow)
CONTROL_BACK 0x00000002 2 back control (S or down arrow)
CONTROL_LEFT 0x00000004 4 move left control (shift + A or left arrow)
CONTROL_RIGHT 0x00000008 8 move right control (shift + D or right arrow)
CONTROL_UP 0x00000010 16 up control (E or PgUp)
CONTROL_DOWN 0x00000020 32 down control (C or PgDn)
CONTROL_ROT_LEFT 0x00000100 256 rotate left control (A or left arrow)
CONTROL_ROT_RIGHT 0x00000200 512 rotate right control ( D or right arrow)
CONTROL_LBUTTON 0x10000000 268,435,456 left mouse button control
CONTROL_ML_LBUTTON 0x40000000 1,073,741,824 left mouse button control with the avatar in MouseLook See ^Note

To filter multiple button presses, combine these values using the | (bitwise OR) operator. (See below for an example.)

The accept and pass_on parameters take a TRUE or FALSE value and have different effects:

accept pass_on effect
0 0 only specified controls functional…no script events
0 1 no apparent effect (all controls functional)…no script events
1 0 other controls functional no events…specified controls non-functional but generate events
1 1 all controls normal…specified controls also generate events

An object must have permission to take controls. Call llGetPermissions to see if the object has the PERMISSION_TAKE_CONTROLS permission. If it does not, you must first call llRequestPermissions to request permissions from the user.

After this function has been called and depending on the other parameters, the scripts’s control event handler will be invoked whenever a specified input is received. The code you place in the control event handler determines how your object behaves in response to captured user input.

Each call to this function replaces the settings for any previous call. Unfortunately, that means a script can’t completely control some inputs and let others continue to function while getting events. Fortunately there’s a small glitch that is extremely handy since we can’t rotate an avatar with a script. See below for more info.

When done with the controls (for example, when an attachment is removed) it is a good idea to clean up with a call to llReleaseControls.

CONTROL_ML_LBUTTON will cause a “Mouselook” button to appear on the bottom of the SL window, but only if pass_on is set to FALSE.

llTakeControls(CONTROL_ML_LBUTTON, TRUE, FALSE); // this works.
llTakeControls(CONTROL_ML_LBUTTON, TRUE, TRUE); // this doesn't.

Note: There seems to be a bug when taking CONTROL_ML_LBUTTON where it does not produce a MouseLook button after re-attaching even though permitted. Solution:

llRequestPermissions(llGetOwner(), PERMISSION_TAKE_CONTROLS);

Example (see ExampleControls for a functioning script):

run_time_permissions(integer perms)
        integer desired_controls = 
                CONTROL_FWD |
                CONTROL_BACK |
                CONTROL_LEFT |
                CONTROL_RIGHT |
                CONTROL_ROT_LEFT |
                CONTROL_ROT_RIGHT |
                CONTROL_UP |
                CONTROL_DOWN |
                CONTROL_LBUTTON |

        if (perms & PERMISSION_TAKE_CONTROLS) {
            llTakeControls(desired_controls, TRUE, FALSE);

Taking Complete Control

There is a handy glitch that can be used to work around a major shortcoming of the control() system. There are many reasons why you might want to grab all the user input and not allow the standard av motion to take effect. For example, creating a custom movement solution. 

The problem is that avs can not be scripted to rotate so normally using this function to grab all the input controls with accept set to 1 and pass to 0 will prevent a user from turning their av in normal non-mouselook view. You can leave out the right and left rotations but then you won’t get events for them.

The trick is to make two calls to this function with the correct parameters. Using the following example, you’ll take complete control (no normal movement) of all input except for left and right rotation which will behave normally and also generate control() events:

Hopefully if a ‘fix’ is made that changes this, the fix will include the functionality we all want and need.

  • Note by Henri Beauchamp: alas, this hack does not work any more now (tried with v1.26 sim server and v1.22 viewer, both with LSL2 and Mono compiled scripts)
  • Note: llTakeControls(desired_controls, 1,1) will work and will glitch the desired controls. (Tested with v1.22.11 viewer and a sim server. Both with LSL2 and Mono scripts.)
  • Note by goldblaze: There is another way around the issue with mouselook. You can have two scripts, one with the mouselook control on TRUE FALSE, and the rest on the second script with TRUE TRUE. This will let you use controls other then mouselook, and have the normal controls, while at the same time having the mouselook control and buttons. It is not a complete fix, but I hope it helps somewhat. (note: Trying to have the same controls on both scripts will cause it to overwrite the previous control.)

Detecting loss of control 
If someone releases controls after they have been granted, a Call to llGetPermissions compared with PERMISSION_TAKE_CONTROLS will show that the object no longer has permission. This can be done with a timer event.

    touch_start(integer start_param)
        llRequestPermissions(llDetectedKey(0), PERMISSION_TAKE_CONTROLS);
    run_time_permissions(integer perm)
            state controlled;
state controlled
        integer controls = 
            | CONTROL_UP | CONTROL_DOWN;

        llTakeControls(controls, TRUE, FALSE);
        if(llGetPermissions() & PERMISSION_TAKE_CONTROLS)
        state default;


I tried taking all possible controls llTakeControls(~0, FALSE, FALSE), and it seems that there are two undocumented, unnamed control events you can listen for: 0x04000000 and 0x02000000. I can’t figure out when 0x02000000 gets sent, but 0x04000000 seems to be sent in conjunction with normal events when they have been active for longer than about a second.

0x02000000 is if the avatar is turning left
0x04000000 is if the avatar is turning right
those are not about the controls themselves, but the avatar itself rotating.