Click here to Skip to main content
Click here to Skip to main content

Converting Joystick into Mouse Radially

By , 15 Apr 2013
Rate this:
Please Sign up or sign in to vote.

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.

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)

About the Author

Lee Louviere

United States United States
No Biography provided

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web01 | 2.8.140415.2 | Last Updated 15 Apr 2013
Article Copyright 2012 by Lee Louviere
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid