Click here to Skip to main content
15,885,869 members
Articles / Programming Languages / C#
Tip/Trick

Converting Joystick into Mouse Radially

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
15 Apr 2013CPOL2 min read 16.3K   8   5   1
Convert joystick movement into mouse position from a fixed center.

Introduction

I wanted something to control a mouse using a joystick in a radial fashion on the screen. I've always been disappointed in top-down RPGs that refuse to offer WASD or joystick support. So I did it for myself. I don't feel this is a hack or cheat because this doesn't circumvent any of the balance features that were offered as counter arguments to offering this mode of movement: stopping to attack, etc.

The other interesting thing I did was add a feature to save off the mouse position. I then modified it to let you alter the mouse position while moving the joystick. A red dot in the form of a clipped window shows the hidden position. This method works with all the major titles out there.

If you want to use a joystick in a game that only supports a mouse, this has that potential, but you'll need to implement a mouse "hold" functionality, as this one currently supports a mouse click.

At a very high radius, it may actually be useful for people who can't use a mouse, and don't like using a joystick to "move" a mouse, and would rather move in a fixed fashion.

Background

It's really hard to find something that does this all in one place. I'm using "deprecated" direct X input.

The capture joystick class is not mine, but I can't source the author and the code I found doesn't include any comments at all.

Using the code

The important thing is, as this grabs the device, the wrapper will regularly trigger an event. That event is handled and then converted into mouse coordinates. The relevant code here is shown here.

Notice anything? I'm starting up a thread to do a sendkeys.sendwait. For some reason sendkeys.send throws all kinds of exceptions if the active window isn't setup to handle keystrokes a certain way. I didn't care to figure that out, and sendwait is slow, so I started a thread.

C#
void cap_StateRefresh(object sender, JoystickStateEventArgs e)
{
    Rectangle resolution = Screen.PrimaryScreen.Bounds;
    if (SaveMouseOption.Checked)
    {
        if (!_Saved)
        {
            _Saved = true;
            _SavePoint = Cursor.Position;
        }
    }

    if ((Math.Abs(e.State.X) < (_JoySettings.XMax * _JoySettings.XDeadzone)) && 
        (Math.Abs(e.State.Y) < (_JoySettings.YMax * _JoySettings.YDeadzone)))
    {
        if (SaveMouseOption.Checked)
        {
            Cursor.Position = _SavePoint;
            _Saved = false;
        }
        return;
    }
    int radiusPixels;
    if (!int.TryParse(RadiusPixels.Text, out radiusPixels))
    {
        radiusPixels = 150;
    }
    int X = (e.State.X < 0) ? e.State.X + (int)(e.State.X * _JoySettings.XDeadzone) : 
             e.State.X - (int)(e.State.X * _JoySettings.XDeadzone);
    int Y = (e.State.Y < 0) ? e.State.Y + (int)(e.State.Y * _JoySettings.YDeadzone) : 
             e.State.Y - (int)(e.State.Y * _JoySettings.YDeadzone);

    POINT point;
    GetCursorPos(out point);

    int XOffset = (e.State.X < 0) ? (int)(e.State.X * radiusPixels / Math.Abs(_JoySettings.XMin)) :
        (int)(e.State.X * radiusPixels / _JoySettings.XMax);
    int YOffset = (e.State.Y < 0) ? (int)(e.State.Y * radiusPixels / Math.Abs(_JoySettings.YMin)) :
        (int)(e.State.Y * radiusPixels / _JoySettings.YMax);

    point.X = (resolution.Width / 2) + XOffset;
    point.Y = (resolution.Height / 2) + YOffset;
    
    Cursor.Position = new System.Drawing.Point(point.X, point.Y);
    if (MoveMouseClickOption.Checked)
    {
        DoMouseClick();
    }
    else if (MoveF12Option.Checked)
    {
        DoF12();
    }
    else
    {
        DoKey();
    }
}

public void DoMouseClick()
{
    mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
    mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
}

public void DoF12()
{
    new System.Threading.Thread((System.Threading.ThreadStart)delegate
    {
        SendKeys.SendWait("{F12}");
    });
}
public void DoKey()
{
    new System.Threading.Thread((System.Threading.ThreadStart)delegate
    {
        try
        {
            SendKeys.SendWait(OtherKeyText.Text);
        }
        catch (InvalidOperationException)
        {
            return;
        }
        catch (Exception)
        {
            if (InvalidKeyLabel.InvokeRequired)
            {
                InvalidKeyLabel.BeginInvoke((MethodInvoker)delegate()
                {
                    InvalidKeyLabel.Visible = true;
                }, null);
            }
            else
            {
                InvalidKeyLabel.Visible = true;
            }
        }
    });
}
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(long dwFlags, long dx, long dy, long cButtons, long dwExtraInfo); 

Points of Interest

This can lock up really bad if you don't include some dead zone space. Fair warning.

History

  • Initial version: 6/13/2012
  • Update: Save mouse is more like record mouse now. It paints a red dot showing the mouse position before the joystick hijack, but then records offsets during hijack, so when you restore, you restore back to the new recorded location. All in real time. This essentially gives two interactive locations for the mouse cursor!!!! I've outdone myself.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Generalapp to record Test case and record mouse movement and keyboard clicks Pin
Member 117448536-Jun-15 20:31
Member 117448536-Jun-15 20:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.