# control

*LSL event*

```lsl
control(key id, integer level, integer edge)
```

- `key id`: UUID of the avatar whose inputs are captured.
- `integer level`: A bitfield of CONTROL_* constants representing currently held controls.
- `integer edge`: A bitfield of CONTROL_* constants representing controls that just changed state.

Triggered to pass captured avatar control inputs into the script. The parameter level indicates held controls, and edge indicates change in controls (both are bitfields of CONTROL_* constants).

Result of [llTakeControls](/functions/llTakeControls/) library function call and user input.

```lsl title="How to use" frame="terminal"
control(key id, integer level, integer edge)
{

}
```

## Specification

| Constant | Value | Description |
| --- | --- | --- |
| [CONTROL_FWD](/constants/CONTROL_FWD/) | 0x00000001 | Move forward control (<kbd>↑</kbd> or <kbd>W</kbd>) |
| [CONTROL_BACK](/constants/CONTROL_BACK/) | 0x00000002 | Move back control (<kbd>↓</kbd> or <kbd>S</kbd>) |
| [CONTROL_LEFT](/constants/CONTROL_LEFT/) | 0x00000004 | Move left control (<kbd>←</kbd> or <kbd>A</kbd> \[<kbd>←</kbd> or <kbd>A</kbd> in [mouselook](https://wiki.secondlife.com/wiki/mouselook)\]) |
| [CONTROL_RIGHT](/constants/CONTROL_RIGHT/) | 0x00000008 | Move right control (<kbd>→</kbd> or <kbd>D</kbd> \[<kbd>→</kbd> or <kbd>D</kbd> in [mouselook](https://wiki.secondlife.com/wiki/mouselook)\]) |
| [CONTROL_ROT_LEFT](/constants/CONTROL_ROT_LEFT/) | 0x00000100 | Rotate left control (<kbd>←</kbd> or <kbd>A</kbd>) |
| [CONTROL_ROT_RIGHT](/constants/CONTROL_ROT_RIGHT/) | 0x00000200 | Rotate right control (<kbd>→</kbd> or <kbd>D</kbd>) |
| [CONTROL_UP](/constants/CONTROL_UP/) | 0x00000010 | Move up control (<kbd>PgUp</kbd> or <kbd>E</kbd>) |
| [CONTROL_DOWN](/constants/CONTROL_DOWN/) | 0x00000020 | Move down control (<kbd>PgDn</kbd> or <kbd>C</kbd>) |
| [CONTROL_LBUTTON](/constants/CONTROL_LBUTTON/) | 0x10000000 | Left mouse button control |
| [CONTROL_ML_LBUTTON](/constants/CONTROL_ML_LBUTTON/) | 0x40000000 | Left mouse button control while in [mouselook](https://wiki.secondlife.com/wiki/mouselook) |
| (undocumented) | 0x02000000 | Avatar left rotation detected. Triggers [llGetAnimation](/functions/llGetAnimation/) == "Turning Left" |
| (undocumented) | 0x04000000 | Avatar right rotation detected. Triggers [llGetAnimation](/functions/llGetAnimation/) == "Turning Right" |

## Caveats

- [CONTROL_ROT_LEFT](/constants/CONTROL_ROT_LEFT/) and [CONTROL_ROT_RIGHT](/constants/CONTROL_ROT_RIGHT/) can be triggered when an object is selected or edited. If the user is running Viewer 2.0 and later, [llGetAgentInfo](/functions/llGetAgentInfo/) will have [AGENT_AUTOPILOT](/constants/AGENT_AUTOPILOT/) set in this case.
- Sitting upon an object that takes control may also trigger [CONTROL_FWD](/constants/CONTROL_FWD/), [CONTROL_BACK](/constants/CONTROL_BACK/), [CONTROL_DOWN](/constants/CONTROL_DOWN/) and [CONTROL_UP](/constants/CONTROL_UP/), depending on avatar position relative to the seat.
- Autopilot control events can continue for a short time after [AGENT_AUTOPILOT](/constants/AGENT_AUTOPILOT/) drops.
- The 'levels' and 'edges' of the control() event both receive ([CONTROL_FWD](/constants/CONTROL_FWD/) + [CONTROL_BACK](/constants/CONTROL_BACK/)) (value 3) after teleport, effecting scripts that use this combination for faster movement. Calling `llTakeControls()` again after a `llSleep(3)` will filter this out.

## Examples

<details open>
<summary>Example 1</summary>

```lsl collapse={1-24}
default
{
    state_entry()
    {
        llRequestPermissions(llGetOwner(), PERMISSION_TAKE_CONTROLS);
    }
    run_time_permissions(integer perm)
    {
        if(PERMISSION_TAKE_CONTROLS & perm)
        {
            llTakeControls(
                            CONTROL_FWD |
                            CONTROL_BACK |
                            CONTROL_LEFT |
                            CONTROL_RIGHT |
                            CONTROL_ROT_LEFT |
                            CONTROL_ROT_RIGHT |
                            CONTROL_UP |
                            CONTROL_DOWN |
                            CONTROL_LBUTTON |
                            CONTROL_ML_LBUTTON |
                            0, TRUE, FALSE);
                            // | 0 is for edit convenience,
                            // it does not change the mask.
        }
    }
    control(key id, integer level, integer edge)
    {
        integer start = level & edge;
        integer end = ~level & edge;
        integer held = level & ~edge;
        integer untouched = ~(level | edge);
        llOwnerSay(llList2CSV([level, edge, start, end, held, untouched]));
    }
}
```

</details>

## Notes

[llGetRot](/functions/llGetRot/) in [mouselook](https://wiki.secondlife.com/wiki/mouselook) for an attachment returns the angle the avatar is looking in.

There are some bugs when you put two scripts in the same prim and call LlTakeControls(), the **id** may not be the intended one. See [SVC-3187](http://jira.secondlife.com/browse/SVC-3187).

## Known issues

From the issue templates included by the wiki article:

- SCR-97 (bug): llTakeControls Traps repeating event when contols are changed or permission revoked
- SVC-3187 (bug): llTakeControls overrides existing controls

## See also

### Functions

- [llTakeControls](/functions/llTakeControls/)
- [llReleaseControls](/functions/llReleaseControls/)
- [llRequestPermissions](/functions/llRequestPermissions/)

### Events

- [run_time_permissions](/events/run_time_permissions/)

---

*Source: [Control](https://wiki.secondlife.com/wiki/Control) on the Second Life Wiki. Content from the Second Life Wiki articles Control (revision 1214941, 2023-10-09), Template:LSL Constants/Controls (revision 1209226, 2020-04-11), Template:Issues/SCR-97 (revision 1188892, 2014-03-29), Template:Issues/SVC-3187 (revision 292973, 2009-03-25) and Template:LSL Function/avatar (revision 1179236, 2013-06-15), CC BY-SA 3.0.*

---

From lsl.dev: https://lsl.dev/events/control/
