Released February 16, 2023


The Game Automation Tool

Now Supports Windows 11!

No Credit Card or Email Required

Star Citizen

ControlMyJoystick can send virtual joystick axis data, keystrokes and mouse button clicks/movements to Star Citizen.  Using a six-degree-of-freedom 3Dconnexion controller is perfect for space games, and Star Citizen is no exception.

Configuring ControlMyJoystick (CMJ) and Star Citizen (SC) is pretty simple, providing you follow the method outlined below.  This article covers how to bind your controller axis and buttons to SC.  It does not cover how to send keystrokes or mouse clicks.

New to using 3Dconnexion Controllers in ControlMyJoystick?  Read these Knowledge Base articles first.
About the 3DxConnection controller and it’s configuration in ControlMyJoystick
About app targets
About the virtual joystick driver and 3dconnexion driver conflicts

Remember This

The secret to getting it working is to use CMJ voice or menu commands to bind the axis to the controller in-game.  Don’t touch the controller while binding.  If you do touch it while binding it will not bind correctly.  This is explained further below.

The Task

Let’s bind the Pitch, Roll and Yaw flight axis and a controller button to bring up the in-game scoreboard while in flight.

Prepare your 3Dconnexion Controller

Plug in the controller and confirm that it is working with the utilities that came with 3DxWare drivers that came with it.

Prepare ControlMyJoystick

  1. Shut down SC and CMJ.
  2. Start CMJ and set it to stay on top (View/Stay on Top menu).  This will allow you to keep the CMJ window floating above your SC game window later on if you are short on screen space.
  3. Enable 3DxWare in the Input/3DxWare menu.
  4. Move the controller puck around and you should be able to see the indicators moving under the 3DxWare panel.
  5. Press some buttons on the controller and you should which button was pressed just below the RZ indicator (in the Bu indicator area).
  6. Enable the microphone in the Input/Voice menu. This is absolutely required to bind the controller axis in-game and there is no way to bind the axis without the microphone. Turn up the voice Threshold to around 90-92 if you are English speaking on an English-language PC, or around 70 otherwise.
  7. Open up the Voice panel in CMJ  and try speaking some commands like ‘Bind button’ or ‘Bind Rotation on X Axis’. If the voice command is detected properly, the voice command text will be auto-selected in the voice command list.  Get it working well so that it can recognize your voice commands reliably.
  8. Create a new profile.


At this point, CMJ is running, the controller is responsive and the voice commands are working.

Prepare Star Citizen

First we will unbind a bunch of axis-related items.

  1. Start SC.  Run it in windowed mode so it’s easy to swap back and forth to CMJ for the next while. Later on you can run it full-screen when the bindings are working.  Go to the Arena/Broken moon area or some place where you will not get shot up.
  2. Go to the Controls tab and on the lower-right corner of the screen, select Joystick/HOTAS1. Disable everything for this by setting flight to No, Throttle to No, everything to No. Do this for all the Joystick/HOTASx’s you have – ours go to Joystick/HOTAS4. This means that SC sees four joysticks on our PC.  You can still bind a real physical joystick while while CMJ is running, it’s just that for now, let’s clear out all the bindings.
  3. Go to the Options/Keybindings/Advanced Controls Customization and on the lower-right corner of the screen, cycle to Joystick/Hotas.  Go to Flight-Movement and unbind all the Pitch, Roll and Yaw entries.


So now in SC, no yaw, pitch and roll is bound to any joystick input. Return to the game and move around the controller. It should not pitch, roll or yaw. If it does, you missed something in the steps above.

Let’s take a look at what happening in SC. Even though we disabled all joystick inputs, SC can still receive inputs directly from the Spacemouse driver. We have no idea why this is possible, but it is the cause of most of the frustration in setting this up.  It could be that there is a hidden Joystick/HOTAS0 that we can’t unbind. So we are stuck with this, and it’s the reason we need to use voice commands for binding the axis.

The Wrong Way to Bind

To see this problem in action(it’s good idea to try this as it will help make sense of it all), try this:

  1. Go to the Options/Keybindings/Advanced Controls Customization and on the lower-right corner of the screen, cycle to Joystick/Hotas.
  2. Go to flight-movement and try to bind the Pitch axis. Move the controller pitch when prompted and it might put something like ‘rotx’ in there. That is bad, because it didn’t come through CMJ’s virtual joystick driver.
  3. Go back into the game and try pitching. It isn’t very good and may be inverted.  After you have experimented with this incorrect method, clear those bindings again so that there are no bindings for yaw, pitch or roll for Joystick/Hotas.

The Correct Way to Bind

We’ll use CMJ voice commands to send the binding data through the CMJ virtual joystick driver. Our hands will never touch the controller as we do this.

  1. Go to the Controls tab and on the lower-right corner of the screen, select Joystick/HOTAS1(it should be #1, though if you have many joysticks, it may be a different HOTAS#). Enable the Flight Movement (set to Yes for flight(pitch), flight(yaw), flight(roll) and the other flight() ones to under movement if you like.
  2. Go to the Options/Keybindings/Advanced Controls Customization and on the lower-right corner of the screen, cycle to Joystick/Hotas.
  3. Go to Flight-Movement and dbl-click on Pitch and then speak ‘Bind Rotation on X Axis’ into the microphone. This causes CMJ to simulate the rotation of the controller along x axis (pitch) and send this movement data via the virtual joystick driver to the game. The game should bind it as ‘rotx(input2)’. If you hadn’t used a voice command and bound it by physically moving the controller, it would have just said ‘rotx’ which is wrong. In fact if when you are binding you physically move the controller around a bit you will see it flicker from rotx to rotx(input2) as SC is receiving inputs from both and displays the one last received. This is why we use voice commands instead.


Now return to the game with only pitch configured. Just doing one axis for now will make the next steps easier as we don’t want axis cross talk messing up our configuration changes. Try pitching up and down with the controller. The ship should pitch up and down, though it might be inverted. That ok, we can fix that in CMJ.

Adjust Curves, Inversion and Deadzones in CMJ, not SC.

Let’s try inverting the pitch, tweaking the axis response curve and deadzones.

  1. In CMJ, open the 3DxWare panel and in the grid with the axis, enabled, invert, etc columns, double-click on RX. RX (Rotation around the X Axis) is the axis used for pitch.  The curve editor window will open and this is where we will tweak this axis. Any changes you make here take immediate effect, so you do not need to close the Rx window or press a button to save your changes. You could keep the CMJ window on top of the SC game window and tweak the curves while you fly.
  2. Now try pitch in-game and get a feel for how much you need to move the controller to get the ship to move.
  3. Go back to CMJ and set the Invert checkbox in the curve editor.  Go back to the game and try pitching and now it pitches the opposite direction.  This is a good way we know that the axis binding was done correctly as we know the axis data is actually coming from CMJ.


So now we have bound a controller axis through CMJ in SC.  Time to tweak that curve so that it has a smoother response.

Curves, Deadzones and Curves

Use curves to adjust the axis responsiveness and deadzones to limit the cross-talk among axis.  With no deadzone, just touching the controller with your fingertip will cause axis movement on pretty well all six axis.  This will make controlling your ship difficult. 

Add a deadzone so that you can actually just touch the controller or rest your hand on it without it generating any axis inputs.  Use Trim to fix a controller that always seems to be off-axis a bit even though you are not touching the controller, giving you a constant pitch etc.

The deadzone and trim values are based on a controller axis input range from -328 to +328.    That is the ‘granularity’ or precision of the data that we get from the controller driver.  So that’s 656 positions for each axis. Since the controller puck moves over a very small physical distance, this is plenty of precision unless you have the steadiest hands in the world.  So if you set a deadzone to 100, that means that the center 100/656 or %15 of the physical movement range is deadzone and CMJ will report the axis position as centered throughout this range.

  1. Right-click on the curve editor graph and select Soft – No Explicit Deadzone. This means that you need to set the deadzone in the Deadzone edit box at the top of the screen. If it has an Explicit Deadzone, the deadzone is built-in to the shape of the curve and it ignores the deadzone edit box.
  2. Go back to the game and try pitch again. It should respond differently now.
  3. Go back to the curve editor and drag the curve graph nodes (squares) around with your mouse.  Go back to the game and test.  Repeat until you have a good curve.
  4. Enter a deadzone of 100 in the deadzone edit box at the top of the curve editor screen.  Go back to the game and test pitch again.  You will need to move the controller more before your ship starts moving and that is good.  Adjust the deadzone value so that it feels right.  Often you don’t can’t finalize a deadzone value until you have all the axis bindings complete and the curves are set.  Only then you can really know how much cross-talk you will have.

Visualizing the Effects of Curves, Trim and Deadzone without running SC

In CMJ, you can see the raw axis data coming in from the controller and the adjusted (curved) data being sent to the CMJ joystick driver. This is really useful for learning how the curve editor works without having to go into the game.

  1. Expand the Joystick panel.  This shows exactly controller inputs modified by CMJ curves., but scaled from -16384 to + 16384.  This is the axis data that is used by the game. Move the controller puck around and you will see that the indicator movements in the 3DxWare panel don’t exactly match what you see in the Joystick panel.  This is because the 3DxWare panel is raw controller data and the Joystick panel shows raw data adjusted with curves.  If went and reset your curves so that they are flat x1.00, the Joystick and 3DxWare indicators would match perfectly.
  2. In the 3DxWare panel, double-click on the Rx row in the grid to bring up the curve editor.
  3. Move the controller around the Rx axis and observe the curve-modified results in two places: in the joystick panel and in the area just below the curve grid.  That last one is what we will use for tweaking the curve.
  4. Right-click on the curve and reset it to a flat default curve. Move the controller in around Rx and observe the two indicators moving just below the curve grid.  The top indicator is the raw unaltered (except for smoothing if you have it enabled) position.   The indicator below it shows the curve modified position data.  Both indicators should be moving in lockstep since the curve is flat.
  5. Check the Invert box and move the controller and watch the indicators.  They should be moving in opposite directions.  This is also happening in the 3DxWware vs Joystick panels.

Now for the Other Axis

Go and bind the other axis with your voice commands and tweak the curves.


Your ship should now be flyable with your bound axis.  You can also bind the Tx, Ty, and Tz to thrusters to allow lateral, forward/back and vertical movement respectively.

Axis Groups

One set of axis curves seldom is adequate for all flight scenarios. Up to this point, you have been editing the curves in the Default Curve Group.  This is shown in the grid just above the axis grid in the 3DxWare panel.  The settings for the six axis are contained within the Default group and you may use these for combat, for example.  But what if you want different curves general non-combat flying around? 

You can create a new axis group for that and then switch which group to use while in-game.  So if you are in-game and just flying around using one group and combat is imminent, you could use a CMJ trigger such as voice or a controller button to change to the combat curve group.  

Let’s create a new axis group

  1. Right-click on the Default axis group row in the grid and select ‘Duplicate’ from the popup menu and give it a name.  You now have two axis groups.
  2. Select your new axis group in the grid and the edit some curves.  Your curve edits are assigned to your new group.  You can switch back to the original default group by clicking on it in the grid or by trigger.


In the curve editor indicators, you may have noticed that your hands are a bit shaky an even though you may try to hold your hand and the controller puck perfectly still, it is pretty well impossible and it will move around a bit.  If you don’t want this shakiness sent to the game, go back to the Input/3DxWare menu and enable Smoothing with a depth of 2 or 3.  Any higher will cause noticeable controller lag but be really smooth.  2 or 3 is usually enough.  Close this window and go back to the curve editor and move the controller around.  You should be able to hold it pretty still now.  You will see that it lags a bit though.

Binding a Controller Button to a Virtual Joystick Button

This also uses voice commands. Don’t touch the controller while doing this. Let’s bind a button on the controller to bring up the scoreboard in-game.

  1. In SC, go to the Options/Keybindings/Advanced Controls Customization and on the lower-right corner of the screen, cycle to Joystick/Hotas. Go to Flight – HUD. We’ll bind this with a voice command.
  2. In CMJ, open the Joystick panel. There is a grid numbered from 1-128. Dbl-click on row#1 and rename it ‘Scoreboard’. Each row here is a virtual joystick button, and we are saying that we want to use #1 for the scoreboard.
  3. Sending button # 1 to the game requires a macro, trigger and script. Create a macro and call it ‘Scoreboard’ or whatever. Add a trigger for 3DxWare Key Combo and then press the button on the controller that you want to bring up the scoreboard with. You can also add another trigger here for voice if you like. So you could bring up the keyboard by pressing the controller button or speaking a command like ‘show scoreboard’.
  4. Under script, add Joystick Button Down and select button #1 Scoreboard. Then add a pause for say 3000 milliseconds. Then add Joystick Button up and select button #1 keyboard.
  5. Test this macro by clicking the Run button above the macro grid, or pressing the button on the controller, or using that voice trigger if you made it. The scoreboard should appear and then 3 seconds later disappear.

You could also bind a keyboard key or mouse button in SC instead of using a joystick button to bring up the scoreboard. In the script, just send keystrokes instead and use profile app targeting while gaming in windowed mode. You’ll need profile app targeting enabled for this to work while windowed gaming though.  Some games ignore keystrokes sent by other apps though, so this may not always work.  But the virtual joystick driver is seen as a real physical joystick, so it won’t be ignored.

Use your Smart Device to open the Scoreboard

Try our free iPhone or Android apps to create buttons on your smart device screen that when touched, cause a macro to fire. In this macro’s triggers, you could put a ‘Scoreboard’ button on your phone and prop it up by your keyboard and use it as a touchscreen.