Jump to content

Steel Battalion controller and win 7 64-Bit drivers


417 replies to this topic

#361 Golden Gun

    Member

  • PipPipPip
  • Legendary Founder
  • Legendary Founder
  • 87 posts
  • LocationIdaho

Posted 23 January 2016 - 03:00 PM

I know what I'm doing when I get home. :D

BTW, did you see what Skillfulest is trying to do? I gave him everything I could think of but he is still stuck. I honestly don't even know if it'll work...

#362 HackNFly

    Member

  • PipPipPipPipPip
  • 131 posts

Posted 24 January 2016 - 01:30 PM

View PostSkillfulist, on 20 January 2016 - 05:01 AM, said:

Ok, I got the SBC to work mostly how I want it too for MWO but I cant get two of the buttons to remain lighted up when pressed, the Close Cockpit button and F1. And is there a way for the Hat control on the left joystick to be used as a fine aiming device?

			double combinedValue = controller.Scaled.AimingX*0.9 + controller.Scaled.SightChangeX*0.1;
			joystick.setAxis(1,(int)combinedValue ,HID_USAGES.HID_USAGE_X);


I think this may be what you're looking for. The Scaled structure contains the values of the SBC scaled to the input value of vJoy, so that you don't really have to calibrate anymore if you don't want to. So in order to get some precise movement, you simply add the two values. Here I use a multiplier of 0.9 for the x-axis of right stick and add it to the x-axis of the thumbstick.

Change the multipliers as you see fit, I just picked 10% of the movement from the thumbstick off the top of my head.

Also, as far as your issue with the buttons staying lit, it shouldn't be that way from default, but it may be that you've changed the second variable from:
controller.AddButtonKeyLightMapping(ButtonEnum.CockpitHatch, true, 3, SBC.Key.A, true);
controller.AddButtonKeyLightMapping(ButtonEnum.FunctionF1, true, 3, Microsoft.DirectX.DirectInput.Key.BackSpace, true);


to:


controller.AddButtonKeyLightMapping(ButtonEnum.CockpitHatch, false, 3, SBC.Key.A, true);
controller.AddButtonKeyLightMapping(ButtonEnum.FunctionF1, false, 3, Microsoft.DirectX.DirectInput.Key.BackSpace, true);

Edited by HackNFly, 24 January 2016 - 01:34 PM.


#363 Golden Gun

    Member

  • PipPipPip
  • Legendary Founder
  • Legendary Founder
  • 87 posts
  • LocationIdaho

Posted 02 February 2016 - 09:02 PM

I've updated all my old code and everything works except the toggles. To be more precise, the toggles OTHER than FUELFLOWRATE. Grrr. I had to Hash the lines below for the config to work. Any pointers on what I'm doing wrong?

//if(controller.GetButtonState(ButtonEnum.ToggleFilterControl)) //FILT Toggle
{
controller.AddButtonKeyMapping(ButtonEnum.RightJoyFire,  SBC.Key.D2, true);
//joystick.setButton(controller.GetButtonState(ButtonEnum.RightJoyFire),1,15);
}
//else
{
controller.AddButtonKeyMapping(ButtonEnum.RightJoyFire,  SBC.Key.NoConvert, true);
//joystick.setButton(controller.GetButtonState(ButtonEnum.RightJoyFire),1,0);
}
 
//if(controller.GetButtonState(ButtonEnum.ToggleOxygenSupply)) // O2 Supply Toggle
{
controller.AddButtonKeyMapping(ButtonEnum.RightJoyMainWeapon,  SBC.Key.D2, true);
}
//else
{
controller.AddButtonKeyMapping(ButtonEnum.RightJoyMainWeapon,  SBC.Key.D3, true);
}
 
currentResetValue = controller.GetButtonState((int)ButtonEnum.ToggleFuelFlowRate);
if(currentResetValue != lastResetValue && currentResetValue)
{
controller.TestLEDs(1);//reset lights


Thanks in advance.

Golden

#364 HackNFly

    Member

  • PipPipPipPipPip
  • 131 posts

Posted 02 February 2016 - 09:21 PM

Could you send me or post the full code I'm having trouble following what you are doing with just this segment. The way it currently reads the if statements aren't doing anything since they're commented out and both lines of code are run.
~Hack

#365 Golden Gun

    Member

  • PipPipPip
  • Legendary Founder
  • Legendary Founder
  • 87 posts
  • LocationIdaho

Posted 03 February 2016 - 07:39 AM

View PostHackNFly, on 02 February 2016 - 09:21 PM, said:

Could you send me or post the full code I'm having trouble following what you are doing with just this segment. The way it currently reads the if statements aren't doing anything since they're commented out and both lines of code are run.
~Hack


Didn't see your reply soon enough. I'll post the full .CS file tonight.

#366 Golden Gun

    Member

  • PipPipPip
  • Legendary Founder
  • Legendary Founder
  • 87 posts
  • LocationIdaho

Posted 04 February 2016 - 11:23 PM

Here is the full file. I put it back in fully active mode so you can see exactly what I was trying to do with the Toggle Switches.

// MWO Config File
// version 0.7
// by von Pilsner (thanks to HackNFly!@!!!)
//
// Uses default MWO keybindings as of Sept 26, 2012
// You must map the 'throttle' axis in-game though...
//
// For use with Steel-Batallion-64_v2_pre.zip
// 64 bit driver code/glue by HackNFly  http://code.google.com/p/steel-batallion-64/
//
// add the folowing to user.cfg
//
// cl_joystick_gain = 1.35
// cl_joystick_invert_throttle = 0
// cl_joystick_invert_pitch = 1
// cl_joystick_invert_yaw = 0
// cl_joystick_invert_turn = 0
// cl_joystick_throttle_range = 0
//
// updated by Santiago Saldana Sept, 27, 2012
using SBC;
using System;
namespace SBC {
public class DynamicClass
{
SteelBattalionController controller;
vJoy joystick;
bool acquired;
bool jumpPressed = false;
bool stopPressed = false;//used in special handling of left pedal
bool currentResetValue;
bool lastResetValue;//used in assessing when to flip lights
int pedalTriggerLevel = 50;//used in special handling of left pedal,
 
SBC.Key jumpKey = SBC.Key.Space;
SBC.Key stopKey = SBC.Key.X;
const int refreshRate = 30;//number of milliseconds between call to mainLoop
//this gets called once by main program
	public void Initialize()
	{
		int baseLineIntensity = 3;//just an average value for LED intensity
		//int emergencyLightIntensity = 15;//for stuff like eject,cockpit Hatch,Ignition, and Start
  controller = new SteelBattalionController();
  controller.Init(50);//50 is refresh rate in milliseconds
  //set all buttons by default to light up only when you press them down
  for(int i=4;i<4+30;i++)
  {
   if (i != (int)ButtonEnum.Eject)//excluding eject since we are going to flash that one
   controller.AddButtonLightMapping((ButtonEnum)(i-1),(ControllerLEDEnum)(i),true,baseLineIntensity);
  }
  controller.AddButtonKeyMapping(ButtonEnum.RightJoyMainWeapon,		   SBC.Key.D4, true);
  controller.AddButtonKeyMapping(ButtonEnum.RightJoyLockOn,		  SBC.Key.R, true);
  controller.AddButtonKeyLightMapping(ButtonEnum.Eject,	 true, 3,	SBC.Key.O, true);
  controller.AddButtonKeyLightMapping(ButtonEnum.Ignition,	true, 3,	SBC.Key.P, true);
  //controller.AddButtonKeyLightMapping(ButtonEnum.Start,	 true, 3,	SBC.Key.X, true);
  controller.AddButtonKeyLightMapping(ButtonEnum.MultiMonOpenClose,  true, 3,	SBC.Key.B, true);
  controller.AddButtonKeyLightMapping(ButtonEnum.MultiMonMapZoomInOut, true, 3,	SBC.Key.B, true);
  //controller.AddButtonKeyLightMapping(ButtonEnum.MultiMonModeSelect, true, 3,	SBC.Key.X, true);
  //controller.AddButtonKeyLightMapping(ButtonEnum.MultiMonSubMonitor, true, 3,	SBC.Key.X, true);
  controller.AddButtonKeyLightMapping(ButtonEnum.MainMonZoomIn,   true, 3,	SBC.Key.Z, true);
  controller.AddButtonKeyLightMapping(ButtonEnum.MainMonZoomOut,   true, 3,	SBC.Key.V, true);
  //controller.AddButtonKeyLightMapping(ButtonEnum.FunctionFSS,   false, 13,  SBC.Key.D6, true);
  controller.AddButtonKeyLightMapping(ButtonEnum.FunctionManipulator,  true, 13,   SBC.Key.LeftShift, true);
  controller.AddButtonKeyLightMapping(ButtonEnum.FunctionLineColorChange, false, 13,  SBC.Key.H, true);
  controller.AddButtonKeyLightMapping(ButtonEnum.Washing,	 true, 3,	SBC.Key.C, true);
  controller.AddButtonKeyLightMapping(ButtonEnum.Extinguisher,   true, 3,	SBC.Key.O, true);
  controller.AddButtonKeyLightMapping(ButtonEnum.Chaff,	 true, 13,   SBC.Key.J, true);
  //controller.AddButtonKeyLightMapping(ButtonEnum.FunctionTankDetach, true, 3,	SBC.Key.X, true);
  controller.AddButtonKeyLightMapping(ButtonEnum.FunctionOverride,  true, 3,	SBC.Key.O, true);
  controller.AddButtonKeyLightMapping(ButtonEnum.FunctionNightScope,  false, 13,  SBC.Key.N, true);
  controller.AddButtonKeyLightMapping(ButtonEnum.FunctionF1,	true, 3,	SBC.Key.Tab, true);
  //controller.AddButtonKeyLightMapping(ButtonEnum.FunctionF2,   true, 3,	SBC.Key.X, true);
  //controller.AddButtonKeyLightMapping(ButtonEnum.FunctionF3,   true, 3,	SBC.Key.LeftControl, true);
  controller.AddButtonKeyLightMapping(ButtonEnum.WeaponConMain,   true, 3,	SBC.Key.RightControl, true);
  controller.AddButtonKeyLightMapping(ButtonEnum.WeaponConSub,   true, 3,	SBC.Key.BackSpace, true);
  //controller.AddButtonKeyLightMapping(ButtonEnum.WeaponConMagazine,  true, 3,	SBC.Key.X, true);
  controller.AddButtonKeyLightMapping(ButtonEnum.Comm1,	 true, 3,	SBC.Key.F6, true);
  controller.AddButtonKeyLightMapping(ButtonEnum.Comm2,	 true, 3,	SBC.Key.F8, true);
  controller.AddButtonKeyLightMapping(ButtonEnum.Comm3,	 true, 3,	SBC.Key.F9, true);
  //controller.AddButtonKeyLightMapping(ButtonEnum.Comm4,	 true, 3,	SBC.Key.X, true);
  controller.AddButtonKeyLightMapping(ButtonEnum.Comm5,	 true, 3,	SBC.Key.RightBracket, true);
  controller.AddButtonKeyMapping(ButtonEnum.LeftJoySightChange,		 SBC.Key.Z, true);
  controller.AddButtonKeyMapping(ButtonEnum.ToggleVTLocation,		   SBC.Key.Q, true);
  controller.AddButtonKeyMapping(ButtonEnum.ToggleFilterControl,		   SBC.Key.D6, true);
 
  joystick = new vJoy();
  acquired = joystick.acquireVJD(1);
  joystick.resetAll();//have to reset before we use it
}
 
//this is necessary, as main program calls this to know how often to call mainLoop
public int getRefreshRate()
{
  return refreshRate;
}
 
private uint getDegrees(double x,double y)
{
  uint temp = (uint)(System.Math.Atan(y/x)* (180/Math.PI));
  if(x < 0)
   temp +=180;
  if(x > 0 && y < 0)
   temp += 360;
  
  temp += 90;//origin is vertical on POV not horizontal
  
  if(temp > 360)//by adding 90 we may have gone over 360
   temp -=360;
 
  temp*=100;
 
  if (temp > 35999)
   temp = 35999;
  if (temp < 0)
   temp = 0;
  
  return temp;
}
 
public void updatePOVhat()
{
int thumbstickDeadZone = 44;
  SBC.POVdirection lastDirection = controller.POVhat;
  if(( (Math.Abs(controller.SightChangeX) > thumbstickDeadZone) || (Math.Abs(controller.SightChangeY) > thumbstickDeadZone) ))
  {
   if(Math.Abs(controller.SightChangeX) > Math.Abs(controller.SightChangeY))
	if(controller.SightChangeX <0)
	 controller.POVhat = SBC.POVdirection.LEFT;
	else
	 controller.POVhat = SBC.POVdirection.RIGHT;
   else
	if(controller.SightChangeY <0)
	 controller.POVhat = SBC.POVdirection.DOWN;
	else
	 controller.POVhat = SBC.POVdirection.UP;
  }
  else
  {
   controller.POVhat = SBC.POVdirection.CENTER;
  }
  if(lastDirection != controller.POVhat)
  {
   switch(lastDirection)
   {
	case SBC.POVdirection.LEFT:
	 controller.sendKeyUp(SBC.Key.Left);
	 break;
	case SBC.POVdirection.RIGHT:
	 controller.sendKeyUp(SBC.Key.Right);
	 break;
	case SBC.POVdirection.DOWN:
	 controller.sendKeyUp(SBC.Key.Up);
	 break;
	case SBC.POVdirection.UP:
	 controller.sendKeyUp(SBC.Key.Down);
	 break;
   }
  }
  else
  {
   switch(controller.POVhat)
   {
	case SBC.POVdirection.LEFT:
	 controller.sendKeyDown(SBC.Key.Left);
	 break;
	case SBC.POVdirection.RIGHT:
	 controller.sendKeyDown(SBC.Key.Right);
	 break;
	case SBC.POVdirection.DOWN:
	 controller.sendKeyDown(SBC.Key.Up);
	 break;
	case SBC.POVdirection.UP:
	 controller.sendKeyDown(SBC.Key.Down);
	 break;
   }
  }
}
 
public void evaluateLeftPedal()
{
	  if(controller.LeftPedal > pedalTriggerLevel)
	 {
	  //take care of the button logic separately, to be less confusing
	  if(!jumpPressed)//if not currently holding down jump key
	  {
	   if(controller.RightPedal > pedalTriggerLevel || controller.MiddlePedal > pedalTriggerLevel)
	   {
		controller.sendKeyDown(jumpKey);
		jumpPressed = true;
	   }
	  }
	  else//jump button was pressed
	  {
				//adding these so that else if won't get optimized into one statement
	   if(controller.RightPedal < pedalTriggerLevel && controller.MiddlePedal < pedalTriggerLevel)
	   {
		controller.sendKeyUp(jumpKey);
		jumpPressed = false;
	   }
	  }  
	  if(!stopPressed)//if not currently holding down stop key
	  {
	   if(controller.RightPedal < pedalTriggerLevel && controller.MiddlePedal < pedalTriggerLevel)
	   {
		controller.sendKeyDown(stopKey);//send fullstop command
		stopPressed = true;
	   }
	  }
	  else//stop button was pressed
	  {
	   if(controller.RightPedal > pedalTriggerLevel || controller.MiddlePedal > pedalTriggerLevel)
	   {
		controller.sendKeyUp(stopKey);
		stopPressed = false;
	   }
	  }
	 }
	 else
	 {
	  if(stopPressed)
	  {
	   controller.sendKeyUp(stopKey);
	   stopPressed = false;
	  }
	  if(jumpPressed)
	  {
	   controller.sendKeyUp(jumpKey);
	   jumpPressed = false;
	  }
	 }
}
//this gets called once every refreshRate milliseconds by main program
public void mainLoop()
{
updatePOVhat();
 
   joystick.setAxis(1,controller.Scaled.AimingX,HID_USAGES.HID_USAGE_X);
			joystick.setAxis(1,controller.Scaled.AimingY,HID_USAGES.HID_USAGE_Y);
			joystick.setAxis(1,-1*(controller.Scaled.RotationLever),HID_USAGES.HID_USAGE_Z);
			joystick.setAxis(1,-1*(controller.Scaled.SightChangeX),HID_USAGES.HID_USAGE_RX);
			joystick.setAxis(1,controller.Scaled.SightChangeY,HID_USAGES.HID_USAGE_RY);
			joystick.setAxis(1,controller.Scaled.RightMiddlePedal,HID_USAGES.HID_USAGE_RZ);//throttle
			joystick.setAxis(1,controller.Scaled.LeftPedal,HID_USAGES.HID_USAGE_SL0);
			joystick.setAxis(1,controller.Scaled.GearLever,HID_USAGES.HID_USAGE_SL1);
   //joystick.setContPov(1,getDegrees(controller.SightChangeX,controller.SightChangeY),1);
  // toggle tricks!!!
   if(controller.GetButtonState(ButtonEnum.ToggleFilterControl)) //FILT Toggle
   {
	 controller.AddButtonKeyMapping(ButtonEnum.RightJoyFire,  SBC.Key.D2, true);
	 joystick.setButton(controller.GetButtonState(ButtonEnum.RightJoyFire),1,15);
   }
   else
   {
	 controller.AddButtonKeyMapping(ButtonEnum.RightJoyFire,  SBC.Key.NoConvert, true);
	 joystick.setButton(controller.GetButtonState(ButtonEnum.RightJoyFire),1,0);
   }
  
   if(controller.GetButtonState(ButtonEnum.ToggleOxygenSupply)) // O2 Supply Toggle
   {
	 controller.AddButtonKeyMapping(ButtonEnum.RightJoyMainWeapon,  SBC.Key.D2, true);
   }
   else
   {
	 controller.AddButtonKeyMapping(ButtonEnum.RightJoyMainWeapon,  SBC.Key.D3, true);
   }
  
   currentResetValue = controller.GetButtonState((int)ButtonEnum.ToggleFuelFlowRate);
   if(currentResetValue != lastResetValue && currentResetValue)
   {
	controller.TestLEDs(1);//reset lights
   }
   lastResetValue = currentResetValue;
 
   evaluateLeftPedal();
   joystick.sendUpdate(1);
  }
 
  //this gets called at the end of the program and must be present, as it cleans up resources
  public void shutDown()
  {
   controller.sendKeyUp(SBC.Key.LeftControl);
   controller.UnInit();
   joystick.Release(1);
  }
}
}


And here is the error log:

c:\Users\J-Golden\AppData\Local\Temp\kqw3zlo0.0.cs(266,7) : error CS1502: The best overloaded method match for 'SBC.SteelBattalionController.GetButtonState(int)' has some invalid arguments


c:\Users\J-Golden\AppData\Local\Temp\kqw3zlo0.0.cs(266,33) : error CS1503: Argument 1: cannot convert from 'SBC.ButtonEnum' to 'int'


c:\Users\J-Golden\AppData\Local\Temp\kqw3zlo0.0.cs(269,25) : error CS1502: The best overloaded method match for 'SBC.SteelBattalionController.GetButtonState(int)' has some invalid arguments


c:\Users\J-Golden\AppData\Local\Temp\kqw3zlo0.0.cs(269,51) : error CS1503: Argument 1: cannot convert from 'SBC.ButtonEnum' to 'int'


c:\Users\J-Golden\AppData\Local\Temp\kqw3zlo0.0.cs(274,25) : error CS1502: The best overloaded method match for 'SBC.SteelBattalionController.GetButtonState(int)' has some invalid arguments


c:\Users\J-Golden\AppData\Local\Temp\kqw3zlo0.0.cs(274,51) : error CS1503: Argument 1: cannot convert from 'SBC.ButtonEnum' to 'int'


c:\Users\J-Golden\AppData\Local\Temp\kqw3zlo0.0.cs(277,7) : error CS1502: The best overloaded method match for 'SBC.SteelBattalionController.GetButtonState(int)' has some invalid arguments


c:\Users\J-Golden\AppData\Local\Temp\kqw3zlo0.0.cs(277,33) : error CS1503: Argument 1: cannot convert from 'SBC.ButtonEnum' to 'int'

To get past this I remarked out lines 266, 269, 274 & 277. That's why they were remed out in the section I sent you. ;)

#367 HackNFly

    Member

  • PipPipPipPipPip
  • 131 posts

Posted 05 February 2016 - 12:16 PM

I'll be out of town this weekend. But first mistake to fix:
   currentResetValue = controller.GetButtonState((int)ButtonEnum.ToggleFuelFlowRate);

change it to
   currentResetValue = controller.GetButtonState(ButtonEnum.ToggleFuelFlowRate);


Looking over the interface I can't tell why those are errors are popping up though it should recognize it. I"ll look into it when I get back.

#368 Golden Gun

    Member

  • PipPipPip
  • Legendary Founder
  • Legendary Founder
  • 87 posts
  • LocationIdaho

Posted 09 February 2016 - 11:28 PM

Looking closer at the errors, they are paired two to a line and the errors are always 26 columns apart. the first error is right after the first open parentheses "(" while the second one is after the second open parentheses "(".

I still have no clue what this means, but I hope this helps.

#369 Golden Gun

    Member

  • PipPipPip
  • Legendary Founder
  • Legendary Founder
  • 87 posts
  • LocationIdaho

Posted 20 February 2016 - 10:40 PM

Okay, I think I've narrowed down the issues as far as I can determine. Let me show you what I did.

1) I remarked out "using Microsoft.DirectX.DirectInput" just to avoid any confusion

2) I ran a replace for "Microsoft.DirectX.DirectInput" to "SBC" to upgrade input configs to the newer version of SteelBattalion-64 program

3) changed:

if(controller.GetButtonState(ButtonEnum.ToggleFilterControl)) //FILT Toggle

to
controller.GetButtonState(ButtonEnum.ToggleFilterControl) //FILT Toggle


This got rid of several errors, but still left two.

c:\Users\J-Golden\AppData\Local\Temp\3jb5g3hi.0.cs(271,61) : error CS1002: ; expected
 
c:\Users\J-Golden\AppData\Local\Temp\3jb5g3hi.0.cs(276,4) : error CS1525: Invalid expression term 'else'
 
c:\Users\J-Golden\AppData\Local\Temp\3jb5g3hi.0.cs(276,8) : error CS1002: ; expected
 
c:\Users\J-Golden\AppData\Local\Temp\3jb5g3hi.0.cs(282,60) : error CS1002: ; expected
 
c:\Users\J-Golden\AppData\Local\Temp\3jb5g3hi.0.cs(286,4) : error CS1525: Invalid expression term 'else'
 
c:\Users\J-Golden\AppData\Local\Temp\3jb5g3hi.0.cs(286,8) : error CS1002: ; expected


4) inserted ";" at every Line/Column point listed with the error "; Expected"


Now the only thing I can't figure out is the, " Invalid expression term 'else' " error.


I've gone through this process with three different files created by three different people. The only glimmer of hope came from Max Gordon's Elite Dangerous code. It not only gave me points to help me with the fixes shown above, but somehow also had one set run WITHOUT ERRORS!

Find his code here: http://mwomercs.com/...ost__p__3806286

This will still need the fixes above, but you'll see that the the controls starting at lines 82 & 210 return the 'Else' error, but Line 158 does not.

Hope this helps!

#370 Golden Gun

    Member

  • PipPipPip
  • Legendary Founder
  • Legendary Founder
  • 87 posts
  • LocationIdaho

Posted 29 February 2016 - 10:13 PM

Been Thinking on two other cool ideas for this program. One, I think, will make the Joystick finally viable for MWO. The other is making the Gear Lever allow a different input for each point.


First the Joystick:

The biggest problem with the joystick is that to get it to work like a mouse (Usable in MWO) you get the movement you want, but several things can seriously throw it off center. To fix this you'd need a hotkey specifically to "Center Torso" losing valuable fight time, distracting you from your game and frustrating the player after a while.

So here's my idea. Why don't we set a button press of "Center Torso" to happen every time the Aiming lever is centered.

We know we can set button presses to certain ranges on an axis, like the left peddle for activating Jump Jets. The code lays it out that if the peddle is pressed to 30% and higher, it activates the JJ where as if you let off it and go underneath 30% it issues a stop command.

What if we took this one step further and instead of setting a threshold, set a range in the middle of both the X and Y axis where if you were too high or too low on either axis, it would not trigger. Basically, we are making a small box in the center of both axis range that if entered will trigger the "Center Torso" key.

It is a rough idea, and would need tweaking to find the line between activating the button press too easily (Happening when you don't want it to) to too hard (fishing for the sweet spot while in the middle of a battle).


Now for the Gear Lever:

This idea also comes from examining previous workings of the JJ and throttle peddle/Reverse Peddle. Look in the calibration screen for the Gear Lever. there is a little box at the bottom that if checked shows you the raw data. The raw data is the numerical amount for any axis controller. If you do it earlier for the joystick, you'll see the X and Y axis now show you the real time positions numerically.

Now the Gear Lever is different then the other inputs. Where they show a broad spectrum of numbers that go into the thousands, the Gear Lever output is always the same.

R = -2
N = -1
1 = 1
2 = 2
3 = 3
4 = 4
5 = 5

These never change! So by making a series of "IF" and "THAN" statements detailing each value to a certain button press, you can now set just about anything to each level of the Gear Lever. In fact, since we are using specific points (numbers) for each position that are basically not connected to each other, we could make using the Gear Lever as easy as setting up any of the other button presses.

Me? I'd create a cruse control where it went up in increments of 20%. I could make it constant, where what ever level its set at, after using the throttle or reverse, the mech will move back to the set speed on the Gear Lever.

OR

I could make it a single press and have it work like car Cruse Controls. Tap the break or speed up, the Cruse Control will disengage until the Gear Lever is shifted.

What do you all think?

#371 GreenHell

    Member

  • PipPipPipPipPipPipPip
  • 543 posts
  • LocationGrandmas House

Posted 07 April 2016 - 10:05 PM

I would love it if the SBC was able to control the aim more similar to the way it worked in Steel Battalion. Turn the view with the small thumb stick, but actually aim with the joystick. That system threw my friends off so bad, but I loved it!

#372 evilC

    Member

  • PipPipPipPipPipPipPipPip
  • Legendary Founder
  • Legendary Founder
  • 1,298 posts
  • LocationLondon, UK

Posted 08 April 2016 - 04:19 AM

View PostGolden Gun, on 29 February 2016 - 10:13 PM, said:

The biggest problem with the joystick is that to get it to work like a mouse (Usable in MWO) you get the movement you want, but several things can seriously throw it off center. To fix this you'd need a hotkey specifically to "Center Torso" losing valuable fight time, distracting you from your game and frustrating the player after a while.

So here's my idea. Why don't we set a button press of "Center Torso" to happen every time the Aiming lever is centered.

We know we can set button presses to certain ranges on an axis, like the left peddle for activating Jump Jets. The code lays it out that if the peddle is pressed to 30% and higher, it activates the JJ where as if you let off it and go underneath 30% it issues a stop command.

This is simply not going to be practical. The box would need to be minuscule, else you would be unable to aim at points close to the center.
I have a largely working solution for joystick absolute aim by mapping joystick to mouse, you can see my thread here for more info:
http://mwomercs.com/...ivity&mid=62105

#373 Golden Gun

    Member

  • PipPipPip
  • Legendary Founder
  • Legendary Founder
  • 87 posts
  • LocationIdaho

Posted 10 April 2016 - 11:55 AM

View PostevilC, on 08 April 2016 - 04:19 AM, said:

This is simply not going to be practical. The box would need to be minuscule, else you would be unable to aim at points close to the center.
I have a largely working solution for joystick absolute aim by mapping joystick to mouse, you can see my thread here for more info:
http://mwomercs.com/...ivity&mid=62105



I did extensive work on getting joystick to mouse to work but there were too many issues. They have all been presented earlier in this thread starting on page 13.

Those issues still exist in your AHK approach as far as I can tell. The idea of mapping "center torso" to a very small point of the center of the axis seems like it would solve all this. I have not tried it yet since I wouldn't know how to do it, and yes, a ton of tweaking would be needed, but doing it this way would be the easiest for people who aren't big on coding themselves.

#374 evilC

    Member

  • PipPipPipPipPipPipPipPip
  • Legendary Founder
  • Legendary Founder
  • 1,298 posts
  • LocationLondon, UK

Posted 11 April 2016 - 03:41 AM

There is no way that just having a center torso mapping will solve this issue.
Let me lay it out in maths:

Lets say that a given mech has a torso twist limit of 400 mouse units, and a max twist rate of 100/units sec. ie it takes 4 seconds to twist from full left to full right.

You map your joystick to this range without any of the buffering type functionality that my script has.
You start the game, then move the stick to full right within one second.
This causes a move of 200 units (center to edge) to be issued in one second. The mech can only twist at 100 units/s, so it throws away 100 units - you end up twisted 50% right. The script is now 50% out in one movement.

How is sending a center key when the stick is centered going to fix that? It in no way addresses the fact that you issued the instruction "Move 100% right" and the result was that it moved 50% right.

What did you do your "extensive work" using? If you mapped joystick position directly to mouse output and did not use code to buffer the mouse output and only move the mouse as fast as the torso could handle, then of course you are never, ever going to be able to find anything like a workable solution - because you have not attempted to address some of the discrepancies between the input method and the output method.

Yes, there are still slight issues with my script, but it just means that we have not worked out all the parameters that we need to feed into the equations. I suspect what is throwing it out is that at the moment I simply stipulate a MAX_TWIST_RATE (How many units per tick the mouse can be moved) but I am forgetting about inertia. If the mech is currently twisting left at 100 units/sec (max rate), it cannot twist right at 100 units/sec on the next tick - it has to slow down the movement in the opposite direction first - ie I need to specify a Max Delta value as well.

It's worth noting that the advantage of using an AHK script is that we can do EMPIRICAL tests. By using code to send mouse_event API calls, we can keep a record of exactly how many units of movement in each direction we have made. I ran a script that twisted the torso left and right (It was about 50% of the move range, but that's not really relevant) at the slowest speed and let it run for an hour. When I came back, it was still 100% in synch - ie when I hit the hotkey to stop moving side to side and move the torso back to center, then hit the "recenter torso" key, the view *did not move*. So clearly there are legs in the mouse output technique, we just need to be able to find what the limits of movement are and obey them.

TL;DR: It's possible to move the joystick faster than the mech torso can physically twist. That problem is ONLY solvable through code. You CANNOT solve this problem using sensitivity or recentering - the output must be fundamentally decoupled from the input.

Edited by evilC, 11 April 2016 - 03:55 AM.


#375 Golden Gun

    Member

  • PipPipPip
  • Legendary Founder
  • Legendary Founder
  • 87 posts
  • LocationIdaho

Posted 11 April 2016 - 12:47 PM

... This is not an AHK thread. This is for the driver for the SB controller. If you had read more, you would have noticed that someone had already proposed AHK but it was shot down as the purpose of the SB-64 suite is to have everything in one program, not string it out over several.

Soooooooo you like to feel superior and talk down to people, is that it? I did hours of checking, measuring, testing again to get the data I presented. If you think I missed something, just say so. Stop trying to push YOUR fix as the ONLY fix.

Oh, and the "Maths" you took so long to explain is exactly WHAT I'm trying to fix.

Al the issues I have faced using the controller in MWO WOULD be fixed if I could figure out how to implement the idea. Issues with recentering, after looking around while shut down, Moving the torso too fast, and zooming in and out. The only issues I have with these problems is centering and If I can make the box small enough that it is only activated when you actually center the stick, why CAN"T this work?

You say there is no WAY this would work. Maybe it does and maybe it doesn't, but I'm sticking with the overall theme of having SB-64 be a SINGLE solution. If you don't like it, you don't have to stay or even reply.

#376 evilC

    Member

  • PipPipPipPipPipPipPipPip
  • Legendary Founder
  • Legendary Founder
  • 1,298 posts
  • LocationLondon, UK

Posted 12 April 2016 - 03:22 AM

Quote

This is not an AHK thread. This is for the driver for the SB controller
No, it's a driver plus a mouse emulator. I was trying to help you with the mouse emulator part because I have significant experience doing these kinds of things and was aware that people on this thread were going round in circles because they do not know what all the hurdles are or how to address them.

Quote

Soooooooo you like to feel superior and talk down to people, is that it? I did hours of checking, measuring, testing again to get the data I presented. If you think I missed something, just say so. Stop trying to push YOUR fix as the ONLY fix.

I was saying that something along the lines of what my script does (i/o limiting and buffering) is the only possible solution to the problem, and presented the code as an example of how to do it.

Quote

The only issues I have with these problems is centering and If I can make the box small enough that it is only activated when you actually center the stick, why CAN"T this work?

As I said, because it is not addressing the problem, but trying to stick a dirty-great band-aid over it and hoping it goes away, which it will not.
I gave the equations that demonstrate why this technique will not work - if you cannot wrap your head around the maths, don't have a go at me...

#377 HackNFly

    Member

  • PipPipPipPipPip
  • 131 posts

Posted 12 April 2016 - 09:20 AM

evilC, you make some good points. But your comments did come across as slightly antagonistic, particularly the use of quotes around the "extensive work" that Golden Gun has put in. Golden Gun has been greatly involved in this project since the beginning, and did spent quite a bit of time measuring twist rates / ranges.



I'm also not sure I follow your buffer approach.
edit:So I believe I understand the key element to your code.
; Limit the amount of movement for this tick to the MAX_TWIST_RATE
delta_move[A_Index] := abs(delta_move[A_Index]) > MAX_TWIST_RATE ? MAX_TWIST_RATE * sgn(delta_move[A_Index]) : delta_move[A_Index]

Its not a bad idea. Certainly worth investigating. I also did the scripting tests you did as far as moving left and right and then coming back.

edit: numPixelExtraX/Y was added to take into account the difference in movement for mechs that allow you to have extra range by using your arms.


If you're talking about calculating a delta between where the joystick is currently at and how many mouse pixels you've sent the API to move, then I tried that 2-3 years ago, I'll attach my code in the next post so you can look through it if you like. It's certainly the way to do it. I abandoned trying to emulate a mouse though due to the enormous pain of guestimating maximum twist rates for each mech. I looked through your code and there are some good ideas in there, for a normal joystick, AHK may make some things more elegant while reducing readability a bit. (Personal Opinion) Still think my program is better for SBC just because it doesn't require you to run SBC emulator + AHK.

GoldenGun's approach would work for a spring mounted joystick, as you can be certain to return to a relatively precise position by releasing the joystick. This seems like it would be relatively difficult to pull off with the springless SBC joystick. I believe this is one of those situations where simply making use of the center torso as a joystick button will functionally work better than trying to achieve the same programmatically.

Here is the code I helped write for Mouse emulation a few years ago, although looking through some of the comments on p. 13 may help.

// MWO Config File
// version 3.1 (WiP)
// by von Pilsner (thanks to HackNFly!@!!!)
//
// NOTE: Calibrate using BvP-Simple-3.0.cs
//	   Or your pedals may not work properly!!
//
// Uses default MWO keybindings and axis as of Jan 28, 2013
//
// For use with Steel-Batallion-64_v2_beta.zip
// 64 bit driver code/glue by HackNFly  http://code.google.com/p/steel-batallion-64/
//
// I suggest you add the folowing to user.cfg (remove the //'s)
//
// cl_joystick_gain = 5.05
// cl_joystick_sensitivity = 1.00
// cl_joystick_invert_throttle = 0
// cl_joystick_invert_pitch = 1
// cl_joystick_invert_yaw = 0
// cl_joystick_invert_turn = 0
// cl_joystick_throttle_range = 0
//
// ; Joystick DeadZone, requires both the i and cl lines to make the joystick deadzone change work
// ; Increase in 0.02 incriments if you get an unstable center point on either stick (0.08 works for some).
// i_joystick_deadzone = 0.04
// cl_joystick_deadzone = 0.04
//
 
using SBC;
using System;
namespace SBC
{
	public class DynamicClass
	{
		SteelBattalionController controller;
		vJoy joystick;
		bool acquired;
String debugString = "";
 
int desiredX;
int desiredY;
int currentX = 0;
int currentY = 0;
int numPixelX = 600;//number of pixels to move in X direction
int numPixelY = 300;//number of pixels to move in X direction
int numPixelExtraX = 25;//used at extreme edges, number of pixels per poll
int numPixelExtraY = 20;//used at extreme edges
 
		const int refreshRate = 30; // Number of milliseconds between call to mainLoop
const int maxAxisValue = 32768;
double sideZone = 0.05;//percent of swing that will cause mouse to move continuously
int jj = 0;
bool startedTracking = false;//used to make switching mouse on and off not jumpy
 
		// This gets called once by main program
		public void Initialize()
		{
			int baseLineIntensity = 3; // Just an average value for LED intensity
			int emergencyLightIntensity = 15; // For stuff like eject,cockpit Hatch,Ignition, and Start
 
			controller = new SteelBattalionController();
			controller.Init(30); // 50 is refresh rate in milliseconds
 
			//set all buttons by default to light up only when you press them down
			for (int i = 4; i < 4 + 30; i++)
			{
				if (i != (int)ButtonEnum.Eject) // Excluding eject since we are going to flash that one
					controller.AddButtonLightMapping((ButtonEnum)(i - 1), (ControllerLEDEnum)(i), true, baseLineIntensity);
			}
 
			// Button Bindings
controller.AddButtonKeyMapping(ButtonEnum.RightJoyFire, Microsoft.DirectX.DirectInput.Key.D1,true);
controller.AddButtonKeyMapping(ButtonEnum.RightJoyMainWeapon, Microsoft.DirectX.DirectInput.Key.D2,true);
			controller.AddButtonKeyMapping(ButtonEnum.RightJoyLockOn, Microsoft.DirectX.DirectInput.Key.R, true);
			controller.AddButtonKeyLightMapping(ButtonEnum.Eject, true, 3, Microsoft.DirectX.DirectInput.Key.O, true);
			controller.AddButtonKeyLightMapping(ButtonEnum.Ignition, true, 3, Microsoft.DirectX.DirectInput.Key.P, true);
			//controller.AddButtonKeyLightMapping(ButtonEnum.CockpitHatch, true, 3, Microsoft.DirectX.DirectInput.Key.X, true);
			//controller.AddButtonKeyLightMapping(ButtonEnum.Start, true, 3, Microsoft.DirectX.DirectInput.Key.X, true);
			controller.AddButtonKeyLightMapping(ButtonEnum.MultiMonOpenClose, true, 3, Microsoft.DirectX.DirectInput.Key.B, true);
			controller.AddButtonKeyLightMapping(ButtonEnum.MultiMonMapZoomInOut, true, 3, Microsoft.DirectX.DirectInput.Key.I, true);
			controller.AddButtonKeyLightMapping(ButtonEnum.MultiMonModeSelect, true, 3, Microsoft.DirectX.DirectInput.Key.Q, true);
			//controller.AddButtonKeyLightMapping(ButtonEnum.MultiMonSubMonitor, true, 3, Microsoft.DirectX.DirectInput.Key.X, true);
			controller.AddButtonKeyLightMapping(ButtonEnum.MainMonZoomIn, true, 3, Microsoft.DirectX.DirectInput.Key.Z, true);
			controller.AddButtonKeyLightMapping(ButtonEnum.MainMonZoomOut, true, 3, Microsoft.DirectX.DirectInput.Key.V, true);
			//controller.AddButtonKeyLightMapping(ButtonEnum.FunctionFSS, true, 3, Microsoft.DirectX.DirectInput.Key.X, true);
			controller.AddButtonKeyLightMapping(ButtonEnum.FunctionManipulator, true, 3, Microsoft.DirectX.DirectInput.Key.J, true);
			controller.AddButtonKeyLightMapping(ButtonEnum.FunctionLineColorChange, true, 3, Microsoft.DirectX.DirectInput.Key.H, true);
			controller.AddButtonKeyLightMapping(ButtonEnum.Washing, true, 3, Microsoft.DirectX.DirectInput.Key.C, true);
			controller.AddButtonKeyLightMapping(ButtonEnum.Extinguisher, true, 3, Microsoft.DirectX.DirectInput.Key.Delete, true);
			//controller.AddButtonKeyLightMapping(ButtonEnum.Chaff, true, 3, Microsoft.DirectX.DirectInput.Key.X, true);
controller.AddButtonKeyLightMapping(ButtonEnum.FunctionTankDetach, true, 3, Microsoft.DirectX.DirectInput.Key.Slash, true);
			controller.AddButtonKeyLightMapping(ButtonEnum.FunctionOverride, true, 3, Microsoft.DirectX.DirectInput.Key.O, true);
			controller.AddButtonKeyLightMapping(ButtonEnum.FunctionNightScope, true, 3, Microsoft.DirectX.DirectInput.Key.N, true);
			controller.AddButtonKeyLightMapping(ButtonEnum.FunctionF1, true, 3, Microsoft.DirectX.DirectInput.Key.Tab, true);
			//controller.AddButtonKeyLightMapping(ButtonEnum.FunctionF2, true, 3, Microsoft.DirectX.DirectInput.Key.X, true);
			//controller.AddButtonKeyLightMapping(ButtonEnum.FunctionF3, true, 4, Microsoft.DirectX.DirectInput.Key.LeftControl, true);
			controller.AddButtonKeyLightMapping(ButtonEnum.WeaponConMain, true, 3, Microsoft.DirectX.DirectInput.Key.RightControl, true);
			controller.AddButtonKeyLightMapping(ButtonEnum.WeaponConSub, true, 3, Microsoft.DirectX.DirectInput.Key.BackSpace, true);
			//controller.AddButtonKeyLightMapping(ButtonEnum.WeaponConMagazine, true, 3, Microsoft.DirectX.DirectInput.Key.X, true);
//controller.AddButtonKeyLightMapping(ButtonEnum.ToggleBufferMaterial, true, 3, Microsoft.DirectX.DirectInput.Key.LeftShift, true);
			// controller.AddButtonKeyMapping(ButtonEnum.LeftJoySightChange, Microsoft.DirectX.DirectInput.Key.V, true);
			controller.AddButtonKeyMapping(ButtonEnum.LeftJoySightChange, Microsoft.DirectX.DirectInput.Key.Z, true);
 
			joystick = new vJoy();
			acquired = joystick.acquireVJD(1);
			joystick.resetAll(); //have to reset before we use it
 
joystick.setAxis(1,32768/2,HID_USAGES.HID_USAGE_SL1);
joystick.setAxis(1,32768/2,HID_USAGES.HID_USAGE_X);
joystick.setAxis(1,32768/2,HID_USAGES.HID_USAGE_Y);
joystick.setAxis(1,32768/2,HID_USAGES.HID_USAGE_Z);//throttle
joystick.setAxis(1,32768/2,HID_USAGES.HID_USAGE_RZ);
joystick.setAxis(1,32768/2,HID_USAGES.HID_USAGE_SL0);
joystick.setAxis(1,32768/2,HID_USAGES.HID_USAGE_RX);
joystick.setAxis(1,32768/2,HID_USAGES.HID_USAGE_RY);
		}
 
		//this is necessary, as main program calls this to know how often to call mainLoop
		public int getRefreshRate()
		{
			return refreshRate;
		}
 
		private uint getDegrees(double x, double y)
		{
			uint temp = (uint)(System.Math.Atan(y / x) * (180 / Math.PI));
			if (x < 0)
				temp += 180;
			if (x > 0 && y < 0)
				temp += 360;
 
			temp += 90; //origin is vertical on POV not horizontal
 
			if (temp > 360)//by adding 90 we may have gone over 360
				temp -= 360;
 
			temp *= 100;
 
			if (temp > 35999)
				temp = 35999;
			if (temp < 0)
				temp = 0;
 
			return temp;
		}
 
		// POV to Arrow Keys
		public void updatePOVhat()
		{
			int thumbstickDeadZone = 75;
			SBC.POVdirection lastDirection = controller.POVhat;
 
			if (((Math.Abs(controller.SightChangeX) > thumbstickDeadZone) || (Math.Abs(controller.SightChangeY) > thumbstickDeadZone)))
			{
				if (Math.Abs(controller.SightChangeX) > Math.Abs(controller.SightChangeY))
					if (controller.SightChangeX < 0)
						controller.POVhat = SBC.POVdirection.LEFT;
					else
						controller.POVhat = SBC.POVdirection.RIGHT;
				else
					if (controller.SightChangeY < 0)
						controller.POVhat = SBC.POVdirection.DOWN;
					else
						controller.POVhat = SBC.POVdirection.UP;
 
			}
			else
			{
				controller.POVhat = SBC.POVdirection.CENTER;
			}
 
			if (lastDirection != controller.POVhat)
			{
				switch (lastDirection)
				{
					case SBC.POVdirection.LEFT:
						controller.sendKeyUp(Microsoft.DirectX.DirectInput.Key.Left);
						break;
					case SBC.POVdirection.RIGHT:
						controller.sendKeyUp(Microsoft.DirectX.DirectInput.Key.Right);
						break;
					case SBC.POVdirection.DOWN:
						controller.sendKeyUp(Microsoft.DirectX.DirectInput.Key.Up);
						break;
					case SBC.POVdirection.UP:
						controller.sendKeyUp(Microsoft.DirectX.DirectInput.Key.Down);
						break;
				}
			}
			else
			{
				switch (controller.POVhat)
				{
					case SBC.POVdirection.LEFT:
						controller.sendKeyDown(Microsoft.DirectX.DirectInput.Key.Left);
						break;
					case SBC.POVdirection.RIGHT:
						controller.sendKeyDown(Microsoft.DirectX.DirectInput.Key.Right);
						break;
					case SBC.POVdirection.DOWN:
						controller.sendKeyDown(Microsoft.DirectX.DirectInput.Key.Up);
						break;
					case SBC.POVdirection.UP:
						controller.sendKeyDown(Microsoft.DirectX.DirectInput.Key.Down);
						break;
				}
			}
		}
 
 
private double expo(int value)
{
double tempIn = ((double)value / (double)maxAxisValue)*2 - 1;//scale to -1 to 1
tempIn *= tempIn * 0.5;//this applies expo, we get 0 to 1 regardless of sign then multiply by 0.5 since it only represents
//half of the value
tempIn = Math.Abs(tempIn);
 
if(value >= maxAxisValue/2)
tempIn += 0.5;
else
tempIn = 0.5 - tempIn;
 
 
//debugString += "value:" + value.ToString() + " tempIn : " + tempIn.ToString() + "\n";
 
return tempIn;
}
 
 
public int scaleValue(int value, int low, int middle, int high, int deadzone)
{
double temp;
debugString += value + " " + low + " " + middle + " " + high + " " + deadzone + "\n";
if(Math.Abs(value - middle) < deadzone)
temp = ((middle-low)/(double)(high - low))*maxAxisValue;
else
{
if(value < middle)
temp = ((double)(value - low) / (double)(middle - low) * 0.5)*maxAxisValue;
else
temp = ((double)(value - middle) / (double)(high - middle) * 0.5 + 0.5)*maxAxisValue;
}
//clamp for extraneous values
if(temp > maxAxisValue)
temp = maxAxisValue;
if(temp < 0)
temp = 0;
return (int) temp;
}
 
public int scaleValue(int value, int low, int high)
{
double temp;
 
temp = ((double)(value - low) / (double)(high - low) * 0.5)*maxAxisValue;
 
//clamp for extraneous values
if(temp > maxAxisValue)
temp = maxAxisValue;
if(temp < 0)
temp = 0;
return (int) temp;
}
 
private int getDeltaS(int axisVal, int desiredVal, int currentVal,int pixelExtra)
{
int delta = desiredVal - currentVal;
//int temp  = (int) (expo(axisVal)*pixels);
//debugString += "axisVal" + axisVal.ToString() + " " + expo(axisVal).ToString() + " temp " + temp.ToString() + " "
//+ "desiredVal:" + desiredVal.ToString() + " currentVal : " + currentVal.ToString() + "\n";
double tempD = (double)axisVal/(double)maxAxisValue;
if(tempD > (1 - sideZone))//sidezone is a percentage, i.e. 0.05 for 5 percent
{
tempD = (tempD - (1- sideZone));
tempD = tempD/sideZone * pixelExtra;//defined at top
return (int)tempD;
}
if(tempD < sideZone)
{
tempD = (sideZone - tempD)/sideZone * pixelExtra;
return (int)(-1*tempD);
}
return delta;
}
 
private int reverse(int val)
{
return (maxAxisValue - val);
}
/*
//new optional function used for debugging purposes, comment out when running in game as it causes issues
public String getDebugString()
{
return debugString;
}
*/
 
 
		//this gets called once every refreshRate milliseconds by main program
		public void mainLoop()
		{
debugString = "";
			//updatePOVhat();
 
int aimingX = scaleValue(controller.AimingX,1,512,1023,5);
int aimingY = reverse(scaleValue(controller.AimingY,1,512,1021,5));//calibration values
int rAxis = scaleValue(controller.RotationLever,-421,1,510,5);//calibration values
int sCX = scaleValue(controller.SightChangeX,-461,0,470,5);
int sCY = scaleValue(controller.SightChangeX,-480,-5,463,5);
int lPedal = scaleValue(controller.LeftPedal,30,1022);
int mPedal = scaleValue(controller.MiddlePedal,128,1021);
int rPedal = scaleValue(controller.RightPedal,0,1020);
 
desiredX = (int)(expo(aimingX)*numPixelX);//numPixels stores resolution, i.e. how much we move mouse
desiredY = (int)(expo(aimingY)*numPixelY);
rAxis = (int)(expo(rAxis)*maxAxisValue);
debugString += "expoX " + expo(aimingX) + "\n";
debugString += "expoY " + expo(aimingY) + "\n";
debugString += "expoR " + expo(rAxis) + "\n";
if((bool)controller.GetButtonState(ButtonEnum.ToggleBufferMaterial))
{
 
//debugString += "aimingX:" + aimingX.ToString()  + " desiredX : " + desiredX.ToString() + "currentX " + currentX.ToString() + "\n";
//debugString += "aimingY:" + aimingY.ToString() + " desiredY : " + desiredY.ToString() + "currentY " + currentY.ToString() + "\n";
int deltaX = getDeltaS(aimingX,desiredX,currentX,numPixelExtraX);
int deltaY = getDeltaS(aimingY,desiredY,currentY,numPixelExtraY);
currentX = desiredX;
currentY = desiredY;
if(startedTracking)//makes it so you can flip the switch and recenter the joystick
InputSimulator.MoveMouseBy(deltaX,deltaY);
else
startedTracking = true;
}
else
{
startedTracking = false;
}
 
			// Joystick Axes
debugString += "rAxis = " + rAxis + "\n";
 
//joystick.setAxis(1, xaxis, HID_USAGES.HID_USAGE_X);
			//joystick.setAxis(1, yaxis, HID_USAGES.HID_USAGE_Y);
joystick.setAxis(1, rAxis, HID_USAGES.HID_USAGE_RZ);
			//joystick.setAxis(1, sCX, HID_USAGES.HID_USAGE_SL1);
			//joystick.setAxis(1, sCY, HID_USAGES.HID_USAGE_RX);
joystick.setAxis(1,(rPedal - mPedal) + maxAxisValue/2,HID_USAGES.HID_USAGE_SL0);//throttle
			//joystick.setAxis(1, controller.GearLever, HID_USAGES.HID_USAGE_SL0);
			joystick.setContPov(1, getDegrees(controller.SightChangeX, controller.SightChangeY), 1);
 
			// Pedals Section
if ((jj == 0) && (lPedal > (maxAxisValue*0.10))) // Left pedal pressed
			{
				controller.sendKeyDown(Microsoft.DirectX.DirectInput.Key.Space);
				jj = 1;
			}
			else if ((jj == 1) && (lPedal < (maxAxisValue*0.10))) // Left pedal released
			{
				controller.sendKeyUp(Microsoft.DirectX.DirectInput.Key.Space);
				jj = 0;
			}
joystick.sendUpdate(1);
		}
 
		// This gets called at the end of the program and must be present, as it cleans up resources
		public void shutDown()
		{
 
			controller.UnInit();
			joystick.Release(1);
		}
	}
}

Edited by HackNFly, 12 April 2016 - 09:42 AM.


#378 GreenHell

    Member

  • PipPipPipPipPipPipPip
  • 543 posts
  • LocationGrandmas House

Posted 12 April 2016 - 10:22 AM

What I really want is to be able to control the arm reticule (the O part) separately from the torso reticule (the + part). THEN I think we'd be able to make use of joysticks / hats to finally equal mouses. Unless I'm just a wierdo... Could also be that. Posted Image

Edit - Actually, if someone could share with me how to setup a T16000 to use the HAT for big movements, and the stick to only move as far as the arms will go, that would be perfect for me. I'd much prefer that type of control over trying to guess how far I have to set my stick to handle the whole mech. Basically, HAT for large movements and stick for fine aim.

Edited by GreenHell, 12 April 2016 - 10:28 AM.


#379 evilC

    Member

  • PipPipPipPipPipPipPipPip
  • Legendary Founder
  • Legendary Founder
  • 1,298 posts
  • LocationLondon, UK

Posted 12 April 2016 - 10:49 AM

Looking back on it, I can see how the quotes might be interpreted that way, but that was not my intention and I apologize.

"I abandoned trying to emulate a mouse though due to the enormous pain of guestimating maximum twist rates for each mech"
I basically have this one licked. To detect max twist rate, I send a big move (eg +50), then the same amount in the opposite direction but as a series of small moves (ie 50x -1). I then take a screenshot, hit center torso, then take another screenshot. If the two screenshots match, then 50 is below the max twist rate, so the code increases the rate and repeats.

Detecting twist range is also done with pixel detection. I center the torso, then keep twisting until the screen doesnt change after I issue mouse movement, which gives me the twist range in mouse units.

This code is not currently in the zip in my thread, I have some more work to do on it before I release it, hopefully tonight.

You are correct about the bit of code that controls the "buffer". To avoid any confusion, here is the logic that it follows:
I will use fake values to make the math simpler:
TWIST_RATE : The number of mouse units that a mech can twist in one tick (10ms for me). Lets use a value of 20 for this.
TWIST_RANGE: The number of mouse units that a mech can twist. Lets assume that this is 100 units from center to twisted full right.
Let's also assume that a joystick reports -100 to +100 (So center to full twist right is also 100 units)

Current mouse "position" is 0
Joystick is 50% right (+50)
Corresponding mouse move to achieve that view would be +50
TWIST_RATE is 20, so we instead only move +20
End of loop

Next "tick".
Current mouse "position" is +20
Joystick has moved to 30% right
Corresponding mouse move to achieve that view would be +10
+10 is below 20, so allow the full amount that it "wants" to move.

This code is simple in AHK, because I can only poll the joystick manually anyway (Joystick axis input in AHK is not event based), so even if the stick does not change, I get a current value each "tick". If you get joystick position in an event-based manner, then implementing this may be a bit more tricky.

Looking at that code you posted, there seems to be rather a lot of logic going on for POV hats. This is an issue that I have come up against in AHK, and I found that generally the best solution was look up tables (ie prebuilt static arrays) - conversions such as degrees to cardinal directions (At least with a normal POV where the degrees are always in 45deg increments) is actually quite quick and simple with arrays. Lemme know if you need some pointers.

Edited by evilC, 12 April 2016 - 10:54 AM.


#380 evilC

    Member

  • PipPipPipPipPipPipPipPip
  • Legendary Founder
  • Legendary Founder
  • 1,298 posts
  • LocationLondon, UK

Posted 12 April 2016 - 10:52 AM

View PostGreenHell, on 12 April 2016 - 10:22 AM, said:

What I really want is to be able to control the arm reticule (the O part) separately from the torso reticule (the + part). THEN I think we'd be able to make use of joysticks / hats to finally equal mouses. Unless I'm just a wierdo... Could also be that. Posted Image

No, you are not alone.

View PostGreenHell, on 12 April 2016 - 10:22 AM, said:

Edit - Actually, if someone could share with me how to setup a T16000 to use the HAT for big movements, and the stick to only move as far as the arms will go, that would be perfect for me. I'd much prefer that type of control over trying to guess how far I have to set my stick to handle the whole mech. Basically, HAT for large movements and stick for fine aim.

May not be technically possible. Is there still the key ?CTRL? that you can hold to look around the cockpit? I seem to remember the arms still worked in that mode. If that still worked AND you could still control the torso (eg with keys) while the button was held, then yes this may be possible, otherwise I dont see how.





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users