Previous Thread
Next Thread
Print Thread
Rate This Thread
Hop To
#3631263 - 08/23/12 03:24 AM Calling functions within TEMPO() *****  
Joined: Aug 2012
Posts: 3
Crescent_Fresh Offline
Junior Member
Crescent_Fresh  Offline
Junior Member

Joined: Aug 2012
Posts: 3
PA
I have the following line of code:
Code:
MapKey(&Throttle, APENG, TEMPO(EXEC("SlugDuration(1);"), EXEC("SlugToggle();")));


I can invoke the first function SlugDuration() all day and it's fine. However occasionally when I invoke the SlugToggle() I will get random runtime errors like "Runtime Error: Bad alias in DefEventHandler".

The contents of the functions are very similar, they each (after some conditional checks) call an ActKey() to enable/disable LED's.

Is there some technical limitation when using (held) TEMPO? Or maybe TARGET cannot handle much of a callstack and things get corrupted?

Any thoughts?

Inline advert (2nd and 3rd post)

#3637980 - 09/04/12 11:48 AM Re: Calling functions within TEMPO() [Re: Crescent_Fresh]  
Joined: Oct 2010
Posts: 83
Nicu Offline
Junior Member
Nicu  Offline
Junior Member

Joined: Oct 2010
Posts: 83
please post the content of SlugToggle()

#3638742 - 09/05/12 10:15 AM Re: Calling functions within TEMPO() [Re: Nicu]  
Joined: Oct 2010
Posts: 83
Nicu Offline
Junior Member
Nicu  Offline
Junior Member

Joined: Oct 2010
Posts: 83
Replace your target.tmh with the following content and the issue should be fixed

Code:
// TARGET definitions
// Copyright (c) Thrustmaster

include "hid.tmh"
include "defines.tmh"
alias Throttle	= "VID_044F&PID_0404", Joystick	= "VID_044F&PID_0402", LMFD		= "VID_044F&PID_b351";
alias RMFD 		= "VID_044F&PID_b352", HCougar	= "VID_044F&PID_0400", T16000	= "VID_044F&PID_B10A";

define KDATASIZE		13
define MAXKEYDATA		52*KDATASIZE	// max 52 physical+virtual keys for each device
define AXDATASIZE		64				// sizeof(sAxis)
define MAXAXDATA		16*AXDATASIZE	// max 16 physical axis for each device
struct sAxis
{
	char dxmap;
	char dir;
	int curvemode;	// 0=none, 1=S, 2=J, else=custom
	char lower, center, upper, curve;	 		// S curve parameters
	float ab;									// J curve parameter, zoom for Scurve
	char locked;
	char relative;
	int trim;
	int val, relpos;
	int key[6];		// ou, iu, om, im, od, id
}
struct sDevice
{
	int keymap[MAXKEYDATA];	// int array
	char axmap[MAXAXDATA];	// sAxis array of 16
}
sAxis axdata;
sDevice devicedata[16], devdata;

// Virtual keyboard interface
int KeyD(int c){ _key(c, OUT_VALUE_BUTTON_PRESS, 0); }
int KeyU(int c){ _key(c, OUT_VALUE_BUTTON_RELEASE, 0); }
int Key(int c, int delay=0){ _key(c, OUT_VALUE_BUTTON_PRESS_RELEASE, delay); }
int AutoRepeat(int handler, int delay, alias proc, int param){ PostEvent(EV_USR+1+handler, &proc, param, -delay); }
int StopAutoRepeat(int handler){ RemoveEvent(EV_USR+1+handler); }
int DeferCall(int delay, alias proc, int param){ PostEvent(EV_USR, &proc, param, delay); }
int PulseKey(int key, int i=0){ Key(key, kb_pulse); }
int HoldKey(int key, int press)
{ 
	if(press) KeyD(key); else KeyU(key);
	return press;
}
int DX(int index, int value=2){ VirtualOutput(OUT_TYPE_GAME, index, value); } // <index> may be DX button index - 1, axis or POV
int kb_pulse=32, kb_delay=48;
int SetKBRate(int pulse_ms=32, int delay_ms=48){ kb_pulse = pulse_ms; kb_delay = delay_ms; }
int KBLayout[] = {&ASCE, &ASCF, &ASCG};
define KB_ENG	0
define KB_FR	1
define KB_GER	2
int SetKBLayout(int layout){ &ASC = KBLayout[layout]; }

int layer_sw[9], layer;	//(&&dev[btn], flag, status) * 3
define	L_SHIFT			0x00010000
define	R_SHIFT			0x00020000
define	L_ALT			0x00040000
define	R_ALT			0x00080000
define	L_CTL			0x00100000
define	R_CTL			0x00200000
define	L_WIN			0x00400000
define	R_WIN			0x00800000
define	PULSE			0x01000000
define	DOWN			0x02000000
define	UP				0x04000000
define	PROC			0x08000000
define	JUMP			0x10000000
define	DELAY			0x20000000
define	LOCK			0x40000000
define	KEYON			0x80000000

int ActKey(int k, int x=0x7fffffff)
{
	alias hk;
	if(k & PROC)
	{
		&hk = keyalloc[k & 0xffff];
		if(x > AMAX) return hk(&keyalloc, k);
		else return hk(&keyalloc, k, x);
	}
	int press = k<0;
	if((k & (PULSE | DOWN | UP)) == PULSE)
		if(!press) return 0;
		else &hk = &PulseKey;
	else if(k & 0xffffff) &hk = &HoldKey;
		else return 0;
	if(press | !(k & (DOWN | UP)))
	{
		press = press & !(k & UP);
		kb_pulse = kb_pulse + 1;
		LockPulseTimestamps(OUT_TYPE_KEYBOARD, 1);
		if(k & L_SHIFT) hk(LSHF, press);
		if(k & R_SHIFT) hk(RSHF, press);
		if(k & L_ALT) hk(LALT, press);
		if(k & R_ALT) hk(RALT, press);
		if(k & L_CTL) hk(LCTL, press);
		if(k & R_CTL) hk(RCTL, press);
		if(k & L_WIN) hk(LWIN, press);
		if(k & R_WIN) hk(RWIN, press);
		kb_pulse = kb_pulse - 1;
		if(k & 0xffff) hk(k & 0xffff, press);
		LockPulseTimestamps(OUT_TYPE_KEYBOARD, 0);
	}
}

int DefaultMapping(alias o, int x) 
{	
	int i, k, ktbl;
	alias a;
	while(i < 9) 
		if(&&o[x] == layer_sw[i]) 
		{
			layer_sw[i+2] = layer_sw[i+2] & layer_sw[i+1] ^ o[x]; 
			if(i>0 & layer_sw[i+2]) layer_sw[11-i] = 0;
			break;
		}
		else i = i+3; 
	k = k + layer_sw[2] + ((layer_sw[8] + !layer_sw[5]) << 1);
	GetDeviceData(&o);
	if(x < IN_POSITION_AXES) 
	{
		i = x*KDATASIZE;
		Map(&ktbl, &&devdata.keymap); Dim(&ktbl, MAXKEYDATA);
		if(o[x]) ktbl[i + KDATASIZE - 1] = k;
		else
		{
			k = ktbl[i + KDATASIZE - 1];
			ActKey(ktbl[i + k]);			// key release
			k = k + 6;						// /R	
		}
		ActKey(ktbl[i + k] | KEYON);		// key press
	}
	else if(x < IN_POSITION_HAT)
	{
		GetAxisData(&o, x);
		axdata.val = AxisVal(o[x], &axdata);
		if(&o == &Throttle & (x == THR_LEFT | x == THR_RIGHT)) axdata.val = -axdata.val;
		if(!!axdata.dxmap & !axdata.locked & !axdata.relative) DXAxis(axdata.dxmap, axdata.val);
		Map(&ktbl, &&axdata.key); Dim(&ktbl, 6);
		i = 0; while(i<6)
		{
			if(ktbl[i])
				if(i == k) ActKey(ktbl[i], o[x]);
				else if(ktbl[i] != ktbl[k]) ActKey(ktbl[i], -AMAX*3);
			i = i+1;
		}
	}
	else; // ignore HAT input
}

short joy0[296]; // non present joystick dummy
int GetIndexJoy(int index)
{
	if(index < 0) return &joy0;
	char t; Dim(&t, 64);
	sprintf(&t, "&joy%u", index+1);
	return ieval(&t);
}

define MODE_EXCLUDED	0
define MODE_KEEPENABLED	1
define MODE_FILTERED	2
int Exclude(alias a){ Configure(&a, MODE_EXCLUDED); } 
int Configure(alias a, int mode){ a[0] = mode; }
int Select(alias id)
{ 
	int i = id[0];
	id[0] = 'V';
	if(i == MODE_EXCLUDED) return -1; 
	else if(i == MODE_KEEPENABLED) return SelectUsbDevice(&id, 1);
	else if(i == MODE_FILTERED) return SelectUsbDevice(&id, 2);
	return SelectUsbDevice(&id);	// 0
}

//                    BUT  HAT X   Y   Z   Rx  Ry  Rz Thrtl SLD1 SLD2 SLD3 SLD4
stGameCfg virtualj = { 32, 1,  1,  1,  1,  1,  1,  1,    1,   1,   0,   0,   0};
define CREATE_JOYSTICK	1
define CREATE_KEYBOARD	2
define CREATE_MOUSE		4
int Init(alias h, int cfg=CREATE_JOYSTICK+CREATE_KEYBOARD+CREATE_MOUSE)
{ 
	&Throttle = GetIndexJoy(Select(&Throttle));	// expect a Warthog Throttle to be plugged on USB
	&Joystick = GetIndexJoy(Select(&Joystick));	// expect a Warthog Stick to be plugged on USB
	&LMFD = GetIndexJoy(Select(&LMFD));			// expect a LMFD to be plugged on USB
	&RMFD = GetIndexJoy(Select(&RMFD));			// expect a RMFD to be plugged on USB
	&HCougar = GetIndexJoy(Select(&HCougar));		// expect a Hotas Cougar to be plugged on USB
	&T16000 = GetIndexJoy(Select(&T16000));		// expect a T16000 to be plugged on USB
	if(cfg & CREATE_JOYSTICK) PlugGame(&virtualj, "Thrustmaster Combined");						// create a Virtual device
	if(cfg & CREATE_KEYBOARD) PlugKeyboard();
	if(cfg & CREATE_MOUSE) PlugMouse(1);
	&_evh = &h;
	SetEventHandler(&DefEventHandler); 
	SEQ();		// initialize SEQ function as VPN	
	CHAIN();	// initialize CHAIN function as VPN	
	AXMAP2();
	int i; while(i<256) { USB[i] = i+1000; i = i+1; }					// fill the USB table
	MapList(&Joystick, &JoystickMap);	// default DX buttons mapping for all devices
	MapList(&Throttle, &ThrottleMap);
	MapList(&HCougar, &JoystickMap);
	MapList(&HCougar, &HCougarMap);
	MapList(&LMFD, &MFDMap);
	MapList(&RMFD, &MFDMap);
	MapList(&T16000, &T16000Map);
	i=elements(&vbtntbl); while(i>0) 	// initialize Throttle virtual buttons with 1
	{
		i = i-1;
		if(vbtntbl[i]) Throttle[vbtntbl[i]] = 1;
	}
	HCougar[DFM] = 1;					// initialize Cougar virtual buttons with 1
	HCougar[SPDM] = 1;
	DXAxis(MOUSE_X_AXIS, 0);
	DXAxis(MOUSE_Y_AXIS, 0);
}

int _gch;		// game callback handler
int RegisterGameCallback(int TCPPort, alias GameCallback)
{
	_gch = &GameCallback;
	return InitSocketServer(TCPPort);
}

alias _evh;
char h2blookup[9] = {0,1,3,2,6,4,12,8,9}, csStatus[4], h1Status[4], h1cStatus[4], h16000Status[4];
char vbtntbl[32]={0,0,0,0,0,0,SPDM,SPDM,BSM,BSM,CHM,CHM,PSM,PSM,0,EFLOVER,EFROVER,EOLNORM,EORNORM,APUOFF,0,FLAPM,FLAPM,EACOFF,RDRDIS,APDIS,APAH,APAH,IDLEROFF,IDLELOFF,EOLNORM,EORNORM};
int DefEventHandler(int e, alias dev, int event) // must be called before any processing in the event handler
{
	alloc_locked = 1;
	if(e >= EV_USR) return dev(event);
	if(e == EV_GAME_DATA) 
	{
		if(!_gch) return 0;
		e = dev;
		&dev = _gch;
		return dev(e, event);
	}
	if(&dev == &Throttle & (event == THR_LEFT | event == THR_RIGHT)) dev[event] = -dev[event];
	_evh(EV_HID_INPUT_DATA, &dev, event);
	if(&dev == &Throttle)
		if(event <= EORIGN)
			if(vbtntbl[event])			// generate virtual keys
			{
				dev[vbtntbl[event]] = !dev[event];
				_evh(EV_HID_INPUT_DATA, &dev, vbtntbl[event]);
			}
			else;
		else if(event == CS)	Hat2Btn(&dev, CS, CSU, &csStatus);		// throttle HAT
		else;
	else if(&dev == &Joystick)
		if(event == POV) Hat2Btn(&dev, POV, H1U, &h1Status);
		else;
	else if(&dev == &HCougar)
		if(event == T7 | event == T8){ dev[DFM] = !dev[event]; _evh(EV_HID_INPUT_DATA, &dev, DFM); }
		else if(event == T9 | event == T10){ dev[SPDM] = !dev[event]; _evh(EV_HID_INPUT_DATA, &dev, SPDM); }
		else if(event == POV) Hat2Btn(&dev, POV, H1U, &h1cStatus);
		else;
	else if(&dev == &T16000)
		if(event == HAT) Hat2Btn(&dev, HAT, H1U, &h16000Status);
		else;
}

int Hat2Btn(alias dev, int hat, int e, alias status)
{
	int i; while(i < 4)					// 4 virtual keys - release
	{
		dev[e+i] = 1 & h2blookup[(dev[hat]+45)/45] >> i;
		if(!dev[e+i] & status[i]) { _evh(EV_HID_INPUT_DATA, &dev, e+i); status[i] = 0; }
		i = i + 1;
	}
	while(i)										// 4 virtual keys - press
	{
		i = i - 1;
		if(dev[e+i] & !status[i]) {_evh(EV_HID_INPUT_DATA, &dev, e+i); status[i] = 1; }
	}
}

int GetDeviceData(alias dev) // fill global devdata alias based on device name (joy1, joy2,...)
{
	char t; Dim(&t, 16);
	strname(&dev, &t);
	Map(&devdata, &&devicedata[t[3]-'0']);
}

define IOTOGGLE		1
define UDTOGGLE 	2
int SetShiftButton(int devI=0, int indexI=0, int devUMD=0, int indexU=0, int indexD=0, int flag=0)
{ 
	alias io = devI, umd = devUMD;
	layer_sw = 0;
	if(devI) layer_sw[0] = &&io + (indexI << 1);
	layer_sw[1] = flag & 1;
	if(devUMD) layer_sw[3] = &&umd + (indexU << 1);
	layer_sw[4] = flag >> 1;
	if(devUMD) layer_sw[6] = &&umd + (indexD << 1);
	layer_sw[7] = layer_sw[4];
}
int MapKey(alias dev, int btnidx, int key=0, int layer=0)
{ 
	if(dev[btnidx]){ dev[btnidx] = 0; _evh(EV_HID_INPUT_DATA, &dev, btnidx); dev[btnidx] = 1;}
	layer = GetLayerBits(layer);
	GetDeviceData(&dev);
	Map(&btnidx, &&devdata.keymap+btnidx*KDATASIZE*4 + 24*!!(layer & 0x40)); Dim(&btnidx, 6);
	int i=6; while(i) 
	{
		i = i-1;
		if(layer & 1) btnidx[i] = key;
		layer = layer >> 1;
	}
}
int MapKeyIO(alias dev, int btnidx, int keyI=0, int keyO=0){ MapKeyIOUMD(&dev, btnidx, keyI, keyO, keyI, keyO, keyI, keyO); }
int MapKeyUMD(alias dev, int btnidx, int keyU=0, int keyM=0, int keyD=0){ MapKeyIOUMD(&dev, btnidx, keyU, keyU, keyM, keyM, keyD, keyD); }
int MapKeyIOUMD(alias dev, int btnidx, int keyIU=0, int keyOU=0, int keyIM=0, int keyOM=0, int keyID=0, int keyOD=0)
{
	if(dev[btnidx]){ dev[btnidx] = 0; _evh(EV_HID_INPUT_DATA, &dev, btnidx); }
	GetDeviceData(&dev);
	Map(&btnidx, &&devdata.keymap+btnidx*KDATASIZE*4); Dim(&btnidx, 6);
	btnidx[0] = keyOU;
	btnidx[1] = keyIU;
	btnidx[2] = keyOM;
	btnidx[3] = keyIM;
	btnidx[4] = keyOD;
	btnidx[5] = keyID;
}
int MapKeyR(alias dev, int btnidx, int key=0){ MapKeyRIOUMD(&dev, btnidx, key, key, key, key, key, key); }
int MapKeyRIO(alias dev, int btnidx, int keyI=0, int keyO=0){ MapKeyRIOUMD(&dev, btnidx, keyI, keyO, keyI, keyO, keyI, keyO); }
int MapKeyRUMD(alias dev, int btnidx, int keyU=0, int keyM=0, int keyD=0){ MapKeyRIOUMD(&dev, btnidx, keyU, keyU, keyM, keyM, keyD, keyD); }
int MapKeyRIOUMD(alias dev, int btnidx, int keyIU=0, int keyOU=0, int keyIM=0, int keyOM=0, int keyID=0, int keyOD=0)
{
	GetDeviceData(&dev);
	Map(&btnidx, &&devdata.keymap+btnidx*KDATASIZE*4 + 24); Dim(&btnidx, 7);
	btnidx[0] = PULSE | keyOU;
	btnidx[1] = PULSE | keyIU;
	btnidx[2] = PULSE | keyOM;
	btnidx[3] = PULSE | keyIM;
	btnidx[4] = PULSE | keyOD;
	btnidx[5] = PULSE | keyID;
	btnidx[6] = 0;							// shift status
}

int keyalloc[16384], kpos, alloc_locked, tmp[4];
int SEQ(){ Map(&SEQ, MakeProcInstance(&_SEQ), MAP_IPTR_VPN); }
int _SEQ(int i, int np, int p){ return ASMAlloc(np, p, &seqproc); }
int CHAIN(){ Map(&CHAIN, MakeProcInstance(&_CHAIN), MAP_IPTR_VPN); }
int _CHAIN(int i, int np, int p){ return ASMAlloc(np, p, &chainproc); }
int D(word ms=0){ if(!ms) ms = kb_delay; return ms | DELAY; }
int TEMPO(int x, int y, int d = 200){ tmp[0]=x; tmp[1]=y; tmp[2]=d; return ASMAlloc(3, &&tmp, &tempoproc); }
int AXIS(int x, int d, int ms){ tmp[0]=x; tmp[1]=d; tmp[2]=ms; return ASMAlloc(3, &&tmp, &axisproc); }
int EXEC(alias cmdon, int cmdoff=0){ tmp[0]=&cmdon; tmp[1]=cmdoff; return ASMAlloc(2, &&tmp, &execproc); }
int execproc(alias v, int p){ p = v[(p+2 & 0xffff) + !(p&KEYON)]; if(p) execute(p); }
define RNOSTOP	0
int REXEC(int h, word t, alias cmdon, int rstop=1){ tmp[0]=h; tmp[1]=t; tmp[2]=&cmdon; tmp[3]=rstop; return ASMAlloc(4, &&tmp, &rexecproc); }
define LED_ONOFF		0
define LED_INTENSITY	1
define LED_CURRENT		0x55555555
define LED0				0x3
define LED1				0x30
define LED2				0x300
define LED3				0x3000
define LED4				0x30000
define LED5				0x300000
int LED(alias dev, int mode, int led){ tmp[0]=&dev; tmp[1]=mode; tmp[2] = led; return ASMAlloc(3, &&tmp, &ledproc); }

int ASMAlloc(int np, int p, alias proc)
{
	int v, x;	
//	if(alloc_locked) return 0 & printf("WARNING: you can declare compound key statements (SEQ, CHAIN, EXEC, TEMPO, AXIS) only inside main() call, and not during an event.\xa");
	v = elements(&keyalloc) - kpos - 4;
	if(v < np | !np) return 0;						// not enough allocation space or no parameters
	Map(&v, p); Dim(&v, np);						// v = params array
	keyalloc[kpos] = np + 4;						// size
	keyalloc[kpos+1] = &proc;						// function
	keyalloc[kpos+2] = kpos + 2 + np;				// parameters index
	while(x < np)
	{
		keyalloc[kpos+3+x] = v[x];
		x = x+1;
	}
	keyalloc[kpos+3+np] = kpos + 3 | JUMP; 
	x = ASMFind(kpos);
	if(x == kpos) kpos = kpos + np + 4;
	return x + 1 | PROC;	// skip block size
}

int ASMFind(int x)
{
	int i, j, k; while(i < x)
	{
		k = i + keyalloc[i]; // next
		if(keyalloc[i] == keyalloc[x])	// size
			if(keyalloc[i+1] == keyalloc[x+1]) // proc
			{
				j = x-i;
				i = i+3;
				while(keyalloc[i] == keyalloc[j+i]) i = i+1;	// param
				if((keyalloc[i] & 0xffff0000) == JUMP) return x-j;
			}
		i = k; 
	}
	return x;
}

int seqproc(alias v, int p)		// key sequence procedure
{
	int flag = p & (PULSE | KEYON);	
	p = (p & 0xffff) + 1;										// params index
	if(flag & KEYON) 
	{
		v[p] = v[p] + 1;
		if(v[v[p]] & JUMP) v[p] = v[v[p]]  & 0xffff;
	}
	p = v[v[p]] | flag;
	if(p & LOCK) chainlock = !chainlock;
	return ActKey(p);
}

int chainlock;
int chaincall(int p){ chainproc(&keyalloc, p); }
int chainproc(alias v, int p)
{
	int k, press = p & KEYON;
	p = p + 1;
	do
	{
		p = p + 1;
		k = v[p & 0xffff];
		if(!!(k & LOCK) & !!press) chainlock = !chainlock;
		if(k & DELAY)
			if(chainlock) Sleep(k & 0xffff);
			else return DeferCall(k & 0xffff, &chaincall, p-1 | press);
		else if(k & JUMP) break;							// end chain
		else ActKey(k | p & PULSE | press);
	} while(1);
	chainlock = 0;
}

int tempo1(int p){ Map(&p, p); Dim(&p, 3); p[0] = 0; ActKey(p[2] | KEYON); }
int tempoproc(alias v, int p)
{
	int i = p+1 & 0xffff;
	v[i+2] = v[i+2] | (p & PULSE);
	if(p & KEYON) { v[i] = 1 | PostEvent(EV_USR+100+i, &tempo1, &&v[i], v[i+3]); }
	else 
	{
		RemoveEvent(EV_USR+100+i);
		if(v[i]) ActKey(v[i+1] | KEYON | PULSE);
		else ActKey(v[i+2]);
	}
}

int rexecproc(alias v, int p)
{ 
	int i = p+2 & 0xffff; 
	if(p & KEYON) AutoRepeat(v[i], v[i+1], &execute, v[i+2]); 
	else if(v[i+3]) StopAutoRepeat(v[i]);
}

int axis1(int p){ Map(&p, p); Dim(&p, 2); DXAxis(p[0], clip(Axis[p[0]].pos + p[1], -AMAX, AMAX)); }
int axisproc(alias v, int p)
{
	int i = p+2 & 0xffff;
	StopAutoRepeat(v[i]+32768+8);
	if(p & KEYON) AutoRepeat(v[i]+32768+8, v[i+2], &axis1, &&v[i]);
}

char ledcmd[16]={3,3,3,2,3,0,1,0,3,3,3,3,3,1,3,3};
int ledproc(alias v, int p)
{
	int k, j, i = p+2 & 0xffff;
	if(p & KEYON)
		if(v[i+1] == LED_INTENSITY) GameOutput(v[i], OUT_ID_LED_INTENSITY, v[i+2]);
		else if(v[i+1] == LED_ONOFF)
		{
			k = v[i+2] & 0xffffff ^ 0x555555; while(k)
			{
				p = ledcmd[k & 0xf];
				if(p < 3) GameOutput(v[i], OUT_ID_LED_BACKLIGHT+j, p);
				k = k >> 4;
				j = j+1;
			}
		}
}

int X(int list, int x)
{
	if(!(list & PROC)) return 0;
	list = list+1 & 0xffff;
	int n = keyalloc[list] - list;
	if(x < 0) return n;		// returns elements number
	if(x >= n) return 0;
	return keyalloc[list+x+1];
}

//x=-1..1, lower=0..1, center=0..1, upper=0..1, trim=-1..1, curve=-32..32
float fcurve(float x, float lower, float center, float upper, float trim, int curve)
{
	float m, M, cM, cm;
	m = lower+lower - 1;
	M = 1 - upper-upper;
	cM = center;
	cm = -cM;
	if(x < m) x = -1;
	else if(x < cm) 
		if(!curve) x = (x-cm)/(cm-m);
		else x = (1 - exp((cm-x)*curve))/(exp((cm-m)*curve) - 1);
 	else if(x < cM) x = 0;
 	else if(x < M)
		if(abs(curve) < 0.01) x = (x-cM)/(M-cM);
		else x =(exp((x-cM)*curve) - 1)/(exp((M-cM)*curve) - 1); 
	else x = 1;
	x = x + trim;
 	if(x < -1) x = -1;
	else if(x > 1) x = 1;
	return x;
}
float P2Curve(float x, float a, float b, float c){ return a*x*x + b*x + c; }

float LI(float x, float y, float X, float Y, float v) { return ((Y-y)*v + X*y - x*Y) / (X-x); } // linear interpolate

int clip(int i, int down, int up)
{
	if(i<down) return down;
	else if(i>up) return up;
	else return i;
}

int hatstatus, hatlkup[16]={POVCENTER, POVU, POVR, POVUR, POVD, POVCENTER, POVDR, POVCENTER, POVL, POVUL, POVCENTER, POVCENTER, POVDL, POVCENTER, POVCENTER, POVCENTER};
int HatUp(int p){ hatstatus = hatstatus & (p ^ 0xffffffff); VirtualOutput(OUT_TYPE_GAME, OUT_ID_HAT, hatlkup[hatstatus]); }
int _key(int c, int mode, int delay=0)
{
	if(c >= MOUSE_LEFT) VirtualOutput(OUT_TYPE_MOUSE, c-MOUSE_LEFT, mode, delay);
	else if(c >= DX1) // DX key
		if(c < DXHATUP) VirtualOutput(OUT_TYPE_GAME, c-DX1, mode, delay);
		else 
		{	
			c = h2blookup[c-DXHATUP+1];
			if(mode) hatstatus = hatstatus | c;
			else hatstatus = hatstatus & (c ^ 0xffffffff);
			VirtualOutput(OUT_TYPE_GAME, OUT_ID_HAT, hatlkup[hatstatus]);
			if(mode == OUT_VALUE_BUTTON_PRESS_RELEASE) DeferCall(delay, &HatUp, c);
		}
	else if(c)
	{
		if(c<256) return _key(ASC[c], mode, delay);
		if(mode != OUT_VALUE_BUTTON_RELEASE) 
			if(c > 2500) _key(RALT, mode, delay+1);
			else if(c > 2000) _key(SHF, mode, delay+1);
		VirtualOutput(OUT_TYPE_KEYBOARD, c%500, mode, delay);
		if(mode == OUT_VALUE_BUTTON_RELEASE) 
			if(c > 2500) _key(RALT, OUT_VALUE_BUTTON_RELEASE);
			else if(c > 2000) _key(SHF, OUT_VALUE_BUTTON_RELEASE);
	}
}

// ------------------------------------------- Axis functions -----------------------------
struct DXAxisStatus
{
	int pos, trim;
	char coupling;
	char lock;
	float cos, sin;
}
DXAxisStatus Axis[12]; 

int DXAxis(int index, int value)
{
	if(index < DX_X_AXIS | index > MOUSE_Z_AXIS) return 0;
	if(index == MOUSE_Z_AXIS) return DXSetAxis(index, value); // MOUSE_Z_AXIS is relative
	Axis[index].pos = value;
	value = Axis[index].coupling;
	if(value)
	{
		DXSetAxis(index,  Axis[index].pos*Axis[index].cos + Axis[value].pos*Axis[index].sin + Axis[index].trim);
		DXSetAxis(value, -Axis[index].pos*Axis[index].sin + Axis[value].pos*Axis[index].cos + Axis[value].trim);
	}
	else DXSetAxis(index, Axis[index].pos + Axis[index].trim);
}

int DXSetAxis(int index, int value)
{	
	value = clip(value, -AMAX, AMAX);
	if(!Axis[index].lock)
		if(index < MOUSE_X_AXIS) DX(index-1+OUT_ID_AXIS, value);
		else VirtualOutput(OUT_TYPE_MOUSE, index-MOUSE_X_AXIS+OUT_ID_AXIS, value);
}

int RotateDXAxis(int XAxis, int YAxis, float angle) // clockwise angle, in degrees
{
	angle = angle * 3.1415926 / 180;
	Axis[XAxis].coupling = YAxis;
	Axis[XAxis].cos = cos(angle);
	Axis[XAxis].sin = -sin(angle);
	Axis[YAxis].coupling = XAxis;
	Axis[YAxis].cos = cos(angle);
	Axis[YAxis].sin = sin(angle);
}

define CURRENT	0x20000
int SET(int i){ return i & 0xffff | 0x10000; }
int TrimDXAxis(int index, int value) // 1024 values
{
	short t = value;
	if(abs(value) < 0x3ff) Axis[index].trim = Axis[index].trim + (t << 5);
	else if(value > 0)
		if(value & 0x10000) Axis[index].trim = t << 5;
		else if(value & CURRENT) Axis[index].trim = Axis[index].pos + Axis[index].trim;
	Axis[index].trim = clip(Axis[index].trim, -AMAX, AMAX);
	DXAxis(index, Axis[index].pos);
}

int LockDXAxis(int index, char lock)
{ 
	Axis[index].lock = lock; 
	if(!lock) DXAxis(index, Axis[index].pos);
}

int GetAxisData(alias o, int x) // maps the global <axdata>
{
	if(x >= IN_POSITION_AXES & x < IN_POSITION_HAT)
	{
		GetDeviceData(&o);
		Map(&axdata, &&devdata.axmap + (x-IN_POSITION_AXES)*AXDATASIZE);
		return 1;
	}
}

int MapAxis(alias o, int x, int dx=0, int dir=AXIS_NORMAL, int relative=MAP_ABSOLUTE)
{ 
	if(!GetAxisData(&o, x)) return 0;
	if(!!axdata.dxmap & axdata.relative) StopAutoRepeat(32767+axdata.dxmap);
	axdata.dxmap = dx; 
	axdata.dir = dir - 1;
	axdata.relative = relative;
//	axdata.relpos = 0;
	if(!!dx & relative) AutoRepeat(32767+dx, 20, &RJLoop, &&axdata);
}

int SetSCurve(alias o, int x, int lower=0, int center=0, int upper=0, int curve=0, float zoom=0) // all percents, curve = -32..32
{
	if(!GetAxisData(&o, x)) return 0;
	axdata.curvemode = 1;
	axdata.lower = lower;
	axdata.center = center;
	axdata.upper = upper;
	axdata.curve = curve;
	axdata.ab = zoom;
	axdata.val = AxisVal(o[x], &axdata);
}

int SetJCurve(alias o, int x, float in, float out) // in, out = percents
{
	if(!GetAxisData(&o, x)) return 0;
	axdata.curvemode = 2;
	axdata.ab = 50*(in - out) / (in*(in - 100));
	axdata.val = AxisVal(o[x], &axdata);
}

int SetCustomCurve(alias o, int x, int list)
{
	if(!GetAxisData(&o, x)) return 0;
	if(list & PROC) axdata.curvemode = list;
	else axdata.curvemode = 0;
	axdata.val = AxisVal(o[x], &axdata);
}

float GetCustomCurveValue(int p, float v)
{
	p = p + 1 & 0xffff;
	int n = keyalloc[p];	// list end
	int i = p+1;
	if(i>=n) return v;
	while(i<n)
		if(keyalloc[i] < v) i=i+2;
		else if(i == p+1) return LI(0, 0, keyalloc[i], keyalloc[i+1], v);
		else return LI(keyalloc[i-2], keyalloc[i-1], keyalloc[i], keyalloc[i+1], v);
	return LI(keyalloc[i-2], keyalloc[i-1], 100, 100, v);
}

int LockAxis(alias o, int x, int lock){ if(GetAxisData(&o, x)) axdata.locked = lock; }

int AxisVal(int v, alias d)
{
	if(d.curvemode == 0);		// no curve, keeps v unchanged
	else if(d.curvemode == 1) v = AMAX*pow(1.41, d.ab)*fcurve(v/AMAXF, d.lower*0.01, d.center*0.01, d.upper*0.01, 0, d.curve);  
	else if(d.curvemode == 2) v = AMAX*P2Curve(v/AMAXF, -d.ab, 1, d.ab);
	else v = AMAX*GetCustomCurveValue(d.curvemode, v*50/AMAXF + 50)/50 - AMAX; 	// custom curve
	return v*(1 + axdata.dir);
}

int RJLoop(int p)
{
	Map(&axdata, p);
	p = axdata.val * !axdata.locked;
	axdata.relpos = clip(axdata.relpos + p, -AMAX*10, AMAX*10);
	if(p) DXAxis(axdata.dxmap, axdata.relpos/10);
}

char gllk[32] = {0x3f, 3, 0xc, 0xf, 0x30, 0x33, 0x3c, 0x3f, 0x2a, 2, 8, 0xa, 0x20, 0x22, 0x28, 0x2a, 0x15, 1, 4, 5, 0x10, 0x11, 0x14, 0x15, 0x3f, 3, 0xc, 0xf, 0x30, 0x33, 0x3c, 0x3f};
int GetLayerBits(int layer) // layer is a word constant, containing i,o,u,m,d, like 'i', or 'iu'
{
	layer = layer & 0x7fffffff;
	char c, mask = 0;
	do
	{	
		c = layer & 0xff;
		mask = mask | (1 << strchr("dmuoir", c));
		layer = layer >> 8;
	} 
	while(layer);
	return gllk[mask & 0x1f] | ((mask & 0x20) << 1);	
}

int KeyAxis(alias o, int x, int layer, int mode)
{
	if(!GetAxisData(&o, x)) return 0;
	layer = GetLayerBits(layer) & 0x3f;		// ignore 'r' bit
	Map(&x, &&axdata.key + 20);
	while(layer)
	{
		if(layer & 1) x = mode;
		layer = layer >> 1;
		Map(&x, &&x-4);
	}
}

int AXMAP1(int n, int u, int d, int c=-1){ Dim(&n, 4); n[1]=u; n[2]=d; n[3]=c; return ASMAlloc(4, &&n, &axmap1proc); }
int axmap1proc(alias v, int p, int x)
{
	Map(&p, &&v[p + 1 & 0xffff]); Dim(&p, 5);
	int n = p[1], center=p[4]>=0;
	if(n & PROC) 
	{
		n = n + 1 & 0xffff;
		n = v[n] - n - 1;	// list size - 1
		center = center & n;
		x = GetListPos(&v, p[1], (x+AMAX)*100 / (AMAX+AMAX+1)) - 1;
	}
	else 
	{
		center = center & (n + 1);
		n = n + center;
		x = ((x + AMAX)*(n + 1) + AMAX) / (AMAX+AMAX+1) - 1;
	}
	int y = -p[0] >> 1;	// last position
	int up = p[0] & 1;
	if(center) center = n >> 1;
	else center = -1;
	while(y != x) 
	{
		if(y>=0 & y<n)
			if(y==center) ActKey(p[4]); 
			else ActKey(p[3-up]);
		if(x < -1) break;
		up = y < x;
		if(y < -1) y = x;		
		else y = y + (up << 1) - 1;
		if(y>=0 & y<n)
			if(y==center) ActKey(p[4] | KEYON); 
			else ActKey(p[3-up] | KEYON); 
	}
	p[0] = -((x << 1) + up);
}

define LIST AXMAP2
int AXMAP2(){ Map(&AXMAP2, MakeProcInstance(&_AXMAP2), MAP_IPTR_VPN); }
int _AXMAP2(int i, int np, int p){ return ASMAlloc(np, p, &axmap2proc); }
int axmap2proc(alias v, int p, int x)
{
	int i = p + 1 & 0xffff;
	Map(&p, &&v[i]); Dim(&p, v[i+1]+2);
	if(p[1] & PROC) x = GetListPos(&v, p[1], (x+AMAX)*100 / (AMAX+AMAX+1)) - 1;
	else x = (x + AMAX) * p[1] / (AMAX+AMAX+1);
	int y = -v[p[0]+1];
	while(y != x)
	{
		if(y>=0 & 1+y<p[0]-i) ActKey(p[2+y]);
		if(x < -1) break;
		if(y < -1) y = x;
		else y = y + ((y<x) << 1) - 1;
		if(y>=0 & 1+y<p[0]-i) ActKey(p[2+y] | KEYON);
	}
	v[p[0]+1] = -x;
}

int GetListPos(alias v, int p, short x)
{
	p = (p & 0xffff) + 2;
	if(x < 0) return -1;
	int pos; while(v[p+pos] <= x) pos = pos+1;
	return pos;
}

// ------------------------------------------- Default button mapping  -----------------------------
int JoystickMap[]={TG1,DX1, S2,DX2, S3,DX3, S4,DX4, S1,DX5, TG2,DX6, H2U,DX7, H2R,DX8, H2D,DX9, H2L,DX10, H3U,DX11, H3R,DX12, H3D,DX13, H3L,DX14,
				   H4U,DX15, H4R,DX16, H4D,DX17, H4L,DX18, H4P,DX19, H1U,DXHATUP, H1R,DXHATRIGHT, H1D,DXHATDOWN, H1L,DXHATLEFT};
int ThrottleMap[]={LTB,DX20, SC,DX21, CSU,DX22, CSR,DX23, CSD,DX24, CSL,DX25, MSP,DX26, MSU,DX27, MSR,DX28, MSD,DX29, MSL,DX30, SPDF,DX31, SPDB,DX32};
int HCougarMap[] ={T1,DX19, T3,DX20, T2,DX21, T4,DX22, T5,DX23, T6,DX24, T7,DX25, T8,DX26, T9,DX27, T10,DX28};
int MFDMap[]	 ={OSB01,DX1, OSB02,DX2, OSB03,DX3, OSB04,DX4, OSB05,DX5, OSB06,DX6, OSB07,DX7, OSB08,DX8, OSB09,DX9, OSB10,DX10, OSB11,DX11, OSB12,DX12,
				   OSB13,DX13, OSB14,DX14, OSB15,DX15, OSB16,DX16, OSB17,DX17, OSB18,DX18, OSB19,DX19, OSB20,DX20, SYMU,DX21, SYMD,DX22, CONU,DX23,
				   COND,DX24, BRTU,DX25, BRTD,DX26, GAINU,DX27, GAIND,DX28};
int T16000Map[]	 ={TS1,DX1, TS2,DX2, TS3,DX3, TS4,DX4, B5,DX5, B6,DX6, B7,DX7, B8,DX8, B9,DX9, B10,DX10, B11,DX11, B12,DX12, B13,DX13, B14,DX14, B15,DX15,
				   B16,DX16};

int MapList(alias dev, alias list)
{
	int i, e = elements(&list); while(i<e)
	{
		MapKey(&dev, list[i], list[i+1]);
		i = i+2;
	}
}


Moderated by  RacerGT 

Quick Search
Recent Articles
Support SimHQ

If you shop on Amazon use this Amazon link to support SimHQ
.
Social


Recent Topics
Actors portraying British Prime Ministers
by Tarnsman. 04/24/24 01:11 AM
Roy Cross is 100 Years Old
by F4UDash4. 04/23/24 11:22 AM
Actors portraying US Presidents
by PanzerMeyer. 04/19/24 12:19 PM
Dickey Betts was 80
by Rick_Rawlings. 04/19/24 01:11 AM
Exodus
by RedOneAlpha. 04/18/24 05:46 PM
Grumman Wildcat unique landing gear
by Coot. 04/17/24 03:54 PM
Peter Higgs was 94
by Rick_Rawlings. 04/17/24 12:28 AM
Whitey Herzog was 92
by F4UDash4. 04/16/24 04:41 PM
Copyright 1997-2016, SimHQ Inc. All Rights Reserved.

Powered by UBB.threads™ PHP Forum Software 7.6.0