798 lines
32 KiB
C++
798 lines
32 KiB
C++
/***************************************************************************
|
|
|
|
file : controlconfig.cpp
|
|
created : Wed Mar 12 21:20:34 CET 2003
|
|
copyright : (C) 2003 by Eric Espie
|
|
email : eric.espie@torcs.org
|
|
version : $Id$
|
|
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
/** @file
|
|
Human player control configuration menu
|
|
@author <a href=mailto:eric.espie@torcs.org>Eric Espie</a>
|
|
@version $Id$
|
|
*/
|
|
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <string>
|
|
|
|
#include <tgf.hpp>
|
|
#include <tgfclient.h>
|
|
#include <track.h>
|
|
#include <robot.h>
|
|
#include <playerpref.h>
|
|
|
|
#include "controlconfig.h"
|
|
#include "mouseconfig.h"
|
|
#include "joystickconfig.h"
|
|
#include "joy2butconfig.h"
|
|
|
|
|
|
static void *ScrHandle = NULL;
|
|
static void *PrevScrHandle = NULL;
|
|
static void *PrefHdle = NULL;
|
|
static int SaveOnExit = 0;
|
|
|
|
static tCtrlMouseInfo MouseInfo;
|
|
static char CurrentSection[256];
|
|
|
|
/* Control command information */
|
|
static tCmdInfo Cmd[] = {
|
|
{HM_ATT_LEFTSTEER, {1, GFCTRL_TYPE_MOUSE_AXIS}, 0, 0, HM_ATT_LEFTSTEER_MIN, 0, HM_ATT_LEFTSTEER_MAX, 0, HM_ATT_LEFTSTEER_POW, 1.0, 1, HM_ATT_JOY_PREF_AXIS, 0},
|
|
{HM_ATT_RIGHTSTEER, {2, GFCTRL_TYPE_MOUSE_AXIS}, 0, 0, HM_ATT_RIGHTSTEER_MIN, 0, HM_ATT_RIGHTSTEER_MAX, 0, HM_ATT_RIGHTSTEER_POW, 1.0, 1, HM_ATT_JOY_PREF_AXIS, 0},
|
|
{HM_ATT_THROTTLE, {1, GFCTRL_TYPE_MOUSE_BUT}, 0, 0, HM_ATT_THROTTLE_MIN, 0, HM_ATT_THROTTLE_MAX, 0, HM_ATT_THROTTLE_POW, 1.0, 1, HM_ATT_JOY_PREF_AXIS, 0},
|
|
{HM_ATT_BRAKE, {2, GFCTRL_TYPE_MOUSE_BUT}, 0, 0, HM_ATT_BRAKE_MIN, 0, HM_ATT_BRAKE_MAX, 0, HM_ATT_BRAKE_POW, 1.0, 1, HM_ATT_JOY_PREF_AXIS, 0},
|
|
{HM_ATT_CLUTCH, {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, HM_ATT_CLUTCH_MIN, 0, HM_ATT_CLUTCH_MAX, 0, HM_ATT_CLUTCH_POW, 1.0, 1, HM_ATT_JOY_PREF_AXIS, 0},
|
|
{HM_ATT_ABS_CMD, {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, HM_ATT_ABS_MIN, 0, HM_ATT_ABS_MAX, 0, 0, 0, 1, HM_ATT_JOY_REQ_BUT, 0},
|
|
{HM_ATT_ASR_CMD, {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, HM_ATT_ASR_MIN, 0, HM_ATT_ASR_MAX, 0, 0, 0, 1, HM_ATT_JOY_REQ_BUT, 0},
|
|
{HM_ATT_SPDLIM_CMD, {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, HM_ATT_SPDLIM_MIN, 0, HM_ATT_SPDLIM_MAX, 0, 0, 0, 1, HM_ATT_JOY_REQ_BUT, 0},
|
|
{HM_ATT_LIGHT1_CMD, {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, HM_ATT_LIGHT1_MIN, 0, HM_ATT_LIGHT1_MAX, 0, 0, 0, 1, HM_ATT_JOY_REQ_BUT, 0},
|
|
{HM_ATT_GEAR_R, {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, HM_ATT_GEAR_R_MIN, 0, HM_ATT_GEAR_R_MAX, 0, 0, 0, 1, HM_ATT_JOY_REQ_BUT, 0},
|
|
{HM_ATT_GEAR_N, {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, HM_ATT_GEAR_N_MIN, 0, HM_ATT_GEAR_N_MAX, 0, 0, 0, 1, HM_ATT_JOY_REQ_BUT, 0},
|
|
{HM_ATT_DN_SHFT, {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, HM_ATT_DN_SHFT_MIN, 0, HM_ATT_DN_SHFT_MAX, 0, 0, 0, 1, HM_ATT_JOY_REQ_BUT, 0},
|
|
{HM_ATT_UP_SHFT, {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, HM_ATT_UP_SHFT_MIN, 0, HM_ATT_UP_SHFT_MAX, 0, 0, 0, 1, HM_ATT_JOY_REQ_BUT, 0},
|
|
{HM_ATT_GEAR_1, {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, 0, 0, 0, 0, 0, 0, 1, HM_ATT_JOY_REQ_BUT, 0},
|
|
{HM_ATT_GEAR_2, {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, 0, 0, 0, 0, 0, 0, 1, HM_ATT_JOY_REQ_BUT, 0},
|
|
{HM_ATT_GEAR_3, {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, 0, 0, 0, 0, 0, 0, 1, HM_ATT_JOY_REQ_BUT, 0},
|
|
{HM_ATT_GEAR_4, {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, 0, 0, 0, 0, 0, 0, 1, HM_ATT_JOY_REQ_BUT, 0},
|
|
{HM_ATT_GEAR_5, {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, 0, 0, 0, 0, 0, 0, 1, HM_ATT_JOY_REQ_BUT, 0},
|
|
{HM_ATT_GEAR_6, {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, 0, 0, 0, 0, 0, 0, 1, HM_ATT_JOY_REQ_BUT, 0},
|
|
{HM_ATT_EBRAKE_CMD, {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, HM_ATT_EBRAKE_MIN, 0, HM_ATT_EBRAKE_MAX, 0, 0, 0, 1, HM_ATT_JOY_REQ_BUT, 0},
|
|
{HM_ATT_HBOX_X, {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, HM_ATT_HBOX_X_MIN, -1, HM_ATT_HBOX_X_MAX, 1, 0, 0, 1, HM_ATT_JOY_REQ_AXIS, 0},
|
|
{HM_ATT_HBOX_Y, {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, HM_ATT_HBOX_Y_MIN, -1, HM_ATT_HBOX_Y_MAX, 1, 0, 0, 1, HM_ATT_JOY_REQ_AXIS, 0},
|
|
|
|
{HM_ATT_CAM_LOOKBACK ,{-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, 0, 0, 0, 0, 0, 0, 1, HM_ATT_JOY_REQ_BUT, 0},
|
|
{HM_ATT_LEFTGLANCE, {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, HM_ATT_L_GLANCE_MIN, -1, HM_ATT_L_GLANCE_MAX,-0.1, 0, 0, 1, HM_ATT_JOY_PREF_ANY, 0},
|
|
{HM_ATT_RIGHTGLANCE,{-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, HM_ATT_R_GLANCE_MIN, 0.1, HM_ATT_R_GLANCE_MAX, 1, 0, 0, 1, HM_ATT_JOY_PREF_ANY, 0},
|
|
{HM_ATT_DASHB_NEXT, {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, HM_ATT_DASHB_NEXT_MIN, 0, HM_ATT_DASHB_NEXT_MAX,0, 0, 0, 1, HM_ATT_JOY_REQ_BUT, 0},
|
|
{HM_ATT_DASHB_PREV, {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, HM_ATT_DASHB_PREV_MIN, 0, HM_ATT_DASHB_PREV_MAX,0, 0, 0, 1, HM_ATT_JOY_REQ_BUT, 0},
|
|
{HM_ATT_DASHB_INC , {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, HM_ATT_DASHB_INC_MIN, 0, HM_ATT_DASHB_INC_MAX, 0, 0, 0, 1, HM_ATT_JOY_REQ_BUT, 0},
|
|
{HM_ATT_DASHB_DEC , {-1, GFCTRL_TYPE_NOT_AFFECTED}, 0, 0, HM_ATT_DASHB_DEC_MIN, 0, HM_ATT_DASHB_DEC_MAX, 0, 0, 0, 1, HM_ATT_JOY_REQ_BUT, 0}
|
|
};
|
|
|
|
static const int MaxCmd = sizeof(Cmd) / sizeof(Cmd[0]);
|
|
static const int ICmdReverseGear = 9;
|
|
static const int ICmdNeutralGear = 10;
|
|
|
|
/* Command editbox display info according to the selected gear changing mode */
|
|
typedef struct tCmdDispInfo
|
|
{
|
|
unsigned gearChangeModeMask;
|
|
} tCmdDispInfo;
|
|
|
|
static tCmdDispInfo CmdDispInfo[] = {
|
|
{ GEAR_MODE_AUTO | GEAR_MODE_SEQ | GEAR_MODE_GRID | GEAR_MODE_HBOX }, // LEFTSTEER,
|
|
{ GEAR_MODE_AUTO | GEAR_MODE_SEQ | GEAR_MODE_GRID | GEAR_MODE_HBOX }, // RIGHTSTEER
|
|
{ GEAR_MODE_AUTO | GEAR_MODE_SEQ | GEAR_MODE_GRID | GEAR_MODE_HBOX }, // THROTTLE,
|
|
{ GEAR_MODE_AUTO | GEAR_MODE_SEQ | GEAR_MODE_GRID | GEAR_MODE_HBOX }, // BRAKE,
|
|
{ GEAR_MODE_AUTO | GEAR_MODE_SEQ | GEAR_MODE_GRID | GEAR_MODE_HBOX }, // CLUTCH,
|
|
{ GEAR_MODE_AUTO | GEAR_MODE_SEQ | GEAR_MODE_GRID | GEAR_MODE_HBOX }, // ABS_CMD,
|
|
{ GEAR_MODE_AUTO | GEAR_MODE_SEQ | GEAR_MODE_GRID | GEAR_MODE_HBOX }, // ASR_CMD,
|
|
{ GEAR_MODE_AUTO | GEAR_MODE_SEQ | GEAR_MODE_GRID | GEAR_MODE_HBOX }, // SPDLIM_CMD
|
|
{ GEAR_MODE_AUTO | GEAR_MODE_SEQ | GEAR_MODE_GRID | GEAR_MODE_HBOX }, // LIGHT1_CMD
|
|
{ GEAR_MODE_AUTO | GEAR_MODE_SEQ | GEAR_MODE_GRID | GEAR_MODE_HBOX }, // GEAR_R,
|
|
{ GEAR_MODE_AUTO | GEAR_MODE_SEQ | GEAR_MODE_GRID | GEAR_MODE_HBOX }, // GEAR_N,
|
|
{ GEAR_MODE_AUTO | GEAR_MODE_SEQ }, // DN_SHFT,
|
|
{ GEAR_MODE_AUTO | GEAR_MODE_SEQ }, // UP_SHFT,
|
|
{ GEAR_MODE_GRID }, // GEAR_1,
|
|
{ GEAR_MODE_GRID }, // GEAR_2,
|
|
{ GEAR_MODE_GRID }, // GEAR_3,
|
|
{ GEAR_MODE_GRID }, // GEAR_4,
|
|
{ GEAR_MODE_GRID }, // GEAR_5,
|
|
{ GEAR_MODE_GRID }, // GEAR_6,
|
|
{ GEAR_MODE_AUTO | GEAR_MODE_SEQ | GEAR_MODE_GRID | GEAR_MODE_HBOX }, // EBRAKE_CMD
|
|
{ GEAR_MODE_HBOX }, // GEAR_X,
|
|
{ GEAR_MODE_HBOX }, // GEAR_Y,
|
|
{ GEAR_MODE_AUTO | GEAR_MODE_SEQ | GEAR_MODE_GRID | GEAR_MODE_HBOX }, // LOOKBEHINDCAMERA,
|
|
{ GEAR_MODE_AUTO | GEAR_MODE_SEQ | GEAR_MODE_GRID | GEAR_MODE_HBOX }, // LEFTGLANCE,
|
|
{ GEAR_MODE_AUTO | GEAR_MODE_SEQ | GEAR_MODE_GRID | GEAR_MODE_HBOX }, // RIGHTGLANCE
|
|
{ GEAR_MODE_AUTO | GEAR_MODE_SEQ | GEAR_MODE_GRID | GEAR_MODE_HBOX }, // DASHBOARD NEXT
|
|
{ GEAR_MODE_AUTO | GEAR_MODE_SEQ | GEAR_MODE_GRID | GEAR_MODE_HBOX }, // DASHBOARD PREVIOUS
|
|
{ GEAR_MODE_AUTO | GEAR_MODE_SEQ | GEAR_MODE_GRID | GEAR_MODE_HBOX }, // DASHBOARD INC
|
|
{ GEAR_MODE_AUTO | GEAR_MODE_SEQ | GEAR_MODE_GRID | GEAR_MODE_HBOX } // DASHBOARD DEC
|
|
};
|
|
|
|
static tCtrlJoyInfo joyInfo;// = NULL;
|
|
static tCtrlJoyInfo joyCenter;
|
|
|
|
static float SteerSensVal;
|
|
static float DeadZoneVal;
|
|
static float SteerSpeedSensVal;
|
|
|
|
static char buf[1024];
|
|
|
|
static int SteerSensEditId;
|
|
static int DeadZoneLabelId;
|
|
static int DeadZoneEditId;
|
|
static int SteerSpeedSensEditId;
|
|
static int CalibrateButtonId;
|
|
|
|
static tGearChangeMode GearChangeMode;
|
|
|
|
static int ReloadValues = 1;
|
|
|
|
static int AcceptMouseClicks = 1;
|
|
|
|
static int MouseCalNeeded;
|
|
static int JoyCalNeeded;
|
|
static int Joy2butCalNeeded;
|
|
|
|
static void
|
|
onSteerSensChange(void * /* dummy */)
|
|
{
|
|
char *val;
|
|
float fv;
|
|
|
|
val = GfuiEditboxGetString(ScrHandle, SteerSensEditId);
|
|
if (sscanf(val, "%f", &fv) == 1) {
|
|
if (fv <= 0.0)
|
|
fv = 1.0e-6;
|
|
sprintf(buf, "%6.4f", fv);
|
|
GfuiEditboxSetString(ScrHandle, SteerSensEditId, buf);
|
|
SteerSensVal = fv;
|
|
} else {
|
|
GfuiEditboxSetString(ScrHandle, SteerSensEditId, "");
|
|
}
|
|
}
|
|
|
|
static void
|
|
onDeadZoneChange(void * /* dummy */)
|
|
{
|
|
char *val;
|
|
float fv;
|
|
|
|
val = GfuiEditboxGetString(ScrHandle, DeadZoneEditId);
|
|
if (sscanf(val, "%f", &fv) == 1) {
|
|
if (fv < 0.0)
|
|
fv = 0.0;
|
|
else if (fv > 1.0)
|
|
fv = 1.0;
|
|
sprintf(buf, "%6.4f", fv);
|
|
GfuiEditboxSetString(ScrHandle, DeadZoneEditId, buf);
|
|
DeadZoneVal = fv;
|
|
} else {
|
|
GfuiEditboxSetString(ScrHandle, SteerSensEditId, "");
|
|
}
|
|
}
|
|
|
|
static void
|
|
onSteerSpeedSensChange(void * /* dummy */)
|
|
{
|
|
char *val;
|
|
float fv;
|
|
|
|
val = GfuiEditboxGetString(ScrHandle, SteerSpeedSensEditId);
|
|
if (sscanf(val, "%f", &fv) == 1) {
|
|
if (fv < 0.0)
|
|
fv = 0.0;
|
|
sprintf(buf, "%6.4f", fv);
|
|
GfuiEditboxSetString(ScrHandle, SteerSpeedSensEditId, buf);
|
|
SteerSpeedSensVal = fv;
|
|
} else {
|
|
GfuiEditboxSetString(ScrHandle, SteerSpeedSensEditId, "");
|
|
}
|
|
}
|
|
|
|
/* Quit current menu */
|
|
static void
|
|
onQuit(void *prevMenu)
|
|
{
|
|
/* Release joysticks */
|
|
// GfctrlJoyRelease(joyInfo);
|
|
|
|
/* Back to previous screen */
|
|
GfuiScreenActivate(prevMenu);
|
|
}
|
|
|
|
/* Save settings in the players preferences and go back to previous screen */
|
|
static void
|
|
onSave(void *prevMenu)
|
|
{
|
|
// Force current edit to loose focus (if one has it) and update associated variable.
|
|
GfuiUnSelectCurrent();
|
|
|
|
ControlPutSettings();
|
|
|
|
onQuit(prevMenu);
|
|
}
|
|
|
|
static void
|
|
updateButtonText(void)
|
|
{
|
|
int cmdInd;
|
|
const char *str;
|
|
|
|
/* No calibration / no dead zone needed for the moment (but let's check this ...) */
|
|
MouseCalNeeded = 0;
|
|
JoyCalNeeded = 0;
|
|
Joy2butCalNeeded = 0;
|
|
|
|
/* For each control: */
|
|
for (cmdInd = 0; cmdInd < MaxCmd; cmdInd++) {
|
|
|
|
/* Update associated editbox according to detected input device action */
|
|
str = GfctrlGetNameByRef(Cmd[cmdInd].ref.type, Cmd[cmdInd].ref.index);
|
|
if (str) {
|
|
GfuiButtonSetText (ScrHandle, Cmd[cmdInd].Id, str);
|
|
} else {
|
|
GfuiButtonSetText (ScrHandle, Cmd[cmdInd].Id, "---");
|
|
}
|
|
|
|
/* According to detected action, update the "calibration needed" flags */
|
|
if (Cmd[cmdInd].ref.type == GFCTRL_TYPE_MOUSE_AXIS) {
|
|
MouseCalNeeded = 1;
|
|
} else if (Cmd[cmdInd].ref.type == GFCTRL_TYPE_JOY_AXIS) {
|
|
JoyCalNeeded = 1;
|
|
} else if (Cmd[cmdInd].ref.type == GFCTRL_TYPE_JOY_ATOB) {
|
|
Joy2butCalNeeded = 1;
|
|
}
|
|
}
|
|
|
|
/* According to detected action, update the "dead zone needed" flag */
|
|
int deadZoneNeeded = 1;
|
|
if ((Cmd[0].ref.type == GFCTRL_TYPE_KEYBOARD
|
|
|| Cmd[0].ref.type == GFCTRL_TYPE_JOY_BUT
|
|
|| Cmd[0].ref.type == GFCTRL_TYPE_MOUSE_BUT)
|
|
&& (Cmd[1].ref.type == GFCTRL_TYPE_KEYBOARD
|
|
|| Cmd[1].ref.type == GFCTRL_TYPE_JOY_BUT
|
|
|| Cmd[1].ref.type == GFCTRL_TYPE_MOUSE_BUT)) {
|
|
deadZoneNeeded = 0;
|
|
}
|
|
|
|
/* Update Steer Sensibility editbox */
|
|
sprintf(buf, "%6.4f", SteerSensVal);
|
|
GfuiEditboxSetString(ScrHandle, SteerSensEditId, buf);
|
|
|
|
/* Update Steer Dead Zone editbox */
|
|
sprintf(buf, "%6.4f", DeadZoneVal);
|
|
GfuiEditboxSetString(ScrHandle, DeadZoneEditId, buf);
|
|
|
|
/* Update Steer Speed Sensitivity editbox */
|
|
sprintf(buf, "%6.4f", SteerSpeedSensVal);
|
|
GfuiEditboxSetString(ScrHandle, SteerSpeedSensEditId, buf);
|
|
|
|
/* Show / hide mouse / joystick calibration button,
|
|
according to the detected input device actions */
|
|
GfuiVisibilitySet(ScrHandle, CalibrateButtonId,
|
|
MouseCalNeeded|JoyCalNeeded|Joy2butCalNeeded ? GFUI_VISIBLE : GFUI_INVISIBLE);
|
|
|
|
/* Show / hide dead zone label /editbox,
|
|
according to the detected input device actions */
|
|
GfuiVisibilitySet(ScrHandle, DeadZoneLabelId,
|
|
deadZoneNeeded ? GFUI_VISIBLE : GFUI_INVISIBLE);
|
|
GfuiVisibilitySet(ScrHandle, DeadZoneEditId,
|
|
deadZoneNeeded ? GFUI_VISIBLE : GFUI_INVISIBLE);
|
|
}
|
|
|
|
static void
|
|
onFocusLost(void * /* dummy */)
|
|
{
|
|
updateButtonText();
|
|
}
|
|
|
|
static int CurrentCmd;
|
|
|
|
static int InputWaited = 0;
|
|
|
|
static int
|
|
onKeyAction(int key, int /* modifier */, int state)
|
|
{
|
|
if (!InputWaited || state == GFUI_KEY_UP) {
|
|
return 0;
|
|
}
|
|
if (key == GFUIK_RSHIFT || key == GFUIK_LSHIFT) {
|
|
return 0;
|
|
}
|
|
if (key == GFUIK_ESCAPE) {
|
|
/* escape */
|
|
Cmd[CurrentCmd].ref.index = -1;
|
|
Cmd[CurrentCmd].ref.type = GFCTRL_TYPE_NOT_AFFECTED;
|
|
GfParmSetStr(PrefHdle, CurrentSection, Cmd[CurrentCmd].name, "");
|
|
} else {
|
|
const char* name = GfctrlGetNameByRef(GFCTRL_TYPE_KEYBOARD, key);
|
|
Cmd[CurrentCmd].ref.index = key;
|
|
Cmd[CurrentCmd].ref.type = GFCTRL_TYPE_KEYBOARD;
|
|
GfParmSetStr(PrefHdle, CurrentSection, Cmd[CurrentCmd].name, name);
|
|
}
|
|
|
|
GfuiApp().eventLoop().setRecomputeCB(0);
|
|
InputWaited = 0;
|
|
updateButtonText();
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
getMovedAxis(int joy_number)
|
|
{
|
|
int i;
|
|
int Index = -1;
|
|
float maxDiff = 0.3;
|
|
|
|
for (i = GFCTRL_JOY_MAX_AXES * joy_number; i < GFCTRL_JOY_MAX_AXES * (joy_number+1); i++) {
|
|
if (maxDiff < fabs(joyInfo.ax[i] - joyCenter.ax[i])) {
|
|
maxDiff = fabs(joyInfo.ax[i] - joyCenter.ax[i]);
|
|
Index = i;
|
|
}
|
|
}
|
|
return Index;
|
|
}
|
|
|
|
// Not used anymore : remove ?
|
|
/* Game event loop idle function : For collecting input devices actions */
|
|
// static void
|
|
// IdleAcceptMouseClicks(void)
|
|
// {
|
|
// AcceptMouseClicks = 1;
|
|
// GfuiApp().eventLoop().setRecomputeCB(0);
|
|
// }
|
|
|
|
/* Game event loop idle function : For collecting input devices actions */
|
|
static void
|
|
IdleWaitForInput(void)
|
|
{
|
|
int i;
|
|
int index;
|
|
const char *str;
|
|
int axis;
|
|
|
|
GfctrlMouseGetCurrentState(&MouseInfo);
|
|
|
|
/* Check for a mouse button pressed */
|
|
for (i = 0; i < GFCTRL_MOUSE_MAX_BUTTONS; i++) {
|
|
if (MouseInfo.edgedn[i]) {
|
|
AcceptMouseClicks = 0;
|
|
GfuiApp().eventLoop().setRecomputeCB(0);
|
|
InputWaited = 0;
|
|
str = GfctrlGetNameByRef(GFCTRL_TYPE_MOUSE_BUT, i);
|
|
Cmd[CurrentCmd].ref.index = i;
|
|
Cmd[CurrentCmd].ref.type = GFCTRL_TYPE_MOUSE_BUT;
|
|
GfuiButtonSetText (ScrHandle, Cmd[CurrentCmd].Id, str);
|
|
GfuiApp().eventLoop().postRedisplay();
|
|
updateButtonText();
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Check for a mouse axis moved */
|
|
for (i = 0; i < GFCTRL_MOUSE_MAX_AXES; i++) {
|
|
if (MouseInfo.ax[i] > 20.0) {
|
|
GfuiApp().eventLoop().setRecomputeCB(0);
|
|
InputWaited = 0;
|
|
str = GfctrlGetNameByRef(GFCTRL_TYPE_MOUSE_AXIS, i);
|
|
Cmd[CurrentCmd].ref.index = i;
|
|
Cmd[CurrentCmd].ref.type = GFCTRL_TYPE_MOUSE_AXIS;
|
|
GfuiButtonSetText (ScrHandle, Cmd[CurrentCmd].Id, str);
|
|
GfuiApp().eventLoop().postRedisplay();
|
|
updateButtonText();
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Check for a Joystick button pressed */
|
|
GfctrlJoyGetCurrentStates(&joyInfo);
|
|
for (index = 0; index < GFCTRL_JOY_NUMBER; index++) {
|
|
|
|
/* check for joystick movement as well */
|
|
axis = getMovedAxis(index);
|
|
|
|
/* Allow a little extra time to detect button */
|
|
if (axis != -1 && Cmd[CurrentCmd].pref != HM_ATT_JOY_REQ_AXIS) {
|
|
GfSleep(0.3);
|
|
GfctrlJoyGetCurrentStates(&joyInfo);
|
|
}
|
|
|
|
/* Joystick buttons */
|
|
for (i = 0; i < GFCTRL_JOY_MAX_BUTTONS; i++) {
|
|
if (joyInfo.levelup[i + GFCTRL_JOY_MAX_BUTTONS * index]) {
|
|
/* Allow a little extra time to detect axis movement */
|
|
if (axis == -1 && Cmd[CurrentCmd].pref != HM_ATT_JOY_REQ_BUT) {
|
|
GfSleep(0.3);
|
|
GfctrlJoyGetCurrentStates(&joyInfo);
|
|
axis = getMovedAxis(index);
|
|
}
|
|
|
|
/* Choose to use AXIS type... */
|
|
if (axis != -1 && Cmd[CurrentCmd].pref != HM_ATT_JOY_PREF_BUT &&
|
|
Cmd[CurrentCmd].pref != HM_ATT_JOY_REQ_BUT &&
|
|
Cmd[CurrentCmd].pref != HM_ATT_JOY_PREF_LAST) {
|
|
// Toggle Prefered Type
|
|
if (Cmd[CurrentCmd].pref == HM_ATT_JOY_PREF_AXIS)
|
|
Cmd[CurrentCmd].pref = HM_ATT_JOY_PREF_BUT;
|
|
if (Cmd[CurrentCmd].pref >= HM_ATT_JOY_PREF_ANY)
|
|
Cmd[CurrentCmd].pref ++;
|
|
|
|
Cmd[CurrentCmd].butIgnore = i + GFCTRL_JOY_MAX_BUTTONS * index;
|
|
|
|
goto configure_for_joy_axis;
|
|
}
|
|
|
|
if (axis != -1 && Cmd[CurrentCmd].pref == HM_ATT_JOY_PREF_BUT) {
|
|
Cmd[CurrentCmd].pref = HM_ATT_JOY_PREF_AXIS;
|
|
}
|
|
if (axis != -1 && Cmd[CurrentCmd].pref == HM_ATT_JOY_PREF_LAST) {
|
|
Cmd[CurrentCmd].pref = HM_ATT_JOY_PREF_ANY;
|
|
}
|
|
Cmd[CurrentCmd].butIgnore = 0;
|
|
|
|
/* Button i fired */
|
|
GfuiApp().eventLoop().setRecomputeCB(0);
|
|
InputWaited = 0;
|
|
str = GfctrlGetNameByRef(GFCTRL_TYPE_JOY_BUT, i + GFCTRL_JOY_MAX_BUTTONS * index);
|
|
Cmd[CurrentCmd].ref.index = i + GFCTRL_JOY_MAX_BUTTONS * index;
|
|
Cmd[CurrentCmd].ref.type = GFCTRL_TYPE_JOY_BUT;
|
|
GfuiButtonSetText (ScrHandle, Cmd[CurrentCmd].Id, str);
|
|
GfuiApp().eventLoop().postRedisplay();
|
|
updateButtonText();
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Axis movement detected without button */
|
|
if (axis != -1) {
|
|
Cmd[CurrentCmd].butIgnore = 0;
|
|
|
|
// Toggle preference, when there is no button available
|
|
if (Cmd[CurrentCmd].pref >= HM_ATT_JOY_PREF_ANY)
|
|
Cmd[CurrentCmd].pref ++;
|
|
if (Cmd[CurrentCmd].pref > HM_ATT_JOY_PREF_ANY1)
|
|
Cmd[CurrentCmd].pref = HM_ATT_JOY_PREF_ANY;
|
|
|
|
configure_for_joy_axis:
|
|
GfuiApp().eventLoop().setRecomputeCB(0);
|
|
InputWaited = 0;
|
|
|
|
if (Cmd[CurrentCmd].pref == HM_ATT_JOY_REQ_BUT ||
|
|
Cmd[CurrentCmd].pref == HM_ATT_JOY_PREF_ANY ||
|
|
Cmd[CurrentCmd].pref == HM_ATT_JOY_PREF_LAST)
|
|
/* Map axis to a button type */
|
|
Cmd[CurrentCmd].ref.type = GFCTRL_TYPE_JOY_ATOB;
|
|
else
|
|
Cmd[CurrentCmd].ref.type = GFCTRL_TYPE_JOY_AXIS;
|
|
|
|
Cmd[CurrentCmd].ref.index = axis;
|
|
str = GfctrlGetNameByRef(GFCTRL_TYPE_JOY_AXIS, axis);
|
|
GfuiButtonSetText (ScrHandle, Cmd[CurrentCmd].Id, str);
|
|
GfuiApp().eventLoop().postRedisplay();
|
|
updateButtonText();
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Let CPU take breath (and fans stay at low and quiet speed) */
|
|
GfSleep(0.001);
|
|
}
|
|
|
|
/* Push button callback for each command button : activate input devices action collection loop */
|
|
static void
|
|
onPush(void *vi)
|
|
{
|
|
long i = (long)vi;
|
|
|
|
/* Do nothing if mouse button clicks are to be refused */
|
|
if (!AcceptMouseClicks) {
|
|
AcceptMouseClicks = 1;
|
|
return;
|
|
}
|
|
|
|
/* Selected given command as the currently awaited one */
|
|
CurrentCmd = i;
|
|
|
|
/* Empty button text to tell the user we will soon be waiting for its input */
|
|
GfuiButtonSetText (ScrHandle, Cmd[i].Id, "");
|
|
|
|
/* Reset selected command action */
|
|
Cmd[i].ref.index = -1;
|
|
Cmd[i].ref.type = GFCTRL_TYPE_NOT_AFFECTED;
|
|
|
|
/* State that a keyboard action is awaited */
|
|
if (Cmd[CurrentCmd].keyboardPossible)
|
|
InputWaited = 1;
|
|
|
|
/* Read initial mouse status */
|
|
GfctrlMouseInitCenter();
|
|
memset(&MouseInfo, 0, sizeof(MouseInfo));
|
|
GfctrlMouseGetCurrentState(&MouseInfo);
|
|
|
|
/* Read initial joysticks status */
|
|
GfctrlJoyGetCurrentStates(&joyInfo);
|
|
memcpy(&joyCenter, &joyInfo, sizeof(joyCenter));
|
|
|
|
/* Now, wait for input device actions */
|
|
GfuiApp().eventLoop().setRecomputeCB(IdleWaitForInput);
|
|
}
|
|
|
|
static void
|
|
onActivate(void * /* dummy */)
|
|
{
|
|
//joyInfo = GfctrlJoyCreate();
|
|
GfctrlJoyGetCurrentStates(&joyInfo);
|
|
|
|
if (ReloadValues) {
|
|
|
|
/* Load command settings from preference params for current player */
|
|
ControlGetSettings();
|
|
|
|
/* For each control : */
|
|
for (int cmdInd = 0; cmdInd < MaxCmd; cmdInd++) {
|
|
|
|
/* Show / hide control editboxes according to selected gear changing mode code */
|
|
if (GearChangeMode & CmdDispInfo[cmdInd].gearChangeModeMask)
|
|
{
|
|
GfuiVisibilitySet(ScrHandle, Cmd[cmdInd].labelId, GFUI_VISIBLE);
|
|
GfuiVisibilitySet(ScrHandle, Cmd[cmdInd].Id, GFUI_VISIBLE);
|
|
}
|
|
else
|
|
{
|
|
GfuiVisibilitySet(ScrHandle, Cmd[cmdInd].labelId, GFUI_INVISIBLE);
|
|
GfuiVisibilitySet(ScrHandle, Cmd[cmdInd].Id, GFUI_INVISIBLE);
|
|
}
|
|
}
|
|
}
|
|
|
|
updateButtonText();
|
|
|
|
AcceptMouseClicks = 1;
|
|
}
|
|
|
|
static void
|
|
DevCalibrate(void * /* dummy */)
|
|
{
|
|
void* nextCalMenu = NULL;
|
|
|
|
// No need to reload command settings from preference on return
|
|
ReloadValues = 0;
|
|
|
|
// Create calibration "wizard" (1 menu for each device to calibrate
|
|
if (Joy2butCalNeeded)
|
|
nextCalMenu = Joy2butCalMenuInit(ScrHandle, nextCalMenu, Cmd, MaxCmd);
|
|
|
|
if (JoyCalNeeded)
|
|
nextCalMenu = JoyCalMenuInit(ScrHandle, nextCalMenu, Cmd, MaxCmd);
|
|
|
|
if (MouseCalNeeded)
|
|
nextCalMenu = MouseCalMenuInit(ScrHandle, nextCalMenu, Cmd, MaxCmd);
|
|
|
|
// Activate first wizard screen
|
|
if (nextCalMenu)
|
|
GfuiScreenActivate(nextCalMenu);
|
|
}
|
|
|
|
|
|
/* */
|
|
void *
|
|
ControlMenuInit(void *prevMenu, void *prefHdle, unsigned index, tGearChangeMode gearChangeMode, int saveOnExit)
|
|
{
|
|
ReloadValues = 1;
|
|
PrefHdle = prefHdle;
|
|
SaveOnExit = saveOnExit;
|
|
|
|
/* Select current player section in the players preferences */
|
|
sprintf(CurrentSection, "%s/%s/%u", HM_SECT_PREF, HM_LIST_DRV, index);
|
|
|
|
/* Set specified gear changing mode for current player */
|
|
GearChangeMode = gearChangeMode;
|
|
|
|
/* Don't recreate screen if already done */
|
|
if (ScrHandle) {
|
|
if (PrevScrHandle != prevMenu)
|
|
// Need to re-create screen as parent has changed
|
|
GfuiScreenRelease(ScrHandle);
|
|
else
|
|
return ScrHandle;
|
|
}
|
|
|
|
PrevScrHandle = prevMenu;
|
|
|
|
/* Create screen */
|
|
ScrHandle = GfuiScreenCreate((float*)NULL, NULL, onActivate, NULL, (tfuiCallback)NULL, 1);
|
|
|
|
void *param = GfuiMenuLoad("controlconfigmenu.xml");
|
|
GfuiMenuCreateStaticControls(ScrHandle, param);
|
|
|
|
/* Default keyboard shortcuts */
|
|
GfuiMenuDefaultKeysAdd(ScrHandle);
|
|
|
|
/* For each control (in Cmd array), create the associated label and editbox */
|
|
for (int i = 0; i < MaxCmd; i++)
|
|
{
|
|
Cmd[i].labelId = GfuiMenuCreateLabelControl(ScrHandle,param,Cmd[i].name);
|
|
std::string strCmdEdit(Cmd[i].name);
|
|
strCmdEdit += " button";
|
|
Cmd[i].Id = GfuiMenuCreateButtonControl(ScrHandle,param,strCmdEdit.c_str(),(void*)(long)i,onPush,NULL,(tfuiCallback)NULL,onFocusLost);
|
|
}
|
|
|
|
/* Steer Sensibility label and associated editbox */
|
|
GfuiMenuCreateLabelControl(ScrHandle,param,"Steer Sensitivity");
|
|
SteerSensEditId = GfuiMenuCreateEditControl(ScrHandle,param,"Steer Sensitivity Edit",NULL,NULL,onSteerSensChange);
|
|
|
|
/* Steer Dead Zone label and associated editbox */
|
|
DeadZoneLabelId = GfuiMenuCreateLabelControl(ScrHandle,param,"Steer Dead Zone");
|
|
DeadZoneEditId = GfuiMenuCreateEditControl(ScrHandle,param,"Steer Dead Zone Edit",NULL,NULL,onDeadZoneChange);
|
|
|
|
/* Steer Speed Sensibility label and associated editbox */
|
|
GfuiMenuCreateLabelControl(ScrHandle,param,"Steer Speed Sensitivity");
|
|
SteerSpeedSensEditId = GfuiMenuCreateEditControl(ScrHandle,param,"Steer Speed Sensitivity Edit",NULL,NULL,onSteerSpeedSensChange);
|
|
|
|
/* Save button and associated keyboard shortcut */
|
|
GfuiMenuCreateButtonControl(ScrHandle,param,"save",PrevScrHandle,onSave);
|
|
GfuiAddKey(ScrHandle, GFUIK_RETURN /* Return */, "Save", PrevScrHandle, onSave, NULL);
|
|
|
|
/* Mouse calibration screen access button */
|
|
CalibrateButtonId = GfuiMenuCreateButtonControl(ScrHandle,param,"calibrate",NULL, DevCalibrate);
|
|
|
|
/* Cancel button and associated keyboard shortcut */
|
|
GfuiMenuCreateButtonControl(ScrHandle,param,"cancel",PrevScrHandle,onQuit);
|
|
GfuiAddKey(ScrHandle, GFUIK_ESCAPE, "Cancel", PrevScrHandle, onQuit, NULL);
|
|
|
|
/* General callback for keyboard keys */
|
|
GfuiKeyEventRegister(ScrHandle, onKeyAction);
|
|
|
|
GfParmReleaseHandle(param);
|
|
|
|
return ScrHandle;
|
|
}
|
|
|
|
/* From parms (prefHdle) to global vars (Cmd, SteerSensVal, DeadZoneVal) */
|
|
void ControlGetSettings(void *prefHdle, unsigned index)
|
|
{
|
|
int iCmd;
|
|
const char *prm;
|
|
tCtrlRef *ref;
|
|
|
|
/* If handle on preferences params not given, get current */
|
|
if (!prefHdle)
|
|
prefHdle = PrefHdle;
|
|
|
|
/* Select current player section in the players preferences if specified */
|
|
if (index > 0)
|
|
sprintf(CurrentSection, "%s/%s/%u", HM_SECT_PREF, HM_LIST_DRV, index);
|
|
|
|
/* For each control : */
|
|
for (iCmd = 0; iCmd < MaxCmd; iCmd++) {
|
|
prm = GfctrlGetNameByRef(Cmd[iCmd].ref.type, Cmd[iCmd].ref.index);
|
|
if (!prm) {
|
|
prm = "---";
|
|
}
|
|
/* Load associated command settings from preferences params for the current player,
|
|
by default from the default "mouse" settings */
|
|
prm = GfParmGetStr(prefHdle, HM_SECT_MOUSEPREF, Cmd[iCmd].name, prm);
|
|
prm = GfParmGetStr(prefHdle, CurrentSection, Cmd[iCmd].name, prm);
|
|
ref = GfctrlGetRefByName(prm);
|
|
Cmd[iCmd].ref.type = ref->type;
|
|
Cmd[iCmd].ref.index = ref->index;
|
|
|
|
if (Cmd[iCmd].minName) {
|
|
Cmd[iCmd].min = GfParmGetNum(prefHdle, HM_SECT_MOUSEPREF, Cmd[iCmd].minName, NULL, Cmd[iCmd].min);
|
|
Cmd[iCmd].min = GfParmGetNum(prefHdle, CurrentSection, Cmd[iCmd].minName, NULL, Cmd[iCmd].min);
|
|
}
|
|
if (Cmd[iCmd].maxName) {
|
|
Cmd[iCmd].max = GfParmGetNum(prefHdle, HM_SECT_MOUSEPREF, Cmd[iCmd].maxName, NULL, Cmd[iCmd].max);
|
|
Cmd[iCmd].max = GfParmGetNum(prefHdle, CurrentSection, Cmd[iCmd].maxName, NULL, Cmd[iCmd].max);
|
|
}
|
|
if (Cmd[iCmd].powName) {
|
|
Cmd[iCmd].pow = GfParmGetNum(prefHdle, HM_SECT_MOUSEPREF, Cmd[iCmd].powName, NULL, Cmd[iCmd].pow);
|
|
Cmd[iCmd].pow = GfParmGetNum(prefHdle, CurrentSection, Cmd[iCmd].powName, NULL, Cmd[iCmd].pow);
|
|
}
|
|
}
|
|
|
|
/* Load also Steer sensibility (default from mouse prefs) */
|
|
SteerSensVal = GfParmGetNum(prefHdle, HM_SECT_MOUSEPREF, HM_ATT_STEER_SENS, NULL, 0);
|
|
SteerSensVal = GfParmGetNum(prefHdle, CurrentSection, HM_ATT_STEER_SENS, NULL, SteerSensVal);
|
|
if (SteerSensVal <= 0.0)
|
|
SteerSensVal = 1.0e-6;
|
|
|
|
/* Load also Dead zone (default from mouse prefs) */
|
|
DeadZoneVal = GfParmGetNum(prefHdle, HM_SECT_MOUSEPREF, HM_ATT_STEER_DEAD, NULL, 0);
|
|
DeadZoneVal = GfParmGetNum(prefHdle, CurrentSection, HM_ATT_STEER_DEAD, NULL, DeadZoneVal);
|
|
if (DeadZoneVal < 0.0)
|
|
DeadZoneVal = 0.0;
|
|
else if (DeadZoneVal > 1.0)
|
|
DeadZoneVal = 1.0;
|
|
|
|
/* Load also Steer speed sensibility (default from mouse prefs) */
|
|
SteerSpeedSensVal = GfParmGetNum(prefHdle, HM_SECT_MOUSEPREF, HM_ATT_STEER_SPD, NULL, 0);
|
|
SteerSpeedSensVal = GfParmGetNum(prefHdle, CurrentSection, HM_ATT_STEER_SPD, NULL, SteerSpeedSensVal);
|
|
if (SteerSpeedSensVal < 0.0)
|
|
SteerSpeedSensVal = 0.0;
|
|
}
|
|
|
|
/* From global vars (Cmd, SteerSensVal, DeadZoneVal) to parms (prefHdle) */
|
|
void ControlPutSettings(void *prefHdle, unsigned index, tGearChangeMode gearChangeMode)
|
|
{
|
|
int iCmd;
|
|
const char* str;
|
|
const char* pszReverseCmd;
|
|
const char* pszNeutralCmd;
|
|
|
|
/* If handle on preferences not given, get current */
|
|
if (!prefHdle)
|
|
prefHdle = PrefHdle;
|
|
|
|
/* Change current player section in the players preferences if specified */
|
|
if (index > 0)
|
|
sprintf(CurrentSection, "%s/%s/%u", HM_SECT_PREF, HM_LIST_DRV, index);
|
|
|
|
/* Select current player gear change mode if not specified */
|
|
if (gearChangeMode == GEAR_MODE_NONE)
|
|
gearChangeMode = GearChangeMode;
|
|
|
|
/* Allow neutral gear in sequential mode if neutral gear command not defined */
|
|
pszNeutralCmd = GfctrlGetNameByRef(Cmd[ICmdNeutralGear].ref.type, Cmd[ICmdNeutralGear].ref.index);
|
|
if (gearChangeMode == GEAR_MODE_SEQ && (!pszNeutralCmd || !strcmp(pszNeutralCmd, "-")))
|
|
GfParmSetStr(prefHdle, CurrentSection, HM_ATT_SEQSHFT_ALLOW_NEUTRAL, HM_VAL_YES);
|
|
else
|
|
GfParmSetStr(prefHdle, CurrentSection, HM_ATT_SEQSHFT_ALLOW_NEUTRAL, HM_VAL_NO);
|
|
|
|
/* Allow reverse gear in sequential mode if reverse gear command not defined */
|
|
pszReverseCmd = GfctrlGetNameByRef(Cmd[ICmdReverseGear].ref.type, Cmd[ICmdReverseGear].ref.index);
|
|
if (gearChangeMode == GEAR_MODE_SEQ && (!pszReverseCmd || !strcmp(pszReverseCmd, "-")))
|
|
GfParmSetStr(prefHdle, CurrentSection, HM_ATT_SEQSHFT_ALLOW_REVERSE, HM_VAL_YES);
|
|
else
|
|
GfParmSetStr(prefHdle, CurrentSection, HM_ATT_SEQSHFT_ALLOW_REVERSE, HM_VAL_NO);
|
|
|
|
/* Release gear lever goes neutral in grid mode if no neutral gear command defined */
|
|
if (gearChangeMode == GEAR_MODE_GRID && (!pszNeutralCmd || !strcmp(pszNeutralCmd, "-")))
|
|
GfParmSetStr(prefHdle, CurrentSection, HM_ATT_REL_BUT_NEUTRAL, HM_VAL_YES);
|
|
else
|
|
GfParmSetStr(prefHdle, CurrentSection, HM_ATT_REL_BUT_NEUTRAL, HM_VAL_NO);
|
|
|
|
/* Steer sensitivity and dead zone */
|
|
GfParmSetNum(prefHdle, CurrentSection, HM_ATT_STEER_SENS, NULL, SteerSensVal);
|
|
GfParmSetNum(prefHdle, CurrentSection, HM_ATT_STEER_DEAD, NULL, DeadZoneVal);
|
|
GfParmSetNum(prefHdle, CurrentSection, HM_ATT_STEER_SPD, NULL, SteerSpeedSensVal);
|
|
|
|
/* Name, min, max and power, for each possible command */
|
|
for (iCmd = 0; iCmd < MaxCmd; iCmd++) {
|
|
str = GfctrlGetNameByRef(Cmd[iCmd].ref.type, Cmd[iCmd].ref.index);
|
|
if (str) {
|
|
GfParmSetStr(prefHdle, CurrentSection, Cmd[iCmd].name, str);
|
|
} else {
|
|
GfParmSetStr(prefHdle, CurrentSection, Cmd[iCmd].name, "");
|
|
}
|
|
if (Cmd[iCmd].minName) {
|
|
GfParmSetNum(prefHdle, CurrentSection, Cmd[iCmd].minName, NULL, Cmd[iCmd].min);
|
|
}
|
|
if (Cmd[iCmd].maxName) {
|
|
GfParmSetNum(prefHdle, CurrentSection, Cmd[iCmd].maxName, NULL, Cmd[iCmd].max);
|
|
}
|
|
if (Cmd[iCmd].powName) {
|
|
GfParmSetNum(prefHdle, CurrentSection, Cmd[iCmd].powName, NULL, Cmd[iCmd].pow);
|
|
}
|
|
}
|
|
|
|
if (SaveOnExit)
|
|
GfParmWriteFile(NULL, PrefHdle, "preferences");
|
|
}
|